aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Wang <weiwan@google.com>2018-09-18 16:45:00 -0400
committerDavid S. Miller <davem@davemloft.net>2018-09-18 23:17:01 -0400
commitce7ea4af0838ffd4667ecad4eb5eec7a25342f1e (patch)
tree196f9e53a53e7aa2c52573c446400640d54f35ad
parent8675860592321a43bbb0b5aedc244a9b2321edc3 (diff)
ipv6: fix memory leak on dst->_metrics
When dst->_metrics and f6i->fib6_metrics share the same memory, both take reference count on the dst_metrics structure. However, when dst is destroyed, ip6_dst_destroy() only invokes dst_destroy_metrics_generic() which does not take care of READONLY metrics and does not release refcnt. This causes memory leak. Similar to ipv4 logic, the fix is to properly release refcnt and free the memory space pointed by dst->_metrics if refcnt becomes 0. Fixes: 93531c674315 ("net/ipv6: separate handling of FIB entries from dst based routes") Reported-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Wei Wang <weiwan@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/route.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b5d3e6b294ab..826b14de7dbb 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -364,11 +364,14 @@ EXPORT_SYMBOL(ip6_dst_alloc);
364 364
365static void ip6_dst_destroy(struct dst_entry *dst) 365static void ip6_dst_destroy(struct dst_entry *dst)
366{ 366{
367 struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
367 struct rt6_info *rt = (struct rt6_info *)dst; 368 struct rt6_info *rt = (struct rt6_info *)dst;
368 struct fib6_info *from; 369 struct fib6_info *from;
369 struct inet6_dev *idev; 370 struct inet6_dev *idev;
370 371
371 dst_destroy_metrics_generic(dst); 372 if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
373 kfree(p);
374
372 rt6_uncached_list_del(rt); 375 rt6_uncached_list_del(rt);
373 376
374 idev = rt->rt6i_idev; 377 idev = rt->rt6i_idev;