aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipmr.c
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>2015-11-20 07:54:19 -0500
committerDavid S. Miller <davem@davemloft.net>2015-11-22 20:44:46 -0500
commit0e615e9601a15efeeb8942cf7cd4dadba0c8c5a7 (patch)
tree40bd7429b26267edfd83fe9179d304e66b293887 /net/ipv4/ipmr.c
parentf96c9285487f28a90b301718aad86f047d2abb94 (diff)
net: ipmr: fix static mfc/dev leaks on table destruction
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>
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r--net/ipv4/ipmr.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 92dd4b74d513..292123bc30fa 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -134,7 +134,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
134 struct mfc_cache *c, struct rtmsg *rtm); 134 struct mfc_cache *c, struct rtmsg *rtm);
135static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, 135static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
136 int cmd); 136 int cmd);
137static void mroute_clean_tables(struct mr_table *mrt); 137static void mroute_clean_tables(struct mr_table *mrt, bool all);
138static void ipmr_expire_process(unsigned long arg); 138static void ipmr_expire_process(unsigned long arg);
139 139
140#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES 140#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
@@ -350,7 +350,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
350static void ipmr_free_table(struct mr_table *mrt) 350static void ipmr_free_table(struct mr_table *mrt)
351{ 351{
352 del_timer_sync(&mrt->ipmr_expire_timer); 352 del_timer_sync(&mrt->ipmr_expire_timer);
353 mroute_clean_tables(mrt); 353 mroute_clean_tables(mrt, true);
354 kfree(mrt); 354 kfree(mrt);
355} 355}
356 356
@@ -1208,7 +1208,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
1208 * Close the multicast socket, and clear the vif tables etc 1208 * Close the multicast socket, and clear the vif tables etc
1209 */ 1209 */
1210 1210
1211static void mroute_clean_tables(struct mr_table *mrt) 1211static void mroute_clean_tables(struct mr_table *mrt, bool all)
1212{ 1212{
1213 int i; 1213 int i;
1214 LIST_HEAD(list); 1214 LIST_HEAD(list);
@@ -1217,8 +1217,9 @@ static void mroute_clean_tables(struct mr_table *mrt)
1217 /* Shut down all active vif entries */ 1217 /* Shut down all active vif entries */
1218 1218
1219 for (i = 0; i < mrt->maxvif; i++) { 1219 for (i = 0; i < mrt->maxvif; i++) {
1220 if (!(mrt->vif_table[i].flags & VIFF_STATIC)) 1220 if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
1221 vif_delete(mrt, i, 0, &list); 1221 continue;
1222 vif_delete(mrt, i, 0, &list);
1222 } 1223 }
1223 unregister_netdevice_many(&list); 1224 unregister_netdevice_many(&list);
1224 1225
@@ -1226,7 +1227,7 @@ static void mroute_clean_tables(struct mr_table *mrt)
1226 1227
1227 for (i = 0; i < MFC_LINES; i++) { 1228 for (i = 0; i < MFC_LINES; i++) {
1228 list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { 1229 list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
1229 if (c->mfc_flags & MFC_STATIC) 1230 if (!all && (c->mfc_flags & MFC_STATIC))
1230 continue; 1231 continue;
1231 list_del_rcu(&c->list); 1232 list_del_rcu(&c->list);
1232 mroute_netlink_event(mrt, c, RTM_DELROUTE); 1233 mroute_netlink_event(mrt, c, RTM_DELROUTE);
@@ -1261,7 +1262,7 @@ static void mrtsock_destruct(struct sock *sk)
1261 NETCONFA_IFINDEX_ALL, 1262 NETCONFA_IFINDEX_ALL,
1262 net->ipv4.devconf_all); 1263 net->ipv4.devconf_all);
1263 RCU_INIT_POINTER(mrt->mroute_sk, NULL); 1264 RCU_INIT_POINTER(mrt->mroute_sk, NULL);
1264 mroute_clean_tables(mrt); 1265 mroute_clean_tables(mrt, false);
1265 } 1266 }
1266 } 1267 }
1267 rtnl_unlock(); 1268 rtnl_unlock();