]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipvs: fix more places with wrong ipv6 transport offsets
authorJulian Anastasov <ja@ssi.bg>
Wed, 8 Jul 2026 18:03:15 +0000 (21:03 +0300)
committerFlorian Westphal <fw@strlen.de>
Fri, 10 Jul 2026 14:28:47 +0000 (16:28 +0200)
Sashiko reports for more incorrect IPv6 transport offsets.

The app code for TCP was assuming IPv4 network header
even after the ipvsh argument was provided. This can
cause problems with apps over IPv6. As for the only
official app in the kernel tree (FTP) this problem is
harmless because we use Netfilter to mangle the FTP
ports and we do not adjust the TCP seq numbers.

Also, provide correct offset of the ICMPV6 header in
ip_vs_out_icmp_v6() for correct checksum checks when
the IPv6 packet has extension headers.

Fixes: d12e12299a69 ("ipvs: add ipv6 support to ftp")
Fixes: 2a3b791e6e11 ("IPVS: Add/adjust Netfilter hook functions and helpers for v6")
Cc: stable@vger.kernel.org
Link: https://sashiko.dev/#/patchset/20260706101624.69471-1-zhaoyz24%40mails.tsinghua.edu.cn
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Florian Westphal <fw@strlen.de>
net/netfilter/ipvs/ip_vs_app.c
net/netfilter/ipvs/ip_vs_core.c

index d54d7da583346b81c71aeb380d13b57f85c8b384..b0e00be85cb12ce0257da0c6b2eb3cf2b922430f 100644 (file)
@@ -361,14 +361,13 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
                                  struct ip_vs_iphdr *ipvsh)
 {
        int diff;
-       const unsigned int tcp_offset = ip_hdrlen(skb);
        struct tcphdr *th;
        __u32 seq;
 
-       if (skb_ensure_writable(skb, tcp_offset + sizeof(*th)))
+       if (skb_ensure_writable(skb, ipvsh->len + sizeof(*th)))
                return 0;
 
-       th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
+       th = (struct tcphdr *)(skb_network_header(skb) + ipvsh->len);
 
        /*
         *      Remember seq number in case this pkt gets resized
@@ -438,14 +437,13 @@ static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb,
                                 struct ip_vs_iphdr *ipvsh)
 {
        int diff;
-       const unsigned int tcp_offset = ip_hdrlen(skb);
        struct tcphdr *th;
        __u32 seq;
 
-       if (skb_ensure_writable(skb, tcp_offset + sizeof(*th)))
+       if (skb_ensure_writable(skb, ipvsh->len + sizeof(*th)))
                return 0;
 
-       th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
+       th = (struct tcphdr *)(skb_network_header(skb) + ipvsh->len);
 
        /*
         *      Remember seq number in case this pkt gets resized
index 35cbe821c2596702c4a2e43852736d2385b247b8..bafab93451d037c7f9b3316cd4517cfb3c2ea9c9 100644 (file)
@@ -1219,8 +1219,7 @@ static int ip_vs_out_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
        snet.in6 = ciph.saddr.in6;
        offset = ciph.len;
        return handle_response_icmp(AF_INET6, skb, &snet, ciph.protocol, cp,
-                                   pp, offset, sizeof(struct ipv6hdr),
-                                   hooknum);
+                                   pp, offset, ipvsh->len, hooknum);
 }
 #endif