For GUE version 0, gue_gro_receive() compares the base GUE header and its optional fields with every held packet. For GUE version 1 (direct IP encapsulation), it skips this comparison and selects the next GRO handler only from the IP version of the incoming packet. A held version 0 GUE packet from the same outer flow therefore stays eligible. For example, a GUE/IPv4/UDP packet can be aggregated with a direct IPv4/TCP packet, and inet_gro_receive() then parses the held packet's GUE header as an IPv4 header. Clear same_flow for held packets whose first nibble does not match the incoming IP version. A valid version 0 GUE header always has a first nibble between 0 and 3, so this also separates the two GUE formats. The reverse case is already handled: the version 0 path compares the whole base GUE header, including the version bits. Fixes: c1e48af7960e ("gue: Implement direction IP encapsulation") Reported-by: Kyle Zeng Signed-off-by: Eric Dumazet --- This issue was discovered by an AI code review agent. It has not been triggered, and the fix was only compile-tested. net/ipv4/fou_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c index 076fdca44f518016e71ba0b3b68c45b3c0858663..5c3c8f55d0570424203e2b664a7b806c51d86dbf 100644 --- a/net/ipv4/fou_core.c +++ b/net/ipv4/fou_core.c @@ -364,6 +364,18 @@ static struct sk_buff *gue_gro_receive(struct sock *sk, default: goto out; } + + /* Match the encapsulation format and IP version. */ + list_for_each_entry(p, head, list) { + const struct iphdr *iph2; + + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + iph2 = (const struct iphdr *)(p->data + off); + if (iph2->version != ((struct iphdr *)guehdr)->version) + NAPI_GRO_CB(p)->same_flow = 0; + } goto next_proto; default: goto out; -- 2.53.0