Message ID | 20250114011354.2096812-1-jsperbeck@google.com (mailing list archive) |
---|---|
State | New |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net,v3] net: netpoll: ensure skb_pool list is always initialized | expand |
On Mon, Jan 13, 2025 at 05:13:54PM -0800, John Sperbeck wrote: > When __netpoll_setup() is called directly, instead of through > netpoll_setup(), the np->skb_pool list head isn't initialized. > If skb_pool_flush() is later called, then we hit a NULL pointer > in skb_queue_purge_reason(). This can be seen with this repro, > when CONFIG_NETCONSOLE is enabled as a module: > > ip tuntap add mode tap tap0 > ip link add name br0 type bridge > ip link set dev tap0 master br0 > modprobe netconsole netconsole=4444@10.0.0.1/br0,9353@10.0.0.2/ > rmmod netconsole > > The backtrace is: > > BUG: kernel NULL pointer dereference, address: 0000000000000008 > #PF: supervisor write access in kernel mode > #PF: error_code(0x0002) - not-present page > ... ... ... > Call Trace: > <TASK> > __netpoll_free+0xa5/0xf0 > br_netpoll_cleanup+0x43/0x50 [bridge] > do_netpoll_cleanup+0x43/0xc0 > netconsole_netdev_event+0x1e3/0x300 [netconsole] > unregister_netdevice_notifier+0xd9/0x150 > cleanup_module+0x45/0x920 [netconsole] > __se_sys_delete_module+0x205/0x290 > do_syscall_64+0x70/0x150 > entry_SYSCALL_64_after_hwframe+0x76/0x7e > > Move the skb_pool list setup and initial skb fill into __netpoll_setup(). > > Fixes: 221a9c1df790 ("net: netpoll: Individualize the skb pool") > Signed-off-by: John Sperbeck <jsperbeck@google.com> Reviewed-by: Breno Leitao <leitao@debian.org>
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 2e459b9d88eb..96a6ed37d4cc 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -627,6 +627,8 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev) const struct net_device_ops *ops; int err; + skb_queue_head_init(&np->skb_pool); + if (ndev->priv_flags & IFF_DISABLE_NETPOLL) { np_err(np, "%s doesn't support polling, aborting\n", ndev->name); @@ -662,6 +664,9 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev) strscpy(np->dev_name, ndev->name, IFNAMSIZ); npinfo->netpoll = np; + /* fill up the skb queue */ + refill_skbs(np); + /* last thing to do is link it to the net device structure */ rcu_assign_pointer(ndev->npinfo, npinfo); @@ -681,8 +686,6 @@ int netpoll_setup(struct netpoll *np) struct in_device *in_dev; int err; - skb_queue_head_init(&np->skb_pool); - rtnl_lock(); if (np->dev_name[0]) { struct net *net = current->nsproxy->net_ns; @@ -782,9 +785,6 @@ int netpoll_setup(struct netpoll *np) } } - /* fill up the skb queue */ - refill_skbs(np); - err = __netpoll_setup(np, ndev); if (err) goto flush;
When __netpoll_setup() is called directly, instead of through netpoll_setup(), the np->skb_pool list head isn't initialized. If skb_pool_flush() is later called, then we hit a NULL pointer in skb_queue_purge_reason(). This can be seen with this repro, when CONFIG_NETCONSOLE is enabled as a module: ip tuntap add mode tap tap0 ip link add name br0 type bridge ip link set dev tap0 master br0 modprobe netconsole netconsole=4444@10.0.0.1/br0,9353@10.0.0.2/ rmmod netconsole The backtrace is: BUG: kernel NULL pointer dereference, address: 0000000000000008 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page ... ... ... Call Trace: <TASK> __netpoll_free+0xa5/0xf0 br_netpoll_cleanup+0x43/0x50 [bridge] do_netpoll_cleanup+0x43/0xc0 netconsole_netdev_event+0x1e3/0x300 [netconsole] unregister_netdevice_notifier+0xd9/0x150 cleanup_module+0x45/0x920 [netconsole] __se_sys_delete_module+0x205/0x290 do_syscall_64+0x70/0x150 entry_SYSCALL_64_after_hwframe+0x76/0x7e Move the skb_pool list setup and initial skb fill into __netpoll_setup(). Fixes: 221a9c1df790 ("net: netpoll: Individualize the skb pool") Signed-off-by: John Sperbeck <jsperbeck@google.com> --- Updated mail message subject to target the 'net' tree. net/core/netpoll.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)