]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipvs: return the csum validation for forward hook
authorJulian Anastasov <ja@ssi.bg>
Thu, 30 Jul 2026 18:35:06 +0000 (21:35 +0300)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 31 Jul 2026 13:58:30 +0000 (15:58 +0200)
Sashiko notes that playing games with the skb dst and rt
flags instead of providing hooknum is not a good idea
when validating the checksums.

Also, skipping checksum validation for FORWARD packets
risk silent data corruption, even if the only user is
the FTP-CMD packets coming from the real server.

Sashiko also noticed that by using common checksum
helper in the previous commit we actually fixed old bug
where the TCP/UDP checksum for IPv6 on CHECKSUM_COMPLETE
was not validated correctly.

Fixes: e876b75b9020 ("ipvs: fix the checksum validations")
Link: https://sashiko.dev/#/patchset/20260722211420.153933-1-pablo%40netfilter.org
Link: https://sashiko.dev/#/patchset/20260727185024.67534-1-ja%40ssi.bg
Link: https://sashiko.dev/#/patchset/20260728202520.59179-1-ja%40ssi.bg
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/ip_vs.h
net/netfilter/ipvs/ip_vs_proto_sctp.c

index 1235f1934e94660b66e1210f1193dfebd10464d6..d2813eb795be216be51d3372bdaa00780381831e 100644 (file)
@@ -25,9 +25,7 @@
 #include <linux/netfilter.h>           /* for union nf_inet_addr */
 #include <linux/ip.h>
 #include <linux/ipv6.h>                        /* for struct ipv6hdr */
-#include <net/route.h>
 #include <net/ipv6.h>
-#include <net/ip6_fib.h>
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
 #include <net/netfilter/nf_conntrack.h>
 #endif
@@ -2095,30 +2093,23 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
        return csum_partial(diff, sizeof(diff), oldsum);
 }
 
-static inline bool ip_vs_checksum_needed(struct sk_buff *skb, int af)
+static inline bool ip_vs_checksum_needed(struct sk_buff *skb)
 {
        /* Checksum unnecessary or already validated? */
        if (skb_csum_unnecessary(skb))
                return false;
-       /* LOCAL_OUT ? */
-       if (!skb->dev || skb->dev->flags & IFF_LOOPBACK)
+       /* Locally generated ? */
+       if (!skb->dev)
                return false;
-       /* !LOCAL_IN (FORWARD) ? */
-       if (af == AF_INET6) {
-               if (!(dst_rt6_info(skb_dst(skb))->rt6i_flags & RTF_LOCAL))
-                       return false;
-       } else {
-               if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
-                       return false;
-       }
        return true;
 }
 
 static inline bool ip_vs_checksum_common_check(struct sk_buff *skb,
                                               int offset, int proto, int af)
 {
-       if (!ip_vs_checksum_needed(skb, af))
+       if (!ip_vs_checksum_needed(skb))
                return true;
+       /* Validate csum even for FORWARD */
        return !nf_checksum(skb, NF_INET_LOCAL_IN, offset, proto, af);
 }
 
index 3dbd3096e1637ba568798ae542edd823670670d7..c80567c73469bb6f236438749566001f5eeb60d5 100644 (file)
@@ -193,7 +193,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
        struct sctphdr *sh;
        __le32 cmp, val;
 
-       if (!ip_vs_checksum_needed(skb, af))
+       if (!ip_vs_checksum_needed(skb))
                return 1;
        sh = (struct sctphdr *)(skb->data + sctphoff);
        cmp = sh->checksum;