Commit b4bc9435 authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski
Browse files

tunnels: load network headers after skb_cow() in iptunnel_pmtud_build_icmp[v6]()



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: 4cb47a86 ("tunnels: PMTU discovery support for directly bridged IP packets")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarStefano Brivio <sbrivio@redhat.com>
Link: https://patch.msgid.link/20260525201335.2361845-1-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent d895767c
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -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,