]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
tunnels: do not assume transport header in iptunnel_pmtud_check_icmp()
authorEric Dumazet <edumazet@google.com>
Fri, 22 May 2026 11:55:12 +0000 (11:55 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 27 May 2026 01:11:47 +0000 (18:11 -0700)
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: 4cb47a8644cc ("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>
net/ipv4/ip_tunnel_core.c

index c77a4c3fbe753ad6d86bf52e9cbdad89a4ae6f85..d3c677e9bff2080e4760347a3d873da4e83ac3ca 100644 (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);
 }