From: Stanislav Fomichev <sdf@google.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, jasowang@redhat.com, brouer@redhat.com,
mst@redhat.com, edumazet@google.com,
Stanislav Fomichev <sdf@google.com>,
syzbot <syzkaller@googlegroups.com>
Subject: [PATCH net 1/2] tun: hold napi_mutex for all napi operations
Date: Mon, 7 Jan 2019 12:02:23 -0800 [thread overview]
Message-ID: <20190107200224.220467-1-sdf@google.com> (raw)
BUG: unable to handle kernel NULL pointer dereference at 00000000000000d1
Call Trace:
? napi_gro_frags+0xa7/0x2c0
tun_get_user+0xb50/0xf20
tun_chr_write_iter+0x53/0x70
new_sync_write+0xff/0x160
vfs_write+0x191/0x1e0
__x64_sys_write+0x5e/0xd0
do_syscall_64+0x47/0xf0
entry_SYSCALL_64_after_hwframe+0x44/0xa9
I think there is a subtle race between sending a packet via tap and
attaching it:
CPU0: CPU1:
tun_chr_ioctl(TUNSETIFF)
tun_set_iff
tun_attach
rcu_assign_pointer(tfile->tun, tun);
tun_fops->write_iter()
tun_chr_write_iter
tun_napi_alloc_frags
napi_get_frags
napi->skb = napi_alloc_skb
tun_napi_init
netif_napi_add
napi->skb = NULL
napi->skb is NULL here
napi_gro_frags
napi_frags_skb
skb = napi->skb
skb_reset_mac_header(skb)
panic()
To fix, do the following:
* Move rcu_assign_pointer(tfile->tun, tun) to be the last thing we do
in tun_attach(); this should guarantee that when we call tun_get()
we always get an initialized object
* As another safeguard, always grab napi_mutex whenever doing any
napi operation; this should prevent napi state change between
calls to napi_get_frags and napi_gro_frags
Reported-by: syzbot <syzkaller@googlegroups.com>
Fixes: 90e33d459407 ("tun: enable napi_gro_frags() for TUN/TAP driver")
Signed-off-by: Stanislav Fomichev <sdf@google.com>
---
drivers/net/tun.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a4fdad475594..7875f06011f2 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -323,22 +323,30 @@ static void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile,
tfile->napi_enabled = napi_en;
tfile->napi_frags_enabled = napi_en && napi_frags;
if (napi_en) {
+ mutex_lock(&tfile->napi_mutex);
netif_napi_add(tun->dev, &tfile->napi, tun_napi_poll,
NAPI_POLL_WEIGHT);
napi_enable(&tfile->napi);
+ mutex_unlock(&tfile->napi_mutex);
}
}
static void tun_napi_disable(struct tun_file *tfile)
{
- if (tfile->napi_enabled)
+ if (tfile->napi_enabled) {
+ mutex_lock(&tfile->napi_mutex);
napi_disable(&tfile->napi);
+ mutex_unlock(&tfile->napi_mutex);
+ }
}
static void tun_napi_del(struct tun_file *tfile)
{
- if (tfile->napi_enabled)
+ if (tfile->napi_enabled) {
+ mutex_lock(&tfile->napi_mutex);
netif_napi_del(&tfile->napi);
+ mutex_unlock(&tfile->napi_mutex);
+ }
}
static bool tun_napi_frags_enabled(const struct tun_file *tfile)
@@ -856,7 +864,6 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
err = 0;
}
- rcu_assign_pointer(tfile->tun, tun);
rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
tun->numqueues++;
@@ -876,6 +883,11 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
* refcnt.
*/
+ /* All tun_fops depend on tun_get() returning non-null pointer.
+ * Thus, assigning tun to a tfile should be the last init operation,
+ * otherwise we risk using half-initialized object.
+ */
+ rcu_assign_pointer(tfile->tun, tun);
out:
return err;
}
--
2.20.1.97.g81188d93c3-goog
next reply other threads:[~2019-01-07 20:02 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-07 20:02 Stanislav Fomichev [this message]
2019-01-07 20:02 ` [PATCH net 2/2] tun: always set skb->dev to tun->dev Stanislav Fomichev
2019-01-07 20:22 ` [PATCH net 1/2] tun: hold napi_mutex for all napi operations Eric Dumazet
2019-01-07 21:02 ` Stanislav Fomichev
2019-01-07 21:10 ` Eric Dumazet
2019-01-07 21:29 ` Stanislav Fomichev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190107200224.220467-1-sdf@google.com \
--to=sdf@google.com \
--cc=brouer@redhat.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=jasowang@redhat.com \
--cc=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=syzkaller@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.