net: netpoll: ensure skb_pool list is always initialized
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: 221a9c1df7 ("net: netpoll: Individualize the skb pool")
Signed-off-by: John Sperbeck <jsperbeck@google.com>
Reviewed-by: Breno Leitao <leitao@debian.org>
Link: https://patch.msgid.link/20250114011354.2096812-1-jsperbeck@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
c17ff476f5
commit
f0d0277796
+5
-5
@@ -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 @@ put_noaddr:
|
||||
}
|
||||
}
|
||||
|
||||
/* fill up the skb queue */
|
||||
refill_skbs(np);
|
||||
|
||||
err = __netpoll_setup(np, ndev);
|
||||
if (err)
|
||||
goto flush;
|
||||
|
||||
Reference in New Issue
Block a user