mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
ipvs: ensure inner headers in ICMP errors are in headroom
[ Upstream commit3f7a535ff0] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
accee8e53a
commit
9bc9b95aee
@@ -1585,6 +1585,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;
|
||||
@@ -1622,9 +1623,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;
|
||||
@@ -1640,9 +1642,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 */
|
||||
@@ -1654,7 +1656,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);
|
||||
@@ -1723,6 +1725,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;
|
||||
@@ -1739,6 +1742,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);
|
||||
@@ -1754,8 +1760,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
|
||||
@@ -1764,6 +1770,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