Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Nikolay Aleksandrov and committed by
David S. Miller
0e615e96 f96c9285

+8 -7
+8 -7
net/ipv4/ipmr.c
··· 134 134 struct mfc_cache *c, struct rtmsg *rtm); 135 135 static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, 136 136 int cmd); 137 - static void mroute_clean_tables(struct mr_table *mrt); 137 + static void mroute_clean_tables(struct mr_table *mrt, bool all); 138 138 static void ipmr_expire_process(unsigned long arg); 139 139 140 140 #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES ··· 350 350 static void ipmr_free_table(struct mr_table *mrt) 351 351 { 352 352 del_timer_sync(&mrt->ipmr_expire_timer); 353 - mroute_clean_tables(mrt); 353 + mroute_clean_tables(mrt, true); 354 354 kfree(mrt); 355 355 } 356 356 ··· 1208 1208 * Close the multicast socket, and clear the vif tables etc 1209 1209 */ 1210 1210 1211 - static void mroute_clean_tables(struct mr_table *mrt) 1211 + static void mroute_clean_tables(struct mr_table *mrt, bool all) 1212 1212 { 1213 1213 int i; 1214 1214 LIST_HEAD(list); ··· 1217 1217 /* Shut down all active vif entries */ 1218 1218 1219 1219 for (i = 0; i < mrt->maxvif; i++) { 1220 - if (!(mrt->vif_table[i].flags & VIFF_STATIC)) 1221 - vif_delete(mrt, i, 0, &list); 1220 + if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) 1221 + continue; 1222 + vif_delete(mrt, i, 0, &list); 1222 1223 } 1223 1224 unregister_netdevice_many(&list); 1224 1225 ··· 1227 1226 1228 1227 for (i = 0; i < MFC_LINES; i++) { 1229 1228 list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { 1230 - if (c->mfc_flags & MFC_STATIC) 1229 + if (!all && (c->mfc_flags & MFC_STATIC)) 1231 1230 continue; 1232 1231 list_del_rcu(&c->list); 1233 1232 mroute_netlink_event(mrt, c, RTM_DELROUTE); ··· 1262 1261 NETCONFA_IFINDEX_ALL, 1263 1262 net->ipv4.devconf_all); 1264 1263 RCU_INIT_POINTER(mrt->mroute_sk, NULL); 1265 - mroute_clean_tables(mrt); 1264 + mroute_clean_tables(mrt, false); 1266 1265 } 1267 1266 } 1268 1267 rtnl_unlock();