]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net/sched: cls_flow: Dont expose folded kernel pointers
authorJamal Hadi Salim <jhs@mojatatu.com>
Wed, 10 Jun 2026 10:18:39 +0000 (06:18 -0400)
committerJakub Kicinski <kuba@kernel.org>
Thu, 11 Jun 2026 22:04:56 +0000 (15:04 -0700)
The flow classifier falls back to addr_fold() for fields that are missing
from packet headers. In map mode, userspace controls mask, xor, rshift,
addend and divisor, and can observe the resulting classid through class
statistics. This allows a tc classifier in a user/network namespace to
recover the 32-bit folded value of skb->sk, skb_dst() or skb_nfct().

Align with standard kernel practices for pointer hashing and replace the
XOR folding with a keyed siphash (which is cryptographically secure)

Fixes: e5dfb815181f ("[NET_SCHED]: Add flow classifier")
Reported-by: Kyle Zeng <kylebot@openai.com>
Tested-by: Kyle Zeng <kylebot@openai.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260610101839.14135-1-jhs@mojatatu.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/sched/cls_flow.c

index ab364e4e468624b1228564a44c058d4528ff4156..356c68ebc3895a850e30a8db7f4dabc9bda173e2 100644 (file)
@@ -21,6 +21,7 @@
 #include <net/inet_sock.h>
 
 #include <net/pkt_cls.h>
+#include <linux/siphash.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/flow_dissector.h>
@@ -57,11 +58,15 @@ struct flow_filter {
        struct rcu_work         rwork;
 };
 
+static siphash_aligned_key_t flow_keys_secret __read_mostly;
+
 static inline u32 addr_fold(void *addr)
 {
-       unsigned long a = (unsigned long)addr;
-
-       return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
+#ifdef CONFIG_64BIT
+       return (u32)siphash_1u64((u64)addr, &flow_keys_secret);
+#else
+       return (u32)siphash_1u32((u32)addr, &flow_keys_secret);
+#endif
 }
 
 static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow)
@@ -596,6 +601,7 @@ static int flow_init(struct tcf_proto *tp)
                return -ENOBUFS;
        INIT_LIST_HEAD(&head->filters);
        rcu_assign_pointer(tp->root, head);
+       net_get_random_once(&flow_keys_secret, sizeof(flow_keys_secret));
        return 0;
 }