diff mbox

netfilter: ipset: Reset flags on private copy on set resize

Message ID 235247e6d667917b56d974d1ece91abe4548636b.1426509747.git.popovich_sergei@mail.ua
State Not Applicable
Delegated to: Jozsef Kadlecsik
Headers show

Commit Message

Sergey Popovich March 16, 2015, 1:40 p.m. UTC
Set resizing takes read lock on the hash table, so we should
not modify any data in the original hash table, as this would
disrupt concurrent readers.

Furthermore set resizing could fail, leaving original set data
in inconsistent state: flags (nomatch currently) would be
cleared on all, but the last, where reallocation fails, set
elements.

Fix this by taking private copy of original set entry for
sets, where it is necessary.

Signed-off-by: Sergey Popovich <popovich_sergei@mail.ua>
---
 net/netfilter/ipset/ip_set_hash_gen.h |   16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)
diff mbox

Patch

diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 7122cd8..fcf75be 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -541,8 +541,9 @@  mtype_resize(struct ip_set *set, bool retried)
 	u8 htable_bits = orig->htable_bits;
 #ifdef IP_SET_HASH_WITH_NETS
 	u8 flags;
+	u8 _data[set->dsize];
 #endif
-	struct mtype_elem *data;
+	struct mtype_elem *data, *hdata;
 	struct mtype_elem *d;
 	struct hbucket *n, *m;
 	u32 i, j;
@@ -581,15 +582,15 @@  retry:
 		for (j = 0; j < n->pos; j++) {
 			data = ahash_data(n, j, set->dsize);
 #ifdef IP_SET_HASH_WITH_NETS
+			hdata = memcpy(_data, data, set->dsize);
 			flags = 0;
-			mtype_data_reset_flags(data, &flags);
+			mtype_data_reset_flags(hdata, &flags);
+#else
+			hdata = data;
 #endif
-			m = hbucket(t, HKEY(data, h->initval, htable_bits));
+			m = hbucket(t, HKEY(hdata, h->initval, htable_bits));
 			ret = hbucket_elem_add(m, AHASH_MAX(h), set->dsize);
 			if (ret < 0) {
-#ifdef IP_SET_HASH_WITH_NETS
-				mtype_data_reset_flags(data, &flags);
-#endif
 				read_unlock_bh(&set->lock);
 				mtype_ahash_destroy(set, t, false);
 				if (ret == -EAGAIN)
@@ -598,9 +599,6 @@  retry:
 			}
 			d = ahash_data(m, m->pos++, set->dsize);
 			memcpy(d, data, set->dsize);
-#ifdef IP_SET_HASH_WITH_NETS
-			mtype_data_reset_flags(d, &flags);
-#endif
 		}
 	}