mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
ipvs: ensure inner headers in ICMP errors are in headroom
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: f2edb9f770 ("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>
This commit is contained in:
committed by
Florian Westphal
parent
2f75c0faa3
commit
3f7a535ff0
@@ -1767,6 +1767,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
bool tunnel, new_cp = false;
|
||||
union nf_inet_addr *raddr;
|
||||
char *outer_proto = "IPIP";
|
||||
unsigned int hlen_ipip;
|
||||
int ulen = 0;
|
||||
|
||||
*related = 1;
|
||||
@@ -1804,9 +1805,10 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
/* Now find the contained IP header */
|
||||
offset += sizeof(_icmph);
|
||||
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
|
||||
if (cih == NULL)
|
||||
if (!(cih && cih->version == 4 && cih->ihl >= 5))
|
||||
return NF_ACCEPT; /* The packet looks wrong, ignore */
|
||||
raddr = (union nf_inet_addr *)&cih->daddr;
|
||||
hlen_ipip = cih->ihl * 4;
|
||||
|
||||
/* Special case for errors for IPIP/UDP/GRE tunnel packets */
|
||||
tunnel = false;
|
||||
@@ -1822,9 +1824,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
/* Only for known tunnel */
|
||||
if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
|
||||
return NF_ACCEPT;
|
||||
offset += cih->ihl * 4;
|
||||
offset += hlen_ipip;
|
||||
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
|
||||
if (cih == NULL)
|
||||
if (!(cih && cih->version == 4 && cih->ihl >= 5))
|
||||
return NF_ACCEPT; /* The packet looks wrong, ignore */
|
||||
tunnel = true;
|
||||
} else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
|
||||
@@ -1836,7 +1838,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
/* Non-first fragment has no UDP/GRE header */
|
||||
if (unlikely(cih->frag_off & htons(IP_OFFSET)))
|
||||
return NF_ACCEPT;
|
||||
offset2 = offset + cih->ihl * 4;
|
||||
offset2 = offset + hlen_ipip;
|
||||
if (cih->protocol == IPPROTO_UDP) {
|
||||
ulen = ipvs_udp_decap(ipvs, skb, offset2, AF_INET,
|
||||
raddr, &iproto);
|
||||
@@ -1905,6 +1907,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
}
|
||||
|
||||
if (tunnel) {
|
||||
unsigned int hlen_orig = cih->ihl * 4;
|
||||
__be32 info = ic->un.gateway;
|
||||
__u8 type = ic->type;
|
||||
__u8 code = ic->code;
|
||||
@@ -1921,6 +1924,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
goto ignore_tunnel;
|
||||
offset2 -= ihl + sizeof(_icmph);
|
||||
skb_reset_network_header(skb);
|
||||
/* Ensure the IP header is present in headroom */
|
||||
if (!pskb_may_pull(skb, hlen_ipip))
|
||||
goto ignore_tunnel;
|
||||
IP_VS_DBG(12, "ICMP for %s %pI4->%pI4: mtu=%u\n",
|
||||
outer_proto, &ip_hdr(skb)->saddr,
|
||||
&ip_hdr(skb)->daddr, mtu);
|
||||
@@ -1936,8 +1942,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
if (dest_dst)
|
||||
mtu = dst_mtu(dest_dst->dst_cache);
|
||||
}
|
||||
if (mtu > 68 + sizeof(struct iphdr) + ulen)
|
||||
mtu -= sizeof(struct iphdr) + ulen;
|
||||
if (mtu > 68 + hlen_ipip + ulen)
|
||||
mtu -= hlen_ipip + ulen;
|
||||
info = htonl(mtu);
|
||||
}
|
||||
/* Strip outer IP, ICMP and IPIP/UDP/GRE, go to IP header of
|
||||
@@ -1946,6 +1952,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
|
||||
if (pskb_pull(skb, offset2) == NULL)
|
||||
goto ignore_tunnel;
|
||||
skb_reset_network_header(skb);
|
||||
/* Ensure the IP header is present in headroom */
|
||||
if (!pskb_may_pull(skb, hlen_orig))
|
||||
goto ignore_tunnel;
|
||||
IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n",
|
||||
&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
|
||||
type, code, ntohl(info));
|
||||
|
||||
Reference in New Issue
Block a user