]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
tunnels: load network headers after skb_cow() in iptunnel_pmtud_build_icmp[v6]()
authorEric Dumazet <edumazet@google.com>
Mon, 25 May 2026 20:13:35 +0000 (20:13 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 27 May 2026 01:10:25 +0000 (18:10 -0700)
Sashiko found that iptunnel_pmtud_build_icmp() and
iptunnel_pmtud_build_icmpv6() were caching ip_hdr() and ipv6_hdr()
before an skb_cow() call which can reallocate skb->head.

Fix this possible UAF by initializing the local variables
after the skb_cow() call.

Remove skb_reset_network_header() calls which were not needed.

Fixes: 4cb47a8644cc ("tunnels: PMTU discovery support for directly bridged IP packets")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/ip_tunnel_core.c

index 2667f53482bdaf1e693907fc527063d0ddd45580..c77a4c3fbe753ad6d86bf52e9cbdad89a4ae6f85 100644 (file)
@@ -212,7 +212,7 @@ EXPORT_SYMBOL_GPL(iptunnel_handle_offloads);
  */
 static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu)
 {
-       const struct iphdr *iph = ip_hdr(skb);
+       const struct iphdr *iph;
        struct icmphdr *icmph;
        struct iphdr *niph;
        struct ethhdr eh;
@@ -226,7 +226,6 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu)
 
        skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
        pskb_pull(skb, ETH_HLEN);
-       skb_reset_network_header(skb);
 
        err = pskb_trim(skb, 576 - sizeof(*niph) - sizeof(*icmph));
        if (err)
@@ -236,7 +235,7 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu)
        err = skb_cow(skb, sizeof(*niph) + sizeof(*icmph) + ETH_HLEN);
        if (err)
                return err;
-
+       iph = ip_hdr(skb);
        icmph = skb_push(skb, sizeof(*icmph));
        *icmph = (struct icmphdr) {
                .type                   = ICMP_DEST_UNREACH,
@@ -308,7 +307,7 @@ static int iptunnel_pmtud_check_icmp(struct sk_buff *skb, int mtu)
  */
 static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu)
 {
-       const struct ipv6hdr *ip6h = ipv6_hdr(skb);
+       const struct ipv6hdr *ip6h;
        struct icmp6hdr *icmp6h;
        struct ipv6hdr *nip6h;
        struct ethhdr eh;
@@ -323,7 +322,6 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu)
 
        skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
        pskb_pull(skb, ETH_HLEN);
-       skb_reset_network_header(skb);
 
        err = pskb_trim(skb, IPV6_MIN_MTU - sizeof(*nip6h) - sizeof(*icmp6h));
        if (err)
@@ -334,6 +332,7 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu)
        if (err)
                return err;
 
+       ip6h = ipv6_hdr(skb);
        icmp6h = skb_push(skb, sizeof(*icmp6h));
        *icmp6h = (struct icmp6hdr) {
                .icmp6_type             = ICMPV6_PKT_TOOBIG,