FAILED: patch "[PATCH] net/packet: fix TOCTOU race on mmap'd vnet_hdr in" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 2c054e17d9d41f1020376806c7f750834ced4dc5
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026042433-handpick-copy-d2e1@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 2c054e17d9d41f1020376806c7f750834ced4dc5 Mon Sep 17 00:00:00 2001
From: Bingquan Chen <[email protected]>
Date: Sat, 18 Apr 2026 19:20:06 +0800
Subject: [PATCH] net/packet: fix TOCTOU race on mmap'd vnet_hdr in
tpacket_snd()
In tpacket_snd(), when PACKET_VNET_HDR is enabled, vnet_hdr points directly into the mmap'd TX ring buffer shared with userspace. The kernel validates the header via __packet_snd_vnet_parse() but then re-reads all fields later in virtio_net_hdr_to_skb(). A concurrent userspace thread can modify the vnet_hdr fields between validation and use, bypassing all safety checks.
The non-TPACKET path (packet_snd()) already correctly copies vnet_hdr to a stack-local variable. All other vnet_hdr consumers in the kernel (tun.c, tap.c, virtio_net.c) also use stack copies. The TPACKET TX path is the only caller of virtio_net_hdr_to_skb() that reads directly from user-controlled shared memory.
Fix this by copying vnet_hdr from the mmap'd ring buffer to a stack-local variable before validation and use, consistent with the approach used in packet_snd() and all other callers.
net/packet/af_packet.c +13 -8
@@ -2718,7 +2718,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) {struct sk_buff *skb =NULL ;struct net_device *dev; -struct virtio_net_hdr *vnet_hdr =NULL ; +struct virtio_net_hdr vnet_hdr; +bool has_vnet_hdr = false;struct sockcm_cookie sockc;__be16 proto;int err, reserve =0 ;
@@ -2819,16 +2820,20 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) hlen =LL_RESERVED_SPACE (dev); tlen = dev->needed_tailroom;if (vnet_hdr_sz) { - vnet_hdr = data; data += vnet_hdr_sz; tp_len -= vnet_hdr_sz; -if (tp_len <0 || -__packet_snd_vnet_parse (vnet_hdr, tp_len)) { +if (tp_len <0 ) { + tp_len = -EINVAL ; + goto tpacket_error; + } +memcpy (&vnet_hdr, data - vnet_hdr_sz,sizeof (vnet_hdr)); +if (__packet_snd_vnet_parse (&vnet_hdr, tp_len)) { tp_len = -EINVAL ; goto tpacket_error; } copylen =__virtio16_to_cpu (vio_le (), - vnet_hdr->hdr_len); + vnet_hdr.hdr_len); + has_vnet_hdr = true; } copylen =max_t (int, copylen, dev->hard_header_len); skb = sock_alloc_send_skb(&po->sk,
@@ -2865,12 +2870,12 @@ tpacket_error: } } -if (vnet_hdr_sz) { -if (virtio_net_hdr_to_skb (skb, vnet_hdr,vio_le ())) { +if (has_vnet_hdr) { +if (virtio_net_hdr_to_skb (skb, &vnet_hdr,vio_le ())) { tp_len = -EINVAL ; goto tpacket_error; } -virtio_net_hdr_set_proto (skb, vnet_hdr); +virtio_net_hdr_set_proto (skb, &vnet_hdr); } skb->destructor = tpacket_destruct_skb;
Sasha Levin
maintainerPATCH 1/1 net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd()
From: Bingquan Chen <[email protected]>
[ Upstream commit 2c054e17d9d41f1020376806c7f750834ced4dc5 ]
In tpacket_snd(), when PACKET_VNET_HDR is enabled, vnet_hdr points directly into the mmap'd TX ring buffer shared with userspace. The kernel validates the header via __packet_snd_vnet_parse() but then re-reads all fields later in virtio_net_hdr_to_skb(). A concurrent userspace thread can modify the vnet_hdr fields between validation and use, bypassing all safety checks.
The non-TPACKET path (packet_snd()) already correctly copies vnet_hdr to a stack-local variable. All other vnet_hdr consumers in the kernel (tun.c, tap.c, virtio_net.c) also use stack copies. The TPACKET TX path is the only caller of virtio_net_hdr_to_skb() that reads directly from user-controlled shared memory.
Fix this by copying vnet_hdr from the mmap'd ring buffer to a stack-local variable before validation and use, consistent with the approach used in packet_snd() and all other callers.
--- net/packet/af_packet.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
net/packet/af_packet.c +15 -10
@@ -2729,7 +2729,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) {struct sk_buff *skb =NULL ;struct net_device *dev; -struct virtio_net_hdr *vnet_hdr =NULL ; +struct virtio_net_hdr vnet_hdr; +bool has_vnet_hdr = false;struct sockcm_cookie sockc;__be16 proto;int err, reserve =0 ;
@@ -2829,16 +2830,20 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) hlen =LL_RESERVED_SPACE (dev); tlen = dev->needed_tailroom;if (po->has_vnet_hdr) { - vnet_hdr = data; - data +=sizeof (*vnet_hdr); - tp_len -=sizeof (*vnet_hdr); -if (tp_len <0 || -__packet_snd_vnet_parse (vnet_hdr, tp_len)) { + data +=sizeof (vnet_hdr); + tp_len -=sizeof (vnet_hdr); +if (tp_len <0 ) { + tp_len = -EINVAL ; + goto tpacket_error; + } +memcpy (&vnet_hdr, data -sizeof (vnet_hdr),sizeof (vnet_hdr)); +if (__packet_snd_vnet_parse (&vnet_hdr, tp_len)) { tp_len = -EINVAL ; goto tpacket_error; } copylen =__virtio16_to_cpu (vio_le (), - vnet_hdr->hdr_len); + vnet_hdr.hdr_len); + has_vnet_hdr = true; } copylen =max_t (int, copylen, dev->hard_header_len); skb = sock_alloc_send_skb(&po->sk,
@@ -2875,12 +2880,12 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) } } -if (po->has_vnet_hdr) { -if (virtio_net_hdr_to_skb (skb, vnet_hdr,vio_le ())) { +if (has_vnet_hdr) { +if (virtio_net_hdr_to_skb (skb, &vnet_hdr,vio_le ())) { tp_len = -EINVAL ; goto tpacket_error; } -virtio_net_hdr_set_proto (skb, vnet_hdr); +virtio_net_hdr_set_proto (skb, &vnet_hdr); } skb->destructor = tpacket_destruct_skb;
Signature · 1 line
2.53.0