• Ziyang Xuan's avatar
    net: tun: fix bugs for oversize packet when napi frags enabled · 363a5328
    Ziyang Xuan authored
    Recently, we got two syzkaller problems because of oversize packet
    when napi frags enabled.
    
    One of the problems is because the first seg size of the iov_iter
    from user space is very big, it is 2147479538 which is bigger than
    the threshold value for bail out early in __alloc_pages(). And
    skb->pfmemalloc is true, __kmalloc_reserve() would use pfmemalloc
    reserves without __GFP_NOWARN flag. Thus we got a warning as following:
    
    ========================================================
    WARNING: CPU: 1 PID: 17965 at mm/page_alloc.c:5295 __alloc_pages+0x1308/0x16c4 mm/page_alloc.c:5295
    ...
    Call trace:
     __alloc_pages+0x1308/0x16c4 mm/page_alloc.c:5295
     __alloc_pages_node include/linux/gfp.h:550 [inline]
     alloc_pages_node include/linux/gfp.h:564 [inline]
     kmalloc_large_node+0x94/0x350 mm/slub.c:4038
     __kmalloc_node_track_caller+0x620/0x8e4 mm/slub.c:4545
     __kmalloc_reserve.constprop.0+0x1e4/0x2b0 net/core/skbuff.c:151
     pskb_expand_head+0x130/0x8b0 net/core/skbuff.c:1654
     __skb_grow include/linux/skbuff.h:2779 [inline]
     tun_napi_alloc_frags+0x144/0x610 drivers/net/tun.c:1477
     tun_get_user+0x31c/0x2010 drivers/net/tun.c:1835
     tun_chr_write_iter+0x98/0x100 drivers/net/tun.c:2036
    
    The other problem is because odd IPv6 packets without NEXTHDR_NONE
    extension header and have big packet length, it is 2127925 which is
    bigger than ETH_MAX_MTU(65535). After ipv6_gso_pull_exthdrs() in
    ipv6_gro_receive(), network_header offset and transport_header offset
    are all bigger than U16_MAX. That would trigger skb->network_header
    and skb->transport_header overflow error, because they are all '__u16'
    type. Eventually, it would affect the value for __skb_push(skb, value),
    and make it be a big value. After __skb_push() in ipv6_gro_receive(),
    skb->data would less than skb->head, an out of bounds memory bug occurred.
    That would trigger the problem as following:
    
    ==================================================================
    BUG: KASAN: use-after-free in eth_type_trans+0x100/0x260
    ...
    Call trace:
     dump_backtrace+0xd8/0x130
     show_stack+0x1c/0x50
     dump_stack_lvl+0x64/0x7c
     print_address_description.constprop.0+0xbc/0x2e8
     print_report+0x100/0x1e4
     kasan_report+0x80/0x120
     __asan_load8+0x78/0xa0
     eth_type_trans+0x100/0x260
     napi_gro_frags+0x164/0x550
     tun_get_user+0xda4/0x1270
     tun_chr_write_iter+0x74/0x130
     do_iter_readv_writev+0x130/0x1ec
     do_iter_write+0xbc/0x1e0
     vfs_writev+0x13c/0x26c
    
    To fix the problems, restrict the packet size less than
    (ETH_MAX_MTU - NET_SKB_PAD - NET_IP_ALIGN) which has considered reserved
    skb space in napi_alloc_skb() because transport_header is an offset from
    skb->head. Add len check in tun_napi_alloc_frags() simply.
    
    Fixes: 90e33d45 ("tun: enable napi_gro_frags() for TUN/TAP driver")
    Signed-off-by: default avatarZiyang Xuan <william.xuanziyang@huawei.com>
    Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
    Link: https://lore.kernel.org/r/20221029094101.1653855-1-william.xuanziyang@huawei.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
    363a5328
tun.c 86.2 KB