[lkml]   [2014]   [Jun]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
Subject[PATCH net-next v1 1/2] netpoll: fix use after free
After a bonding master reclaims the netpoll info struct, slaves could
still hold a pointer to the reclaimed data. This patch fixes it: as
soon as netpoll_async_cleanup is called for a slave (eg. when
un-enslaved), we make sure that this slave doesn't point to the data.

The style of this patch is not nice, but it represents the simplest
fix. The function is restructured by the next patch anyway ("netpoll:
avoid reference leaks").

One way to reproduce the panic is with netconsole: with the script
below run in a loop without this patch. Same procedure with this
patch can run without panic.
Then run in a loop (dual port NIC makes it easier to crash):
ifconfig eth0 up
ifconfig eth1 up
sleep 10
modprobe -r netconsole
modprobe -r bonding
modprobe netconsole
modprobe bonding mode=4
echo +bond0 > /sys/class/net/bonding_masters
ifconfig bond0 up
mkdir /sys/kernel/config/netconsole/blah
echo 0 > /sys/kernel/config/netconsole/blah/enabled
echo bond0 > /sys/kernel/config/netconsole/blah/dev_name
echo > /sys/kernel/config/netconsole/blah/remote_ip
echo 1 > /sys/kernel/config/netconsole/blah/enabled
# npinfo refcnt ->1
ifenslave bond0 eth1
# npinfo refcnt ->2
ifenslave bond0 eth0
# (this should be optional, preventing ndo_cleanup_nepoll below)
# npinfo refcnt ->3
sleep 3
ifenslave -d bond0 eth1
# npinfo refcnt ->2, eth1 keeps ptr to npinfo reclaimed later => garbage
sleep 1
echo -bond0 > /sys/class/net/bonding_masters
# netpoll_cleanup(bond0) + dec(refcnt)
# (should be optional: becomes -> 1 (aka. != 0)
# ==> do not call ndo_cleanup_nepoll)
# try to increase chance of writing garbage onto npinfo:
ls -lR / 2>&1 | tail -30
echo +bond0 > /sys/class/net/bonding_masters
ifconfig bond0 up
ifenslave bond0 eth1
# dev_open() called --> netpoll_rx_disable() + npinfo is garbage
# -> down(&ni->dev_lock);

Signed-off-by: David Decotigny <>
net/core/netpoll.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index e33937f..907fb5e 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -822,7 +822,8 @@ void __netpoll_cleanup(struct netpoll *np)

RCU_INIT_POINTER(np->dev->npinfo, NULL);
call_rcu_bh(&npinfo->rcu, rcu_cleanup_netpoll_info);
- }
+ } else
+ RCU_INIT_POINTER(np->dev->npinfo, NULL);


 \ /
  Last update: 2014-07-01 02:01    [W:0.057 / U:3.500 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site