]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net/packet: reset the MAC header on the packet-socket transmit path
authorDoruk Tan Ozturk <doruk@0sec.ai>
Fri, 24 Jul 2026 14:40:15 +0000 (16:40 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 Jul 2026 23:29:07 +0000 (16:29 -0700)
packet_parse_headers() resets the MAC header only for a SOCK_RAW frame
whose socket did not bind a protocol. A protocol-bound SOCK_RAW socket,
any SOCK_DGRAM frame, and the legacy SOCK_PACKET path therefore leave
skb->mac_header unset here.

For frames sent via __dev_queue_xmit() this is harmless: it resets the
MAC header unconditionally. But the packet-socket PACKET_QDISC_BYPASS
path uses dev_direct_xmit(), which does not, so the frame reaches
ndo_start_xmit() with the MAC header unset. A driver that reads
eth_hdr(skb) on transmit then dereferences skb->head + (u16)~0, an
out-of-bounds access ~64 KiB past the head -- the same class fixed for
one consumer in commit f5089008f90c ("macsec: do not read an unset MAC
header in macsec_encrypt()").

packet_parse_headers() runs only on the transmit path, where skb->data
points at the start of the L2 header for every packet-socket type
regardless of its length: SOCK_RAW and SOCK_PACKET carry a user-supplied
header and SOCK_DGRAM has one built by dev_hard_header(). Reset the MAC
header unconditionally, mirroring __dev_queue_xmit(), so the frame is
anchored on the bypass path too.

Found by 0sec (https://0sec.ai) using automated source analysis;
verified against source and matched to the macsec KASAN report in
f5089008f90c. Compile-tested.

Fixes: 75c65772c3d1 ("net/packet: Ask driver for protocol if not provided by user")
Cc: stable@vger.kernel.org
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20260724144015.63219-1-doruk@0sec.ai
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/packet/af_packet.c

index e75d2932475ac04a77f12af840e6c1eb6503f547..5ae0511e89e32c2cad10c6275ba58f3348b60653 100644 (file)
@@ -1924,11 +1924,12 @@ static void packet_parse_headers(struct sk_buff *skb, struct socket *sock)
 {
        int depth;
 
+       /* On TX skb->data is the L2 header; anchor it for all socket types. */
+       skb_reset_mac_header(skb);
+
        if ((!skb->protocol || skb->protocol == htons(ETH_P_ALL)) &&
-           sock->type == SOCK_RAW) {
-               skb_reset_mac_header(skb);
+           sock->type == SOCK_RAW)
                skb->protocol = dev_parse_header_protocol(skb);
-       }
 
        /* Move network header to the right position for VLAN tagged packets */
        if (likely(skb->dev->type == ARPHRD_ETHER) &&