tunnels: do not assume transport header in iptunnel_pmtud_check_icmp()

In some cases, iptunnel_pmtud_check_icmp() can be called while
skb transport header is not set.

This triggers an out-of-bound access, because
(typeof(skb->transport_header))~0U is 65535.

Access the icmp header based on IPv4 network header,
after making sure icmp->type is present in skb linear part.

Note that iptunnel_pmtud_check_icmpv6()) is fine.

Fixes: 4cb47a8644 ("tunnels: PMTU discovery support for directly bridged IP packets")
Reported-by: Damiano Melotti <melotti@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260522115512.1519110-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2026-05-22 11:55:12 +00:00 committed by Jakub Kicinski
parent 7d9ef0cb27
commit 509323077e

View File

@ -280,7 +280,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu)
*/
static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu)
{
const struct icmphdr *icmph = icmp_hdr(skb);
const struct iphdr *iph = ip_hdr(skb);
if (mtu < 576 || iph->frag_off != htons(IP_DF))
@ -291,9 +290,17 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu)
ipv4_is_lbcast(iph->saddr) || ipv4_is_multicast(iph->saddr))
return 0;
if (iph->protocol == IPPROTO_ICMP && icmp_is_err(icmph->type))
return 0;
if (iph->protocol == IPPROTO_ICMP) {
const struct icmphdr *icmph;
if (!pskb_network_may_pull(skb, iph->ihl * 4 +
offsetofend(struct icmphdr, type)))
return 0;
iph = ip_hdr(skb);
icmph = (void *)iph + iph->ihl * 4;
if (icmp_is_err(icmph->type))
return 0;
}
return iptunnel_pmtud_build_icmp(skb, mtu);
}