diff options
author | Eric Dumazet <edumazet@google.com> | 2022-10-20 23:20:18 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2022-10-24 11:04:43 +0100 |
commit | 0cafd77dcd032d1687efaba5598cf07bce85997f (patch) | |
tree | c32efa19fb02e86944f6f71cf8e79f145432b721 /net/netlink | |
parent | b29e0dece45174f8c791853cbf40a24212148b47 (diff) | |
download | linux-rpi-0cafd77dcd032d1687efaba5598cf07bce85997f.tar.gz linux-rpi-0cafd77dcd032d1687efaba5598cf07bce85997f.tar.bz2 linux-rpi-0cafd77dcd032d1687efaba5598cf07bce85997f.zip |
net: add a refcount tracker for kernel sockets
Commit ffa84b5ffb37 ("net: add netns refcount tracker to struct sock")
added a tracker to sockets, but did not track kernel sockets.
We still have syzbot reports hinting about netns being destroyed
while some kernel TCP sockets had not been dismantled.
This patch tracks kernel sockets, and adds a ref_tracker_dir_print()
call to net_free() right before the netns is freed.
Normally, each layer is responsible for properly releasing its
kernel sockets before last call to net_free().
This debugging facility is enabled with CONFIG_NET_NS_REFCNT_TRACKER=y
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Tested-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a662e8a5ff84..f0c94d394ab1 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -812,6 +812,17 @@ static int netlink_release(struct socket *sock) } sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1); + + /* Because struct net might disappear soon, do not keep a pointer. */ + if (!sk->sk_net_refcnt && sock_net(sk) != &init_net) { + __netns_tracker_free(sock_net(sk), &sk->ns_tracker, false); + /* Because of deferred_put_nlk_sk and use of work queue, + * it is possible netns will be freed before this socket. + */ + sock_net_set(sk, &init_net); + __netns_tracker_alloc(&init_net, &sk->ns_tracker, + false, GFP_KERNEL); + } call_rcu(&nlk->rcu, deferred_put_nlk_sk); return 0; } |