From 1d6119baf0610f813eb9d9580eb4fd16de5b4ceb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 2 Nov 2015 09:03:11 -0800 Subject: net: fix percpu memory leaks This patch fixes following problems : 1) percpu_counter_init() can return an error, therefore init_frag_mem_limit() must propagate this error so that inet_frags_init_net() can do the same up to its callers. 2) If ip[46]_frags_ns_ctl_register() fail, we must unwind properly and free the percpu_counter. Without this fix, we leave freed object in percpu_counters global list (if CONFIG_HOTPLUG_CPU) leading to crashes. This bug was detected by KASAN and syzkaller tool (http://github.com/google/syzkaller) Fixes: 6d7b857d541e ("net: use lib/percpu_counter API for fragmentation mem accounting") Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Cc: Hannes Frederic Sowa Cc: Jesper Dangaard Brouer Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/net/inet_frag.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 53eead2da743..ac42bbb37b2d 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -108,7 +108,15 @@ struct inet_frags { int inet_frags_init(struct inet_frags *); void inet_frags_fini(struct inet_frags *); -void inet_frags_init_net(struct netns_frags *nf); +static inline int inet_frags_init_net(struct netns_frags *nf) +{ + return percpu_counter_init(&nf->mem, 0, GFP_KERNEL); +} +static inline void inet_frags_uninit_net(struct netns_frags *nf) +{ + percpu_counter_destroy(&nf->mem); +} + void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f); void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); @@ -154,11 +162,6 @@ static inline void add_frag_mem_limit(struct netns_frags *nf, int i) __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch); } -static inline void init_frag_mem_limit(struct netns_frags *nf) -{ - percpu_counter_init(&nf->mem, 0, GFP_KERNEL); -} - static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf) { unsigned int res; -- cgit v1.2.3