]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
authorEric Dumazet <edumazet@google.com>
Thu, 26 Mar 2026 20:26:08 +0000 (20:26 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 28 Mar 2026 03:22:46 +0000 (20:22 -0700)
Sashiko AI-review observed:

  In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
  where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
  and passed to icmp6_send(), it uses IP6CB(skb2).

  IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
  offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
  at offset 18.

  If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
  would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
  and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).

  This would scan the inner, attacker-controlled IPv6 packet starting at that
  offset, potentially returning a fake TLV without checking if the remaining
  packet length can hold the full 18-byte struct ipv6_destopt_hao.

  Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
  of the packet data into skb_shared_info?

  Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
  ip6ip6_err() to prevent this?

This patch implements the first suggestion.

I am not sure if ip6ip6_err() needs to be changed.
A separate patch would be better anyway.

Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
Reported-by: Ido Schimmel <idosch@nvidia.com>
Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Oskar Kjos <oskar.kjos@hotmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv6/icmp.c

index 813d2e9edb8bed7c1649e279cea9229806af4132..d5d23a9296eac86a4a7ae8ea0240314653170035 100644 (file)
@@ -875,6 +875,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
        if (!skb2)
                return 1;
 
+       /* Remove debris left by IPv4 stack. */
+       memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
+
        skb_dst_drop(skb2);
        skb_pull(skb2, nhs);
        skb_reset_network_header(skb2);