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: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3a5be7d4b0
commit
6d1a3fb567
|
@ -444,8 +444,11 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
if (ops->dumpit == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return netlink_dump_start(genl_sock, skb, nlh,
|
||||
ops->dumpit, ops->done);
|
||||
genl_unlock();
|
||||
err = netlink_dump_start(genl_sock, skb, nlh,
|
||||
ops->dumpit, ops->done);
|
||||
genl_lock();
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ops->doit == NULL)
|
||||
|
@ -603,9 +606,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
int chains_to_skip = cb->args[0];
|
||||
int fams_to_skip = cb->args[1];
|
||||
|
||||
if (chains_to_skip != 0)
|
||||
genl_lock();
|
||||
|
||||
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
|
||||
if (i < chains_to_skip)
|
||||
continue;
|
||||
|
@ -623,9 +623,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
}
|
||||
|
||||
errout:
|
||||
if (chains_to_skip != 0)
|
||||
genl_unlock();
|
||||
|
||||
cb->args[0] = i;
|
||||
cb->args[1] = n;
|
||||
|
||||
|
@ -770,7 +767,7 @@ static int __init genl_init(void)
|
|||
|
||||
/* we'll bump the group number right afterwards */
|
||||
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)
|
||||
panic("GENL: Cannot initialize generic netlink\n");
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user