In the Linux kernel, the following vulnerability has been resolved:
nsh: Restore skb->{protocol,data,macheader} for outer header in nshgso_segment().
syzbot triggered various splats (see [0] and links) by a crafted GSO packet of VIRTIONETHDRGSOUDP layering the following protocols:
ETHP8021AD + ETHPNSH + ETHPIPV6 + IPPROTO_UDP
NSH can encapsulate IPv4, IPv6, Ethernet, NSH, and MPLS. As the inner protocol can be Ethernet, NSH GSO handler, nshgsosegment(), calls skbmacgso_segment() to invoke inner protocol GSO handlers.
nshgsosegment() does the following for the original skb before calling skbmacgso_segment()
and does the following for the segmented skb
There are two problems in 6-7 and 8-9.
(a) After 6 & 7, skb->data points to the NSH header, so the outer header (ETHP8021AD in this case) is stripped when skb is sent out of netdev.
Also, if NSH is encapsulated by NSH + Ethernet (so NSH-Ethernet-NSH), skbpull() in the first nshgsosegment() will make skb->data point to the middle of the outer NSH or Ethernet header because the Ethernet header is not pulled by the second nshgso_segment().
(b) While restoring skb->{macheader,networkheader} in 8 & 9, nshgsosegment() does not assume that the data in the linear buffer is shifted.
However, udp6ufofragment() could shift the data and change skb->mac_header accordingly as demonstrated by syzbot.
If this happens, even the restored skb->mac_header points to the middle of the outer header.
It seems nshgsosegment() has never worked with outer headers so far.
At the end of nshgsosegment(), the outer header must be restored for the segmented skb, instead of the NSH header.
To do that, let's calculate the outer header position relatively from the inner header and set skb->{data,mac_header,protocol} properly.
BUG: KMSAN: uninit-value in ipvlanxmitmodel3 drivers/net/ipvlan/ipvlancore.c:602 [inline] BUG: KMSAN: uninit-value in ipvlanqueuexmit+0xf44/0x16b0 drivers/net/ipvlan/ipvlancore.c:668 ipvlanprocessoutbound drivers/net/ipvlan/ipvlancore.c:524 [inline] ipvlanxmitmodel3 drivers/net/ipvlan/ipvlancore.c:602 [inline] ipvlanqueuexmit+0xf44/0x16b0 drivers/net/ipvlan/ipvlancore.c:668 ipvlanstartxmit+0x5c/0x1a0 drivers/net/ipvlan/ipvlanmain.c:222 _netdevstartxmit include/linux/netdevice.h:4989 [inline] netdevstartxmit include/linux/netdevice.h:5003 [inline] xmitone net/core/dev.c:3547 [inline] devhardstartxmit+0x244/0xa10 net/core/dev.c:3563 _devqueuexmit+0x33ed/0x51c0 net/core/dev.c:4351 devqueuexmit include/linux/netdevice.h:3171 [inline] packetxmit+0x9c/0x6b0 net/packet/afpacket.c:276 packetsnd net/packet/afpacket.c:3081 [inline] packetsendmsg+0x8aef/0x9f10 net/packet/afpacket.c:3113 socksendmsgnosec net/socket.c:730 [inline] _socksendmsg net/socket.c:745 [inline] _syssendto+0x735/0xa10 net/socket.c:2191 _dosyssendto net/socket.c:2203 [inline] _sesyssendto net/socket.c:2199 [inline] _x64syssendto+0x125/0x1c0 net/socket.c:2199 dosyscallx64 arch/x86/entry/common.c:52 [inline] dosyscall64+0xcf/0x1e0 arch/x86/entry/common.c:83 entrySYSCALL64after_hwframe+0x63/0x6b
Uninit was created at: slabpostallochook mm/slub.c:3819 [inline] slaballocnode mm/slub.c:3860 [inline] _dokmallocnode mm/slub.c:3980 [inline] _kmallocnodetrackcaller+0x705/0x1000 mm/slub.c:4001 kmallocreserve+0x249/0x4a0 net/core/skbuff.c:582 _ ---truncated---