All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf v2] netfilter: ipset: don't mask the element in place in mtype_test_cidrs()
@ 2026-10-18  5:23 Tamaki Yanagawa
  2026-10-18 11:45 ` Florian Westphal
  0 siblings, 1 reply; 2+ messages in thread
From: Tamaki Yanagawa @ 2026-10-18  5:23 UTC (permalink / raw)
  To: netfilter-devel; +Cc: pablo, fw, phil, coreteam, linux-kernel, ty

mtype_test_cidrs() masks the element under test in place with
mtype_data_netmask() while walking the cidr array from the most to the
least specific prefix. Since the walk is restarted on concurrent cidr
array updates, the IPSET_NET_COUNT == 1 types (hash:net, hash:net,port,
hash:ip,port,net, hash:net,iface) rescan with an element already masked
to the widest prefix tried, so a lookup can wrongly match a more specific
entry at the network base address (e.g. 10.200.3.4 matching 10.0.0.0/29).
Work on a local copy of the element that is reinitialised on every scan
instead.

Fixes: e80456d79ec8 ("netfilter: ipset: remove need to allocate memory on delete operations")
Suggested-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Tamaki Yanagawa <ty@000ty.net>
Assisted-by: Claude:claude-opus-5-5
---
v2: work on a local copy of the element instead of restoring it before
    rescanning (Florian Westphal)
v1: https://lore.kernel.org/netfilter-devel/20261018035205.1008-1-ty@000ty.net/

 net/netfilter/ipset/ip_set_hash_gen.h        | 18 +++++++++---------
 net/netfilter/ipset/ip_set_hash_netnet.c     |  4 ++--
 net/netfilter/ipset/ip_set_hash_netportnet.c |  4 ++--
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 80ca523f30..e0d970a25e 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -1298,18 +1298,17 @@ mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,
  * sizes added to the set
  */
 static int
-mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
+mtype_test_cidrs(struct ip_set *set, const struct mtype_elem *orig,
 		 const struct ip_set_ext *ext,
 		 struct ip_set_ext *mext, u32 flags)
 {
 	struct htype *h = set->data;
 	struct htable *t = rcu_dereference_bh(h->table);
 	struct net_prefixes *nets0;
+	struct mtype_elem *data, d;
 	struct hbucket *n;
-	struct mtype_elem *data;
 #if IPSET_NET_COUNT == 2
 	struct net_prefixes *nets1;
-	struct mtype_elem orig = *d;
 	unsigned int seq1;
 	int ret, i, j, k;
 #else
@@ -1322,6 +1321,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
 	pr_debug("test by nets\n");
 	rcu_read_lock_bh();
 retry:
+	d = *orig;
 	multi = 0;
 	nets0 = rcu_dereference_bh(h->rnets[0]);
 	seq0 = read_seqcount_begin(&nets0->seq);
@@ -1335,18 +1335,18 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
 		if (!p0.count)
 			continue;
 #if IPSET_NET_COUNT == 2
-		mtype_data_reset_elem(d, &orig);
-		mtype_data_netmask(d, p0.cidr, false);
+		mtype_data_reset_elem(&d, orig);
+		mtype_data_netmask(&d, p0.cidr, false);
 		for (k = 0; k < nets1->len && !multi; k++) {
 			struct net_prefix p1 = READ_ONCE(nets1->nets[k]);
 
 			if (!p1.count)
 				continue;
-			mtype_data_netmask(d, p1.cidr, true);
+			mtype_data_netmask(&d, p1.cidr, true);
 #else
-		mtype_data_netmask(d, p0.cidr);
+		mtype_data_netmask(&d, p0.cidr);
 #endif
-		key = HKEY(d, h->initval, t->htable_bits);
+		key = HKEY(&d, h->initval, t->htable_bits);
 		n = rcu_dereference_bh(hbucket(t, key));
 		if (!n)
 			continue;
@@ -1355,7 +1355,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
 			if (!test_bit_acquire(i, n->used))
 				continue;
 			data = ahash_data(n, i, set->dsize);
-			if (!mtype_data_equal(data, d, &multi))
+			if (!mtype_data_equal(data, &d, &multi))
 				continue;
 			ret = mtype_data_match(data, ext, mext, set, flags);
 			if (ret != 0)
diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c
index f7c8a1cc30..522ec51374 100644
--- a/net/netfilter/ipset/ip_set_hash_netnet.c
+++ b/net/netfilter/ipset/ip_set_hash_netnet.c
@@ -85,7 +85,7 @@ hash_netnet4_data_reset_flags(struct hash_netnet4_elem *elem, u8 *flags)
 
 static void
 hash_netnet4_data_reset_elem(struct hash_netnet4_elem *elem,
-			     struct hash_netnet4_elem *orig)
+			     const struct hash_netnet4_elem *orig)
 {
 	elem->ip[1] = orig->ip[1];
 }
@@ -323,7 +323,7 @@ hash_netnet6_data_reset_flags(struct hash_netnet6_elem *elem, u8 *flags)
 
 static void
 hash_netnet6_data_reset_elem(struct hash_netnet6_elem *elem,
-			     struct hash_netnet6_elem *orig)
+			     const struct hash_netnet6_elem *orig)
 {
 	elem->ip[1] = orig->ip[1];
 }
diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c
index 61af1ce271..a170b5dd89 100644
--- a/net/netfilter/ipset/ip_set_hash_netportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_netportnet.c
@@ -88,7 +88,7 @@ hash_netportnet4_data_reset_flags(struct hash_netportnet4_elem *elem, u8 *flags)
 
 static void
 hash_netportnet4_data_reset_elem(struct hash_netportnet4_elem *elem,
-				 struct hash_netportnet4_elem *orig)
+				 const struct hash_netportnet4_elem *orig)
 {
 	elem->ip[1] = orig->ip[1];
 }
@@ -382,7 +382,7 @@ hash_netportnet6_data_reset_flags(struct hash_netportnet6_elem *elem, u8 *flags)
 
 static void
 hash_netportnet6_data_reset_elem(struct hash_netportnet6_elem *elem,
-				 struct hash_netportnet6_elem *orig)
+				 const struct hash_netportnet6_elem *orig)
 {
 	elem->ip[1] = orig->ip[1];
 }

base-commit: ab699d296e066eb64f51d2a8a1d42237a3b186c8
-- 
2.52.0.windows.1



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-18 11:45 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-18  5:23 [PATCH nf v2] netfilter: ipset: don't mask the element in place in mtype_test_cidrs() Tamaki Yanagawa
2026-10-18 11:45 ` Florian Westphal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.