Skip to content

Commit dd22f74

Browse files
Julian Anastasovgregkh
authored andcommitted
ipvs: ensure inner headers in ICMP errors are in headroom
[ Upstream commit 3f7a535 ] Sashiko points out that after stripping the outer headers with pskb_pull() we should ensure the inner IP headers in ICMP errors from tunnels are present in the skb headroom for functions like ipv4_update_pmtu(), icmp_send() and IP_VS_DBG(). Also, add more checks for the length of the inner headers. Fixes: f2edb9f ("ipvs: implement passive PMTUD for IPIP packets") Link: https://sashiko.dev/#/patchset/20260702073430.67680-1-zhaoyz24%40mails.tsinghua.edu.cn Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e774e6a commit dd22f74

1 file changed

Lines changed: 15 additions & 6 deletions

File tree

net/netfilter/ipvs/ip_vs_core.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
15941594
bool tunnel, new_cp = false;
15951595
union nf_inet_addr *raddr;
15961596
char *outer_proto = "IPIP";
1597+
unsigned int hlen_ipip;
15971598
int ulen = 0;
15981599

15991600
*related = 1;
@@ -1631,9 +1632,10 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
16311632
/* Now find the contained IP header */
16321633
offset += sizeof(_icmph);
16331634
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
1634-
if (cih == NULL)
1635+
if (!(cih && cih->version == 4 && cih->ihl >= 5))
16351636
return NF_ACCEPT; /* The packet looks wrong, ignore */
16361637
raddr = (union nf_inet_addr *)&cih->daddr;
1638+
hlen_ipip = cih->ihl * 4;
16371639

16381640
/* Special case for errors for IPIP/UDP/GRE tunnel packets */
16391641
tunnel = false;
@@ -1649,9 +1651,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
16491651
/* Only for known tunnel */
16501652
if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
16511653
return NF_ACCEPT;
1652-
offset += cih->ihl * 4;
1654+
offset += hlen_ipip;
16531655
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
1654-
if (cih == NULL)
1656+
if (!(cih && cih->version == 4 && cih->ihl >= 5))
16551657
return NF_ACCEPT; /* The packet looks wrong, ignore */
16561658
tunnel = true;
16571659
} else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
@@ -1663,7 +1665,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
16631665
/* Non-first fragment has no UDP/GRE header */
16641666
if (unlikely(cih->frag_off & htons(IP_OFFSET)))
16651667
return NF_ACCEPT;
1666-
offset2 = offset + cih->ihl * 4;
1668+
offset2 = offset + hlen_ipip;
16671669
if (cih->protocol == IPPROTO_UDP) {
16681670
ulen = ipvs_udp_decap(ipvs, skb, offset2, AF_INET,
16691671
raddr, &iproto);
@@ -1732,6 +1734,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
17321734
}
17331735

17341736
if (tunnel) {
1737+
unsigned int hlen_orig = cih->ihl * 4;
17351738
__be32 info = ic->un.gateway;
17361739
__u8 type = ic->type;
17371740
__u8 code = ic->code;
@@ -1748,6 +1751,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
17481751
goto ignore_tunnel;
17491752
offset2 -= ihl + sizeof(_icmph);
17501753
skb_reset_network_header(skb);
1754+
/* Ensure the IP header is present in headroom */
1755+
if (!pskb_may_pull(skb, hlen_ipip))
1756+
goto ignore_tunnel;
17511757
IP_VS_DBG(12, "ICMP for %s %pI4->%pI4: mtu=%u\n",
17521758
outer_proto, &ip_hdr(skb)->saddr,
17531759
&ip_hdr(skb)->daddr, mtu);
@@ -1763,8 +1769,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
17631769
if (dest_dst)
17641770
mtu = dst_mtu(dest_dst->dst_cache);
17651771
}
1766-
if (mtu > 68 + sizeof(struct iphdr) + ulen)
1767-
mtu -= sizeof(struct iphdr) + ulen;
1772+
if (mtu > 68 + hlen_ipip + ulen)
1773+
mtu -= hlen_ipip + ulen;
17681774
info = htonl(mtu);
17691775
}
17701776
/* Strip outer IP, ICMP and IPIP/UDP/GRE, go to IP header of
@@ -1773,6 +1779,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
17731779
if (pskb_pull(skb, offset2) == NULL)
17741780
goto ignore_tunnel;
17751781
skb_reset_network_header(skb);
1782+
/* Ensure the IP header is present in headroom */
1783+
if (!pskb_may_pull(skb, hlen_orig))
1784+
goto ignore_tunnel;
17761785
IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n",
17771786
&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
17781787
type, code, ntohl(info));

0 commit comments

Comments
 (0)