CVE-2024-36933
Publication date:
30/05/2024
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
nsh: Restore skb->{protocol,data,mac_header} for outer header in nsh_gso_segment().<br />
<br />
syzbot triggered various splats (see [0] and links) by a crafted GSO<br />
packet of VIRTIO_NET_HDR_GSO_UDP layering the following protocols:<br />
<br />
ETH_P_8021AD + ETH_P_NSH + ETH_P_IPV6 + IPPROTO_UDP<br />
<br />
NSH can encapsulate IPv4, IPv6, Ethernet, NSH, and MPLS. As the inner<br />
protocol can be Ethernet, NSH GSO handler, nsh_gso_segment(), calls<br />
skb_mac_gso_segment() to invoke inner protocol GSO handlers.<br />
<br />
nsh_gso_segment() does the following for the original skb before<br />
calling skb_mac_gso_segment()<br />
<br />
1. reset skb->network_header<br />
2. save the original skb->{mac_heaeder,mac_len} in a local variable<br />
3. pull the NSH header<br />
4. resets skb->mac_header<br />
5. set up skb->mac_len and skb->protocol for the inner protocol.<br />
<br />
and does the following for the segmented skb<br />
<br />
6. set ntohs(ETH_P_NSH) to skb->protocol<br />
7. push the NSH header<br />
8. restore skb->mac_header<br />
9. set skb->mac_header + mac_len to skb->network_header<br />
10. restore skb->mac_len<br />
<br />
There are two problems in 6-7 and 8-9.<br />
<br />
(a)<br />
After 6 & 7, skb->data points to the NSH header, so the outer header<br />
(ETH_P_8021AD in this case) is stripped when skb is sent out of netdev.<br />
<br />
Also, if NSH is encapsulated by NSH + Ethernet (so NSH-Ethernet-NSH),<br />
skb_pull() in the first nsh_gso_segment() will make skb->data point<br />
to the middle of the outer NSH or Ethernet header because the Ethernet<br />
header is not pulled by the second nsh_gso_segment().<br />
<br />
(b)<br />
While restoring skb->{mac_header,network_header} in 8 & 9,<br />
nsh_gso_segment() does not assume that the data in the linear<br />
buffer is shifted.<br />
<br />
However, udp6_ufo_fragment() could shift the data and change<br />
skb->mac_header accordingly as demonstrated by syzbot.<br />
<br />
If this happens, even the restored skb->mac_header points to<br />
the middle of the outer header.<br />
<br />
It seems nsh_gso_segment() has never worked with outer headers so far.<br />
<br />
At the end of nsh_gso_segment(), the outer header must be restored for<br />
the segmented skb, instead of the NSH header.<br />
<br />
To do that, let&#39;s calculate the outer header position relatively from<br />
the inner header and set skb->{data,mac_header,protocol} properly.<br />
<br />
[0]:<br />
BUG: KMSAN: uninit-value in ipvlan_process_outbound drivers/net/ipvlan/ipvlan_core.c:524 [inline]<br />
BUG: KMSAN: uninit-value in ipvlan_xmit_mode_l3 drivers/net/ipvlan/ipvlan_core.c:602 [inline]<br />
BUG: KMSAN: uninit-value in ipvlan_queue_xmit+0xf44/0x16b0 drivers/net/ipvlan/ipvlan_core.c:668<br />
ipvlan_process_outbound drivers/net/ipvlan/ipvlan_core.c:524 [inline]<br />
ipvlan_xmit_mode_l3 drivers/net/ipvlan/ipvlan_core.c:602 [inline]<br />
ipvlan_queue_xmit+0xf44/0x16b0 drivers/net/ipvlan/ipvlan_core.c:668<br />
ipvlan_start_xmit+0x5c/0x1a0 drivers/net/ipvlan/ipvlan_main.c:222<br />
__netdev_start_xmit include/linux/netdevice.h:4989 [inline]<br />
netdev_start_xmit include/linux/netdevice.h:5003 [inline]<br />
xmit_one net/core/dev.c:3547 [inline]<br />
dev_hard_start_xmit+0x244/0xa10 net/core/dev.c:3563<br />
__dev_queue_xmit+0x33ed/0x51c0 net/core/dev.c:4351<br />
dev_queue_xmit include/linux/netdevice.h:3171 [inline]<br />
packet_xmit+0x9c/0x6b0 net/packet/af_packet.c:276<br />
packet_snd net/packet/af_packet.c:3081 [inline]<br />
packet_sendmsg+0x8aef/0x9f10 net/packet/af_packet.c:3113<br />
sock_sendmsg_nosec net/socket.c:730 [inline]<br />
__sock_sendmsg net/socket.c:745 [inline]<br />
__sys_sendto+0x735/0xa10 net/socket.c:2191<br />
__do_sys_sendto net/socket.c:2203 [inline]<br />
__se_sys_sendto net/socket.c:2199 [inline]<br />
__x64_sys_sendto+0x125/0x1c0 net/socket.c:2199<br />
do_syscall_x64 arch/x86/entry/common.c:52 [inline]<br />
do_syscall_64+0xcf/0x1e0 arch/x86/entry/common.c:83<br />
entry_SYSCALL_64_after_hwframe+0x63/0x6b<br />
<br />
Uninit was created at:<br />
slab_post_alloc_hook mm/slub.c:3819 [inline]<br />
slab_alloc_node mm/slub.c:3860 [inline]<br />
__do_kmalloc_node mm/slub.c:3980 [inline]<br />
__kmalloc_node_track_caller+0x705/0x1000 mm/slub.c:4001<br />
kmalloc_reserve+0x249/0x4a0 net/core/skbuff.c:582<br />
__<br />
---truncated---
Severity CVSS v4.0: Pending analysis
Last modification:
22/01/2026