| From foo@baz Fri Dec 11 11:39:46 EST 2015 |
| From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| Date: Fri, 20 Nov 2015 13:54:19 +0100 |
| Subject: net: ipmr: fix static mfc/dev leaks on table destruction |
| |
| From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| |
| [ Upstream commit 0e615e9601a15efeeb8942cf7cd4dadba0c8c5a7 ] |
| |
| When destroying an mrt table the static mfc entries and the static |
| devices are kept, which leads to devices that can never be destroyed |
| (because of refcnt taken) and leaked memory, for example: |
| unreferenced object 0xffff880034c144c0 (size 192): |
| comm "mfc-broken", pid 4777, jiffies 4320349055 (age 46001.964s) |
| hex dump (first 32 bytes): |
| 98 53 f0 34 00 88 ff ff 98 53 f0 34 00 88 ff ff .S.4.....S.4.... |
| ef 0a 0a 14 01 02 03 04 00 00 00 00 01 00 00 00 ................ |
| backtrace: |
| [<ffffffff815c1b9e>] kmemleak_alloc+0x4e/0xb0 |
| [<ffffffff811ea6e0>] kmem_cache_alloc+0x190/0x300 |
| [<ffffffff815931cb>] ip_mroute_setsockopt+0x5cb/0x910 |
| [<ffffffff8153d575>] do_ip_setsockopt.isra.11+0x105/0xff0 |
| [<ffffffff8153e490>] ip_setsockopt+0x30/0xa0 |
| [<ffffffff81564e13>] raw_setsockopt+0x33/0x90 |
| [<ffffffff814d1e14>] sock_common_setsockopt+0x14/0x20 |
| [<ffffffff814d0b51>] SyS_setsockopt+0x71/0xc0 |
| [<ffffffff815cdbf6>] entry_SYSCALL_64_fastpath+0x16/0x7a |
| [<ffffffffffffffff>] 0xffffffffffffffff |
| |
| Make sure that everything is cleaned on netns destruction. |
| |
| Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| Reviewed-by: Cong Wang <cwang@twopensource.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/ipmr.c | 15 ++++++++------- |
| 1 file changed, 8 insertions(+), 7 deletions(-) |
| |
| --- a/net/ipv4/ipmr.c |
| +++ b/net/ipv4/ipmr.c |
| @@ -136,7 +136,7 @@ static int __ipmr_fill_mroute(struct mr_ |
| struct mfc_cache *c, struct rtmsg *rtm); |
| static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, |
| int cmd); |
| -static void mroute_clean_tables(struct mr_table *mrt); |
| +static void mroute_clean_tables(struct mr_table *mrt, bool all); |
| static void ipmr_expire_process(unsigned long arg); |
| |
| #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES |
| @@ -348,7 +348,7 @@ static struct mr_table *ipmr_new_table(s |
| static void ipmr_free_table(struct mr_table *mrt) |
| { |
| del_timer_sync(&mrt->ipmr_expire_timer); |
| - mroute_clean_tables(mrt); |
| + mroute_clean_tables(mrt, true); |
| kfree(mrt); |
| } |
| |
| @@ -1199,7 +1199,7 @@ static int ipmr_mfc_add(struct net *net, |
| * Close the multicast socket, and clear the vif tables etc |
| */ |
| |
| -static void mroute_clean_tables(struct mr_table *mrt) |
| +static void mroute_clean_tables(struct mr_table *mrt, bool all) |
| { |
| int i; |
| LIST_HEAD(list); |
| @@ -1208,8 +1208,9 @@ static void mroute_clean_tables(struct m |
| /* Shut down all active vif entries */ |
| |
| for (i = 0; i < mrt->maxvif; i++) { |
| - if (!(mrt->vif_table[i].flags & VIFF_STATIC)) |
| - vif_delete(mrt, i, 0, &list); |
| + if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) |
| + continue; |
| + vif_delete(mrt, i, 0, &list); |
| } |
| unregister_netdevice_many(&list); |
| |
| @@ -1217,7 +1218,7 @@ static void mroute_clean_tables(struct m |
| |
| for (i = 0; i < MFC_LINES; i++) { |
| list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { |
| - if (c->mfc_flags & MFC_STATIC) |
| + if (!all && (c->mfc_flags & MFC_STATIC)) |
| continue; |
| list_del_rcu(&c->list); |
| mroute_netlink_event(mrt, c, RTM_DELROUTE); |
| @@ -1252,7 +1253,7 @@ static void mrtsock_destruct(struct sock |
| NETCONFA_IFINDEX_ALL, |
| net->ipv4.devconf_all); |
| RCU_INIT_POINTER(mrt->mroute_sk, NULL); |
| - mroute_clean_tables(mrt); |
| + mroute_clean_tables(mrt, false); |
| } |
| } |
| rtnl_unlock(); |