diff options
author | Denis V. Lunev <den@openvz.org> | 2008-01-19 08:53:31 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-29 00:08:05 +0100 |
commit | 869e58f87094b1e8a0df49232e4a5172678d46c9 (patch) | |
tree | 9ac2dc45be284ac66099e3e71b16a03fb5c21b8d /net/netlink | |
parent | [IPV6]: Fix ip6_frag ctl (diff) | |
download | linux-869e58f87094b1e8a0df49232e4a5172678d46c9.tar.xz linux-869e58f87094b1e8a0df49232e4a5172678d46c9.zip |
[NETNS]: Double free in netlink_release.
Netlink protocol table is global for all namespaces. Some netlink
protocols have been virtualized, i.e. they have per/namespace netlink
socket. This difference can easily lead to double free if more than 1
namespace is started. Count the number of kernel netlink sockets to
track that this table is not used any more.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Tested-by: Alexey Dobriyan <adobriyan@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 21f9e30184e2..29fef558aab6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -498,9 +498,12 @@ static int netlink_release(struct socket *sock) netlink_table_grab(); if (netlink_is_kernel(sk)) { - kfree(nl_table[sk->sk_protocol].listeners); - nl_table[sk->sk_protocol].module = NULL; - nl_table[sk->sk_protocol].registered = 0; + BUG_ON(nl_table[sk->sk_protocol].registered == 0); + if (--nl_table[sk->sk_protocol].registered == 0) { + kfree(nl_table[sk->sk_protocol].listeners); + nl_table[sk->sk_protocol].module = NULL; + nl_table[sk->sk_protocol].registered = 0; + } } else if (nlk->subscriptions) netlink_update_listeners(sk); netlink_table_ungrab(); @@ -1389,6 +1392,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, nl_table[unit].registered = 1; } else { kfree(listeners); + nl_table[unit].registered++; } netlink_table_ungrab(); |