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
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.