diff options
author | Thomas Graf <tgraf@suug.ch> | 2007-07-24 15:32:46 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-07-24 15:32:46 -0700 |
commit | 79dc4386aec655ad829f320ab90888bacbc7037b (patch) | |
tree | 82340d9c2be1c96e3e894a4fa29132e4234e74a1 /net/netlink | |
parent | 85ccc365e91de9f0053c94de4cbc6ce97f8170e7 (diff) |
[GENETLINK]: Fix race in genl_unregister_mc_groups()
family->mcast_groups is protected by genl_lock so it must
be held while accessing the list in genl_unregister_mc_groups().
Requires adding a non-locking variant of genl_unregister_mc_group().
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/genetlink.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index e146531faf1..61d65569e2b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -200,6 +200,18 @@ int genl_register_mc_group(struct genl_family *family, } EXPORT_SYMBOL(genl_register_mc_group); +static void __genl_unregister_mc_group(struct genl_family *family, + struct genl_multicast_group *grp) +{ + BUG_ON(grp->family != family); + netlink_clear_multicast_users(genl_sock, grp->id); + clear_bit(grp->id, mc_groups); + list_del(&grp->list); + genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); + grp->id = 0; + grp->family = NULL; +} + /** * genl_unregister_mc_group - unregister a multicast group * @@ -217,14 +229,8 @@ EXPORT_SYMBOL(genl_register_mc_group); void genl_unregister_mc_group(struct genl_family *family, struct genl_multicast_group *grp) { - BUG_ON(grp->family != family); genl_lock(); - netlink_clear_multicast_users(genl_sock, grp->id); - clear_bit(grp->id, mc_groups); - list_del(&grp->list); - genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); - grp->id = 0; - grp->family = NULL; + __genl_unregister_mc_group(family, grp); genl_unlock(); } @@ -232,8 +238,10 @@ static void genl_unregister_mc_groups(struct genl_family *family) { struct genl_multicast_group *grp, *tmp; + genl_lock(); list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list) - genl_unregister_mc_group(family, grp); + __genl_unregister_mc_group(family, grp); + genl_unlock(); } /** |