mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 08:03:01 +09:00
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 <edumazet@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
e5d75fc20b
commit
9ba74e6c9e
@@ -34,6 +34,7 @@
|
||||
#include <net/netns/smc.h>
|
||||
#include <net/netns/bpf.h>
|
||||
#include <net/netns/mctp.h>
|
||||
#include <net/net_trackers.h>
|
||||
#include <linux/ns_common.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/skbuff.h>
|
||||
@@ -87,6 +88,7 @@ struct net {
|
||||
struct idr netns_ids;
|
||||
|
||||
struct ns_common ns;
|
||||
struct ref_tracker_dir refcnt_tracker;
|
||||
|
||||
struct list_head dev_base_head;
|
||||
struct proc_dir_entry *proc_net;
|
||||
@@ -240,6 +242,7 @@ void ipx_unregister_sysctl(void);
|
||||
#ifdef CONFIG_NET_NS
|
||||
void __put_net(struct net *net);
|
||||
|
||||
/* Try using get_net_track() instead */
|
||||
static inline struct net *get_net(struct net *net)
|
||||
{
|
||||
refcount_inc(&net->ns.count);
|
||||
@@ -258,6 +261,7 @@ static inline struct net *maybe_get_net(struct net *net)
|
||||
return net;
|
||||
}
|
||||
|
||||
/* Try using put_net_track() instead */
|
||||
static inline void put_net(struct net *net)
|
||||
{
|
||||
if (refcount_dec_and_test(&net->ns.count))
|
||||
@@ -308,6 +312,36 @@ 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)
|
||||
{
|
||||
#ifdef CONFIG_NET_NS_REFCNT_TRACKER
|
||||
ref_tracker_alloc(&net->refcnt_tracker, tracker, gfp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void netns_tracker_free(struct net *net,
|
||||
netns_tracker *tracker)
|
||||
{
|
||||
#ifdef CONFIG_NET_NS_REFCNT_TRACKER
|
||||
ref_tracker_free(&net->refcnt_tracker, tracker);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline struct net *get_net_track(struct net *net,
|
||||
netns_tracker *tracker, gfp_t gfp)
|
||||
{
|
||||
get_net(net);
|
||||
netns_tracker_alloc(net, tracker, gfp);
|
||||
return net;
|
||||
}
|
||||
|
||||
static inline void put_net_track(struct net *net, netns_tracker *tracker)
|
||||
{
|
||||
netns_tracker_free(net, tracker);
|
||||
put_net(net);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
#ifdef CONFIG_NET_NS
|
||||
struct net *net;
|
||||
|
||||
Reference in New Issue
Block a user