From: Zhiling Zou CAKE's ACK filter special-cases IPv4 packets carrying IPv6 to find TCP ACKs inside 6in4 tunnels. The parser checks the outer IPv4 protocol and the inner next-header field, but it does not verify that the inner header is actually IPv6. A malformed packet can therefore use an inner header with a non-IPv6 version while still setting the byte used as nexthdr to TCP. When two packets from the same queued flow reach cake_ack_filter(), the version dispatch can fall through to WARN_ON(1), which becomes a denial of service on kernels with panic_on_warn enabled. Reject 6in4 packets unless the encapsulated header has IPv6 version 6 in both IP and TCP header parsing helpers. Fixes: 8b7138814f29 ("sch_cake: Add optional ACK filter") Cc: stable@vger.kernel.org Reported-by: Vega Assisted-by: Codex:gpt-5.4 Signed-off-by: Zhiling Zou Signed-off-by: Ren Wei --- net/sched/sch_cake.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 505f63fecf640..7c4d92cdf514f 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -950,16 +950,19 @@ static struct iphdr *cake_get_iphdr(const struct sk_buff *skb, if (!iph) return NULL; - if (iph->version == 4 && iph->protocol == IPPROTO_IPV6) - return skb_header_pointer(skb, offset + iph->ihl * 4, - sizeof(struct ipv6hdr), buf); + if (iph->version == 4 && iph->protocol == IPPROTO_IPV6) { + iph = skb_header_pointer(skb, offset + iph->ihl * 4, + sizeof(struct ipv6hdr), buf); + if (!iph || iph->version != 6) + return NULL; - else if (iph->version == 4) return iph; - - else if (iph->version == 6) + } else if (iph->version == 4) { + return iph; + } else if (iph->version == 6) { return skb_header_pointer(skb, offset, sizeof(struct ipv6hdr), buf); + } return NULL; } @@ -990,7 +993,8 @@ static struct tcphdr *cake_get_tcphdr(const struct sk_buff *skb, ipv6h = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); - if (!ipv6h || ipv6h->nexthdr != IPPROTO_TCP) + if (!ipv6h || ipv6h->version != 6 || + ipv6h->nexthdr != IPPROTO_TCP) return NULL; offset += sizeof(struct ipv6hdr); -- 2.43.0