Skip to content

Commit

Permalink
netlink: genl: fix circular locking
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Jun 18, 2008
1 parent 3a5be7d commit 6d1a3fb
Showing 1 changed file with 6 additions and 9 deletions.
15 changes: 6 additions & 9 deletions net/netlink/genetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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");

Expand Down

0 comments on commit 6d1a3fb

Please sign in to comment.