Commit 6d1a3fb5 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

netlink: genl: fix circular locking

genetlink has a circular locking dependency when dumping the registered
families:

- dump start:
genl_rcv()            : take genl_mutex
genl_rcv_msg()        : call netlink_dump_start() while holding genl_mutex
netlink_dump_start(),
netlink_dump()        : take nlk->cb_mutex
ctrl_dumpfamily()     : try to detect this case and not take genl_mutex a
                        second time

- dump continuance:
netlink_rcv()         : call netlink_dump
netlink_dump          : take nlk->cb_mutex
ctrl_dumpfamily()     : take genl_mutex

Register genl_lock as callback mutex with netlink to fix this. This slightly
widens an already existing module unload race, the genl ops used during the
dump might go away when the module is unloaded. Thomas Graf is working on a
seperate fix for this.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3a5be7d4
...@@ -444,8 +444,11 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -444,8 +444,11 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (ops->dumpit == NULL) if (ops->dumpit == NULL)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return netlink_dump_start(genl_sock, skb, nlh, genl_unlock();
err = netlink_dump_start(genl_sock, skb, nlh,
ops->dumpit, ops->done); ops->dumpit, ops->done);
genl_lock();
return err;
} }
if (ops->doit == NULL) if (ops->doit == NULL)
...@@ -603,9 +606,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -603,9 +606,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
int chains_to_skip = cb->args[0]; int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1]; int fams_to_skip = cb->args[1];
if (chains_to_skip != 0)
genl_lock();
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
if (i < chains_to_skip) if (i < chains_to_skip)
continue; continue;
...@@ -623,9 +623,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -623,9 +623,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
} }
errout: errout:
if (chains_to_skip != 0)
genl_unlock();
cb->args[0] = i; cb->args[0] = i;
cb->args[1] = n; cb->args[1] = n;
...@@ -770,7 +767,7 @@ static int __init genl_init(void) ...@@ -770,7 +767,7 @@ static int __init genl_init(void)
/* we'll bump the group number right afterwards */ /* we'll bump the group number right afterwards */
genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0, genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0,
genl_rcv, NULL, THIS_MODULE); genl_rcv, &genl_mutex, THIS_MODULE);
if (genl_sock == NULL) if (genl_sock == NULL)
panic("GENL: Cannot initialize generic netlink\n"); panic("GENL: Cannot initialize generic netlink\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment