+++ /dev/null
-From b13e4063fb63f721a1343f2a866d63ad13587cd3 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 20 Oct 2022 23:20:18 +0000
-Subject: net: add a refcount tracker for kernel sockets
-
-From: Eric Dumazet <edumazet@google.com>
-
-[ Upstream commit 0cafd77dcd032d1687efaba5598cf07bce85997f ]
-
-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>
-Stable-dep-of: 0f6ede9fbc74 ("net: defer final 'struct net' free in netns dismantle")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/net_namespace.h | 30 ++++++++++++++++++++++--------
- net/core/net_namespace.c | 5 +++++
- net/core/sock.c | 14 ++++++++++++++
- net/netlink/af_netlink.c | 11 +++++++++++
- net/rds/tcp.c | 3 +++
- 5 files changed, 55 insertions(+), 8 deletions(-)
-
-diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
-index 8c3587d5c308..78beaa765c73 100644
---- a/include/net/net_namespace.h
-+++ b/include/net/net_namespace.h
-@@ -92,7 +92,9 @@ struct net {
-
- struct ns_common ns;
- struct ref_tracker_dir refcnt_tracker;
--
-+ struct ref_tracker_dir notrefcnt_tracker; /* tracker for objects not
-+ * refcounted against netns
-+ */
- struct list_head dev_base_head;
- struct proc_dir_entry *proc_net;
- struct proc_dir_entry *proc_net_stat;
-@@ -320,19 +322,31 @@ static inline int check_net(const struct net *net)
- #endif
-
-
--static inline void netns_tracker_alloc(struct net *net,
-- netns_tracker *tracker, gfp_t gfp)
-+static inline void __netns_tracker_alloc(struct net *net,
-+ netns_tracker *tracker,
-+ bool refcounted,
-+ gfp_t gfp)
- {
- #ifdef CONFIG_NET_NS_REFCNT_TRACKER
-- ref_tracker_alloc(&net->refcnt_tracker, tracker, gfp);
-+ ref_tracker_alloc(refcounted ? &net->refcnt_tracker :
-+ &net->notrefcnt_tracker,
-+ tracker, gfp);
- #endif
- }
-
--static inline void netns_tracker_free(struct net *net,
-- netns_tracker *tracker)
-+static inline void netns_tracker_alloc(struct net *net, netns_tracker *tracker,
-+ gfp_t gfp)
-+{
-+ __netns_tracker_alloc(net, tracker, true, gfp);
-+}
-+
-+static inline void __netns_tracker_free(struct net *net,
-+ netns_tracker *tracker,
-+ bool refcounted)
- {
- #ifdef CONFIG_NET_NS_REFCNT_TRACKER
-- ref_tracker_free(&net->refcnt_tracker, tracker);
-+ ref_tracker_free(refcounted ? &net->refcnt_tracker :
-+ &net->notrefcnt_tracker, tracker);
- #endif
- }
-
-@@ -346,7 +360,7 @@ static inline struct net *get_net_track(struct net *net,
-
- static inline void put_net_track(struct net *net, netns_tracker *tracker)
- {
-- netns_tracker_free(net, tracker);
-+ __netns_tracker_free(net, tracker, true);
- put_net(net);
- }
-
-diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
-index 1d95a5adce4e..0fe9fd2cf4e2 100644
---- a/net/core/net_namespace.c
-+++ b/net/core/net_namespace.c
-@@ -319,6 +319,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
-
- refcount_set(&net->ns.count, 1);
- ref_tracker_dir_init(&net->refcnt_tracker, 128);
-+ ref_tracker_dir_init(&net->notrefcnt_tracker, 128);
-
- refcount_set(&net->passive, 1);
- get_random_bytes(&net->hash_mix, sizeof(u32));
-@@ -439,6 +440,10 @@ static void net_free(struct net *net)
- {
- if (refcount_dec_and_test(&net->passive)) {
- kfree(rcu_access_pointer(net->gen));
-+
-+ /* There should not be any trackers left there. */
-+ ref_tracker_dir_exit(&net->notrefcnt_tracker);
-+
- kmem_cache_free(net_cachep, net);
- }
- }
-diff --git a/net/core/sock.c b/net/core/sock.c
-index dce8f878f638..2ba6385e39fd 100644
---- a/net/core/sock.c
-+++ b/net/core/sock.c
-@@ -2111,6 +2111,9 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
- if (likely(sk->sk_net_refcnt)) {
- get_net_track(net, &sk->ns_tracker, priority);
- sock_inuse_add(net, 1);
-+ } else {
-+ __netns_tracker_alloc(net, &sk->ns_tracker,
-+ false, priority);
- }
-
- sock_net_set(sk, net);
-@@ -2166,6 +2169,9 @@ static void __sk_destruct(struct rcu_head *head)
-
- if (likely(sk->sk_net_refcnt))
- put_net_track(sock_net(sk), &sk->ns_tracker);
-+ else
-+ __netns_tracker_free(sock_net(sk), &sk->ns_tracker, false);
-+
- sk_prot_free(sk->sk_prot_creator, sk);
- }
-
-@@ -2254,6 +2260,14 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
- if (likely(newsk->sk_net_refcnt)) {
- get_net_track(sock_net(newsk), &newsk->ns_tracker, priority);
- sock_inuse_add(sock_net(newsk), 1);
-+ } else {
-+ /* Kernel sockets are not elevating the struct net refcount.
-+ * Instead, use a tracker to more easily detect if a layer
-+ * is not properly dismantling its kernel sockets at netns
-+ * destroy time.
-+ */
-+ __netns_tracker_alloc(sock_net(newsk), &newsk->ns_tracker,
-+ false, priority);
- }
- sk_node_init(&newsk->sk_node);
- sock_lock_init(newsk);
-diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
-index 8a74847dacaf..3bc862fd89a5 100644
---- a/net/netlink/af_netlink.c
-+++ b/net/netlink/af_netlink.c
-@@ -797,6 +797,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;
- }
-diff --git a/net/rds/tcp.c b/net/rds/tcp.c
-index 4444fd82b66d..c5b86066ff66 100644
---- a/net/rds/tcp.c
-+++ b/net/rds/tcp.c
-@@ -503,6 +503,9 @@ bool rds_tcp_tune(struct socket *sock)
- release_sock(sk);
- return false;
- }
-+ /* Update ns_tracker to current stack trace and refcounted tracker */
-+ __netns_tracker_free(net, &sk->ns_tracker, false);
-+
- sk->sk_net_refcnt = 1;
- netns_tracker_alloc(net, &sk->ns_tracker, GFP_KERNEL);
- sock_inuse_add(net, 1);
---
-2.39.5
-
-From 7c7c5115460996b63102c3458ee25b9551524d37 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
+From 0f6ede9fbc747e2553612271bce108f7517e7a45 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
Date: Wed, 4 Dec 2024 12:54:55 +0000
Subject: net: defer final 'struct net' free in netns dismantle
From: Eric Dumazet <edumazet@google.com>
-[ Upstream commit 0f6ede9fbc747e2553612271bce108f7517e7a45 ]
+commit 0f6ede9fbc747e2553612271bce108f7517e7a45 upstream.
Ilya reported a slab-use-after-free in dst_destroy [1]
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20241204125455.3871859-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- include/net/net_namespace.h | 1 +
- net/core/net_namespace.c | 20 +++++++++++++++++++-
- 2 files changed, 20 insertions(+), 1 deletion(-)
+ include/net/net_namespace.h | 1 +
+ net/core/net_namespace.c | 21 ++++++++++++++++++++-
+ 2 files changed, 21 insertions(+), 1 deletion(-)
-diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
-index 78beaa765c73..75241d170633 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -81,6 +81,7 @@ struct net {
struct llist_node cleanup_list; /* namespaces on death row */
#ifdef CONFIG_KEYS
-diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
-index 0fe9fd2cf4e2..ddd33dcd6658 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
-@@ -436,6 +436,21 @@ static struct net *net_alloc(void)
+@@ -435,11 +435,28 @@ out_free:
goto out;
}
static void net_free(struct net *net)
{
if (refcount_dec_and_test(&net->passive)) {
-@@ -444,7 +459,8 @@ static void net_free(struct net *net)
- /* There should not be any trackers left there. */
- ref_tracker_dir_exit(&net->notrefcnt_tracker);
-
+ kfree(rcu_access_pointer(net->gen));
- kmem_cache_free(net_cachep, net);
++
+ /* Wait for an extra rcu_barrier() before final free. */
+ llist_add(&net->defer_free_list, &defer_free_list);
}
}
-@@ -619,6 +635,8 @@ static void cleanup_net(struct work_struct *work)
+@@ -614,6 +631,8 @@ static void cleanup_net(struct work_stru
*/
rcu_barrier();
/* Finally it is safe to free my network namespace structure */
list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
list_del_init(&net->exit_list);
---
-2.39.5
-
+++ /dev/null
-From 6e77a5a4af05d5e7391c841a4a4f3e4cadf72c25 Mon Sep 17 00:00:00 2001
-From: Eric Dumazet <edumazet@google.com>
-Date: Wed, 8 Feb 2023 18:21:23 +0000
-Subject: net: initialize net->notrefcnt_tracker earlier
-
-From: Eric Dumazet <edumazet@google.com>
-
-commit 6e77a5a4af05d5e7391c841a4a4f3e4cadf72c25 upstream.
-
-syzbot was able to trigger a warning [1] from net_free()
-calling ref_tracker_dir_exit(&net->notrefcnt_tracker)
-while the corresponding ref_tracker_dir_init() has not been
-done yet.
-
-copy_net_ns() can indeed bypass the call to setup_net()
-in some error conditions.
-
-Note:
-
-We might factorize/move more code in preinit_net() in the future.
-
-[1]
-INFO: trying to register non-static key.
-The code is fine but needs lockdep annotation, or maybe
-you didn't initialize this object before use?
-turning off the locking correctness validator.
-CPU: 0 PID: 5817 Comm: syz-executor.3 Not tainted 6.2.0-rc7-next-20230208-syzkaller #0
-Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/12/2023
-Call Trace:
-<TASK>
-__dump_stack lib/dump_stack.c:88 [inline]
-dump_stack_lvl+0xd9/0x150 lib/dump_stack.c:106
-assign_lock_key kernel/locking/lockdep.c:982 [inline]
-register_lock_class+0xdb6/0x1120 kernel/locking/lockdep.c:1295
-__lock_acquire+0x10a/0x5df0 kernel/locking/lockdep.c:4951
-lock_acquire.part.0+0x11c/0x370 kernel/locking/lockdep.c:5691
-__raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
-_raw_spin_lock_irqsave+0x3d/0x60 kernel/locking/spinlock.c:162
-ref_tracker_dir_exit+0x52/0x600 lib/ref_tracker.c:24
-net_free net/core/net_namespace.c:442 [inline]
-net_free+0x98/0xd0 net/core/net_namespace.c:436
-copy_net_ns+0x4f3/0x6b0 net/core/net_namespace.c:493
-create_new_namespaces+0x3f6/0xb20 kernel/nsproxy.c:110
-unshare_nsproxy_namespaces+0xc1/0x1f0 kernel/nsproxy.c:228
-ksys_unshare+0x449/0x920 kernel/fork.c:3205
-__do_sys_unshare kernel/fork.c:3276 [inline]
-__se_sys_unshare kernel/fork.c:3274 [inline]
-__x64_sys_unshare+0x31/0x40 kernel/fork.c:3274
-do_syscall_x64 arch/x86/entry/common.c:50 [inline]
-do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
-
-Fixes: 0cafd77dcd03 ("net: add a refcount tracker for kernel sockets")
-Reported-by: syzbot <syzkaller@googlegroups.com>
-Signed-off-by: Eric Dumazet <edumazet@google.com>
-Link: https://lore.kernel.org/r/20230208182123.3821604-1-edumazet@google.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- net/core/net_namespace.c | 10 +++++++++-
- 1 file changed, 9 insertions(+), 1 deletion(-)
-
---- a/net/core/net_namespace.c
-+++ b/net/core/net_namespace.c
-@@ -307,6 +307,12 @@ struct net *get_net_ns_by_id(const struc
- }
- EXPORT_SYMBOL_GPL(get_net_ns_by_id);
-
-+/* init code that must occur even if setup_net() is not called. */
-+static __net_init void preinit_net(struct net *net)
-+{
-+ ref_tracker_dir_init(&net->notrefcnt_tracker, 128);
-+}
-+
- /*
- * setup_net runs the initializers for the network namespace object.
- */
-@@ -319,7 +325,6 @@ static __net_init int setup_net(struct n
-
- refcount_set(&net->ns.count, 1);
- ref_tracker_dir_init(&net->refcnt_tracker, 128);
-- ref_tracker_dir_init(&net->notrefcnt_tracker, 128);
-
- refcount_set(&net->passive, 1);
- get_random_bytes(&net->hash_mix, sizeof(u32));
-@@ -491,6 +496,8 @@ struct net *copy_net_ns(unsigned long fl
- rv = -ENOMEM;
- goto dec_ucounts;
- }
-+
-+ preinit_net(net);
- refcount_set(&net->passive, 1);
- net->ucounts = ucounts;
- get_user_ns(user_ns);
-@@ -1144,6 +1151,7 @@ void __init net_ns_init(void)
- init_net.key_domain = &init_net_key_domain;
- #endif
- down_write(&pernet_ops_rwsem);
-+ preinit_net(&init_net);
- if (setup_net(&init_net, &init_user_ns))
- panic("Could not setup the initial network namespace");
-