]> git.ipfire.org Git - thirdparty/linux.git/commit - drivers/net/tun.c
tun: publish tfile after it's fully initialized
authorStanislav Fomichev <sdf@google.com>
Mon, 7 Jan 2019 21:38:38 +0000 (13:38 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Jan 2019 14:24:38 +0000 (09:24 -0500)
commit0b7959b6257322f7693b08a459c505d4938646f2
tree97b2b16fe998f2a85e29f0fff7449b2c98d5c7bd
parentd972f3dce8d161e2142da0ab1ef25df00e2f21a9
tun: publish tfile after it's fully initialized

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()

Move rcu_assign_pointer(tfile->tun) and rcu_assign_pointer(tun->tfiles) 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.

v2 changes:
* remove extra napi_mutex locks/unlocks for napi operations

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>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/tun.c