All of lore.kernel.org
 help / color / mirror / Atom feed
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: Zero Mark <patzilla007@gmail.com>,
	 Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Cc: security@kernel.org,  "David S . Miller" <davem@davemloft.net>,
	 Jakub Kicinski <kuba@kernel.org>,
	 Eric Dumazet <edumazet@google.com>,
	 netdev@vger.kernel.org,  Zero Mark <patzilla007@gmail.com>
Subject: Re: [PATCH] net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd()
Date: Fri, 17 Apr 2026 04:15:52 -0400	[thread overview]
Message-ID: <willemdebruijn.kernel.1683671b10e8@gmail.com> (raw)
In-Reply-To: <20260417060714.35488-1-patzilla007@gmail.com>

Zero Mark wrote:
> 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 (gso_type, gso_size,
> flags, csum_start, csum_offset) between validation and use, bypassing
> all safety checks.
> 
> This can lead to:
>  - Out-of-bounds checksum writes via crafted csum_start/csum_offset
>  - Malicious GSO segmentation parameters
>  - Kernel memory corruption and potential local privilege escalation
> 
> 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.
> 
> Exploitation requires CAP_NET_RAW, which can be obtained without
> special privileges via user namespaces.
> 
> Confirmed with a PoC on Linux 6.8.0 (Ubuntu): kprobe tracing on
> skb_partial_csum_set captured 77 race wins in 500,000 iterations.

No need to add such details on exploitability of bugs.

> Affects all kernels since PACKET_VNET_HDR support was added to the
> TPACKET TX path (~v3.14).
> 
> Fixes: 9ed988e5 ("packet: add vnet_hdr support for tpacket_snd")

This patch does not exist. Also 12-char SHA1.

I think this should be

Fixes: 1d036d25e560 ("packet: tpacket_snd gso and checksum offload")

> Signed-off-by: Zero Mark <patzilla007@gmail.com>

Thanks for the fix!

Only it does not apply cleanly. Please mark fixes [PATCH net] and
ensure that they apply to current netdev-net/main

https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html

> ---
>  net/packet/af_packet.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index abcdef012345..fedcba654321 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -2725,7 +2725,8 @@ static int tpacket_parse_header(struct packet_sock *po, void *frame,
>  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;
> @@ -2828,16 +2829,17 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
>  		if (po->has_vnet_hdr) {
> -			vnet_hdr = data;
> -			data += sizeof(*vnet_hdr);
> -			tp_len -= sizeof(*vnet_hdr);
> +			memcpy(&vnet_hdr, data, sizeof(vnet_hdr));

Move the tp_len < 0 check before memcpy

> +			data += sizeof(vnet_hdr);
> +			tp_len -= sizeof(vnet_hdr);
>  			if (tp_len < 0 ||
> -			    __packet_snd_vnet_parse(vnet_hdr, tp_len)) {
> +			    __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,11 +2877,11 @@ 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;
> --
> 2.43.0
> 



  reply	other threads:[~2026-04-17  8:15 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CAHOBGNBvZOXGzzMDuHWw1RrRvbg4TZVH34jVDhc1nkHbW_URXA@mail.gmail.com>
2026-04-17  6:07 ` [PATCH] net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd() Zero Mark
2026-04-17  8:15   ` Willem de Bruijn [this message]
2026-04-17 13:36     ` [PATCH net] " Zero Mark
2026-04-17 20:01       ` Willem de Bruijn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=willemdebruijn.kernel.1683671b10e8@gmail.com \
    --to=willemdebruijn.kernel@gmail.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=patzilla007@gmail.com \
    --cc=security@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.