[PATCH net 1/2] net: packet: fix skb->protocol not updated after VLAN network header adjustment
[email protected] Wed, 5 Aug 2026 18:53:13 +0800
| Newsgroups | org.kernel.vger.bpf,dev.linux.lists.imx,org.kernel.vger.linux-kernel,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
From: Wei Fang <[email protected]> In packet_parse_headers(), when processing a VLAN-tagged frame on a SOCK_RAW AF_PACKET socket, skb_set_network_header() is called with the depth returned by vlan_get_protocol_and_depth() to advance network_header past the VLAN tag to the inner protocol header. However, skb->protocol was not updated to reflect the inner EtherType resolved by vlan_get_protocol_and_depth(), leaving it pointing to the outer VLAN EtherType (e.g. ETH_P_8021Q). This mismatch causes skb_probe_transport_header() to invoke the flow dissector with proto=ETH_P_8021Q but nhoff already pointing past the VLAN tag to the inner header. The dissector interprets the inner header bytes as a VLAN header, fails to find a recognizable encapsulated protocol, and returns false. Consequently, transport_header is never set and remains at its uninitialized sentinel value (~0U = 0xFFFF). Any subsequent code that calls skb_transport_header() or udp_hdr() on such an skb will dereference a pointer 65535 bytes past skb->head, potentially corrupting arbitrary kernel memory. Save the return value of vlan_get_protocol_and_depth(), which already resolves the inner EtherType, and assign it to skb->protocol after skb_set_network_header(). This keeps skb->protocol and network_header consistent when skb_probe_transport_header() is called, allowing the flow dissector to correctly identify the transport layer header. Fixes: dfed913e8b55 ("net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO") Assisted-by: WChat:claude-opus-4-8 Signed-off-by: Wei Fang <[email protected]> --- net/packet/af_packet.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 0e1355be89f6..a62d445047c0 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1945,9 +1945,15 @@ static void packet_parse_headers(struct sk_buff *skb, struct socket *sock) /* Move network header to the right position for VLAN tagged packets */ if (likely(skb->dev->type == ARPHRD_ETHER) && - eth_type_vlan(skb->protocol) && - vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0) - skb_set_network_header(skb, depth); + eth_type_vlan(skb->protocol)) { + __be16 proto = vlan_get_protocol_and_depth(skb, skb->protocol, + &depth); + + if (proto != 0) { + skb_set_network_header(skb, depth); + skb->protocol = proto; + } + } skb_probe_transport_header(skb); } -- 2.34.1