Commit 107976b3 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by Greg Kroah-Hartman

net: ipmr: fix static mfc/dev leaks on table destruction

[ Upstream commit 0e615e96 ]

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: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Reviewed-by: default avatarCong Wang <cwang@twopensource.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 72925ccc
...@@ -134,7 +134,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, ...@@ -134,7 +134,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
struct mfc_cache *c, struct rtmsg *rtm); struct mfc_cache *c, struct rtmsg *rtm);
static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
int cmd); 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); static void ipmr_expire_process(unsigned long arg);
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
...@@ -351,7 +351,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) ...@@ -351,7 +351,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
static void ipmr_free_table(struct mr_table *mrt) static void ipmr_free_table(struct mr_table *mrt)
{ {
del_timer_sync(&mrt->ipmr_expire_timer); del_timer_sync(&mrt->ipmr_expire_timer);
mroute_clean_tables(mrt); mroute_clean_tables(mrt, true);
kfree(mrt); kfree(mrt);
} }
...@@ -1209,7 +1209,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, ...@@ -1209,7 +1209,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
* Close the multicast socket, and clear the vif tables etc * 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; int i;
LIST_HEAD(list); LIST_HEAD(list);
...@@ -1218,8 +1218,9 @@ static void mroute_clean_tables(struct mr_table *mrt) ...@@ -1218,8 +1218,9 @@ static void mroute_clean_tables(struct mr_table *mrt)
/* Shut down all active vif entries */ /* Shut down all active vif entries */
for (i = 0; i < mrt->maxvif; i++) { for (i = 0; i < mrt->maxvif; i++) {
if (!(mrt->vif_table[i].flags & VIFF_STATIC)) if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
vif_delete(mrt, i, 0, &list); continue;
vif_delete(mrt, i, 0, &list);
} }
unregister_netdevice_many(&list); unregister_netdevice_many(&list);
...@@ -1227,7 +1228,7 @@ static void mroute_clean_tables(struct mr_table *mrt) ...@@ -1227,7 +1228,7 @@ static void mroute_clean_tables(struct mr_table *mrt)
for (i = 0; i < MFC_LINES; i++) { for (i = 0; i < MFC_LINES; i++) {
list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { 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; continue;
list_del_rcu(&c->list); list_del_rcu(&c->list);
mroute_netlink_event(mrt, c, RTM_DELROUTE); mroute_netlink_event(mrt, c, RTM_DELROUTE);
...@@ -1262,7 +1263,7 @@ static void mrtsock_destruct(struct sock *sk) ...@@ -1262,7 +1263,7 @@ static void mrtsock_destruct(struct sock *sk)
NETCONFA_IFINDEX_ALL, NETCONFA_IFINDEX_ALL,
net->ipv4.devconf_all); net->ipv4.devconf_all);
RCU_INIT_POINTER(mrt->mroute_sk, NULL); RCU_INIT_POINTER(mrt->mroute_sk, NULL);
mroute_clean_tables(mrt); mroute_clean_tables(mrt, false);
} }
} }
rtnl_unlock(); rtnl_unlock();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment