From b3c963d51a02153ffd7c2c41ed4a9287c9d25da2 Mon Sep 17 00:00:00 2001 From: Josh Elsasser Date: Mon, 1 Jul 2019 16:48:47 -0700 Subject: [PATCH] net: check before dereferencing netdev_ops during busy poll init_dummy_netdev() leaves its netdev_ops pointer zeroed. This leads to a NULL pointer dereference when sk_busy_loop fires against an iwlwifi wireless adapter and checks napi->dev->netdev_ops->ndo_busy_poll. Avoid this by ensuring napi->dev->netdev_ops is valid before following the pointer, avoiding the following panic when busy polling on a dummy netdev: BUG: unable to handle kernel NULL pointer dereference at 00000000000000c8 IP: [] sk_busy_loop+0x92/0x2f0 Call Trace: [] ? uart_write_room+0x74/0xf0 [] sock_poll+0x99/0xa0 [] do_sys_poll+0x2e2/0x520 [] ? get_page_from_freelist+0x3bc/0xa30 [] ? update_curr+0x62/0x140 [] ? __slab_free+0xa1/0x2a0 [] ? __slab_free+0xa1/0x2a0 [] ? skb_free_head+0x21/0x30 [] ? poll_initwait+0x50/0x50 [] ? kmem_cache_free+0x1c6/0x1e0 [] ? uart_write+0x124/0x1d0 [] ? remove_wait_queue+0x4d/0x60 [] ? __wake_up+0x44/0x50 [] ? tty_write_unlock+0x31/0x40 [] ? tty_ldisc_deref+0x16/0x20 [] ? tty_write+0x1e0/0x2f0 [] ? process_echoes+0x80/0x80 [] ? __vfs_write+0x2b/0x130 [] ? vfs_write+0x15a/0x1a0 [] SyS_poll+0x75/0x100 [] entry_SYSCALL_64_fastpath+0x24/0xcf Commit 79e7fff47b7b ("net: remove support for per driver ndo_busy_poll()") indirectly fixed this upstream in linux-4.11 by removing the offending pointer usage. No other users of napi->dev touch its netdev_ops. Fixes: 8b80cda536ea ("net: rename include/net/ll_poll.h to include/net/busy_poll.h") # 4.4.y Signed-off-by: Josh Elsasser Signed-off-by: Greg Kroah-Hartman --- include/net/busy_poll.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/busy_poll.h b/include/net/busy_poll.h index 1d67fb6b23a0..6d238506d49b 100644 --- a/include/net/busy_poll.h +++ b/include/net/busy_poll.h @@ -93,7 +93,7 @@ static inline bool sk_busy_loop(struct sock *sk, int nonblock) goto out; ops = napi->dev->netdev_ops; - if (!ops->ndo_busy_poll) + if (!ops || !ops->ndo_busy_poll) goto out; do {