Skip to content

Commit 9ba74e6

Browse files
edumazetkuba-moo
authored andcommitted
net: add networking namespace refcount tracker
We have 100+ syzbot reports about netns being dismantled too soon, still unresolved as of today. We think a missing get_net() or an extra put_net() is the root cause. In order to find the bug(s), and be able to spot future ones, this patch adds CONFIG_NET_NS_REFCNT_TRACKER and new helpers to precisely pair all put_net() with corresponding get_net(). To use these helpers, each data structure owning a refcount should also use a "netns_tracker" to pair the get and put. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent e5d75fc commit 9ba74e6

File tree

5 files changed

+65
-8
lines changed

5 files changed

+65
-8
lines changed

include/linux/netdevice.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
#include <uapi/linux/pkt_cls.h>
4949
#include <linux/hashtable.h>
5050
#include <linux/rbtree.h>
51-
#include <linux/ref_tracker.h>
51+
#include <net/net_trackers.h>
5252

5353
struct netpoll_info;
5454
struct device;
@@ -300,13 +300,6 @@ enum netdev_state_t {
300300
__LINK_STATE_TESTING,
301301
};
302302

303-
304-
#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
305-
typedef struct ref_tracker *netdevice_tracker;
306-
#else
307-
typedef struct {} netdevice_tracker;
308-
#endif
309-
310303
struct gro_list {
311304
struct list_head list;
312305
int count;

include/net/net_namespace.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <net/netns/smc.h>
3535
#include <net/netns/bpf.h>
3636
#include <net/netns/mctp.h>
37+
#include <net/net_trackers.h>
3738
#include <linux/ns_common.h>
3839
#include <linux/idr.h>
3940
#include <linux/skbuff.h>
@@ -87,6 +88,7 @@ struct net {
8788
struct idr netns_ids;
8889

8990
struct ns_common ns;
91+
struct ref_tracker_dir refcnt_tracker;
9092

9193
struct list_head dev_base_head;
9294
struct proc_dir_entry *proc_net;
@@ -240,6 +242,7 @@ void ipx_unregister_sysctl(void);
240242
#ifdef CONFIG_NET_NS
241243
void __put_net(struct net *net);
242244

245+
/* Try using get_net_track() instead */
243246
static inline struct net *get_net(struct net *net)
244247
{
245248
refcount_inc(&net->ns.count);
@@ -258,6 +261,7 @@ static inline struct net *maybe_get_net(struct net *net)
258261
return net;
259262
}
260263

264+
/* Try using put_net_track() instead */
261265
static inline void put_net(struct net *net)
262266
{
263267
if (refcount_dec_and_test(&net->ns.count))
@@ -308,6 +312,36 @@ static inline int check_net(const struct net *net)
308312
#endif
309313

310314

315+
static inline void netns_tracker_alloc(struct net *net,
316+
netns_tracker *tracker, gfp_t gfp)
317+
{
318+
#ifdef CONFIG_NET_NS_REFCNT_TRACKER
319+
ref_tracker_alloc(&net->refcnt_tracker, tracker, gfp);
320+
#endif
321+
}
322+
323+
static inline void netns_tracker_free(struct net *net,
324+
netns_tracker *tracker)
325+
{
326+
#ifdef CONFIG_NET_NS_REFCNT_TRACKER
327+
ref_tracker_free(&net->refcnt_tracker, tracker);
328+
#endif
329+
}
330+
331+
static inline struct net *get_net_track(struct net *net,
332+
netns_tracker *tracker, gfp_t gfp)
333+
{
334+
get_net(net);
335+
netns_tracker_alloc(net, tracker, gfp);
336+
return net;
337+
}
338+
339+
static inline void put_net_track(struct net *net, netns_tracker *tracker)
340+
{
341+
netns_tracker_free(net, tracker);
342+
put_net(net);
343+
}
344+
311345
typedef struct {
312346
#ifdef CONFIG_NET_NS
313347
struct net *net;

include/net/net_trackers.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __NET_NET_TRACKERS_H
3+
#define __NET_NET_TRACKERS_H
4+
#include <linux/ref_tracker.h>
5+
6+
#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
7+
typedef struct ref_tracker *netdevice_tracker;
8+
#else
9+
typedef struct {} netdevice_tracker;
10+
#endif
11+
12+
#ifdef CONFIG_NET_NS_REFCNT_TRACKER
13+
typedef struct ref_tracker *netns_tracker;
14+
#else
15+
typedef struct {} netns_tracker;
16+
#endif
17+
18+
#endif /* __NET_NET_TRACKERS_H */

net/Kconfig.debug

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,12 @@ config NET_DEV_REFCNT_TRACKER
88
help
99
Enable debugging feature to track device references.
1010
This adds memory and cpu costs.
11+
12+
config NET_NS_REFCNT_TRACKER
13+
bool "Enable networking namespace refcount tracking"
14+
depends on DEBUG_KERNEL && STACKTRACE_SUPPORT
15+
select REF_TRACKER
16+
default n
17+
help
18+
Enable debugging feature to track netns references.
19+
This adds memory and cpu costs.

net/core/net_namespace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
311311
LIST_HEAD(net_exit_list);
312312

313313
refcount_set(&net->ns.count, 1);
314+
ref_tracker_dir_init(&net->refcnt_tracker, 128);
315+
314316
refcount_set(&net->passive, 1);
315317
get_random_bytes(&net->hash_mix, sizeof(u32));
316318
preempt_disable();
@@ -635,6 +637,7 @@ static DECLARE_WORK(net_cleanup_work, cleanup_net);
635637

636638
void __put_net(struct net *net)
637639
{
640+
ref_tracker_dir_exit(&net->refcnt_tracker);
638641
/* Cleanup the network namespace in process context */
639642
if (llist_add(&net->cleanup_list, &cleanup_list))
640643
queue_work(netns_wq, &net_cleanup_work);

0 commit comments

Comments
 (0)