[PATCH nf 1/4] netfilter: nft_set_hash: fix panic when destroying set

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In order to destroy elements of set, a rhashtable_free_and_destroy()
is used. the rhashtable_free_and_destroy() cancels a re-hash deferred work
then walks and destroys elements. at this moment, some elements are
still in a future_tbl. that elements are not destroyed.

A nft_rhash_iterate_destroy() walks all elements in the tbl and
the future_tbl then destroy.

test script:
   %cat test.nft
   table ip aa {
	map map1 {
		type ipv4_addr : verdict;
		elements = {
			   0 : jump a0,
			   1 : jump a0,
			   2 : jump a0,
			   3 : jump a0,
			   4 : jump a0,
			   5 : jump a0,
			   6 : jump a0,
			   7 : jump a0,
			   8 : jump a0,
			   9 : jump a0,
		}
	}
	chain a0 {
	}
   }
   flush ruleset

   [ ... ]

   table ip aa {
	map map1 {
		type ipv4_addr : verdict;
		elements = {
			   0 : jump a0,
			   1 : jump a0,
			   2 : jump a0,
			   3 : jump a0,
			   4 : jump a0,
			   5 : jump a0,
			   6 : jump a0,
			   7 : jump a0,
			   8 : jump a0,
			   9 : jump a0,
		}
	}
	chain a0 {
	}
   }
   flush ruleset

Splat looks like:
[  200.795603] kernel BUG at net/netfilter/nf_tables_api.c:1363!
[  200.806944] invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN PTI
[  200.812253] CPU: 1 PID: 1582 Comm: nft Not tainted 4.17.0+ #24
[  200.820297] Hardware name: To be filled by O.E.M. To be filled by O.E.M./Aptio CRB, BIOS 5.6.5 07/08/2015
[  200.830309] RIP: 0010:nf_tables_chain_destroy.isra.34+0x62/0x240 [nf_tables]
[  200.838317] Code: 43 50 85 c0 74 26 48 8b 45 00 48 8b 4d 08 ba 54 05 00 00 48 c7 c6 60 6d 29 c0 48 c7 c7 c0 65 29 c0 4c 8b 40 08 e8 58 e5 fd f8 <0f> 0b 48 89 da 48 b8 00 00 00 00 00 fc ff
[  200.860366] RSP: 0000:ffff880118dbf4d0 EFLAGS: 00010282
[  200.866354] RAX: 0000000000000061 RBX: ffff88010cdeaf08 RCX: 0000000000000000
[  200.874355] RDX: 0000000000000061 RSI: 0000000000000008 RDI: ffffed00231b7e90
[  200.882361] RBP: ffff880118dbf4e8 R08: ffffed002373bcfb R09: ffffed002373bcfa
[  200.890354] R10: 0000000000000000 R11: ffffed002373bcfb R12: dead000000000200
[  200.898356] R13: dead000000000100 R14: ffffffffbb62af38 R15: dffffc0000000000
[  200.906354] FS:  00007fefc31fd700(0000) GS:ffff88011b800000(0000) knlGS:0000000000000000
[  200.915533] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  200.922355] CR2: 0000557f1c8e9128 CR3: 0000000106880000 CR4: 00000000001006e0
[  200.930353] Call Trace:
[  200.932351]  ? nf_tables_commit+0x26f6/0x2c60 [nf_tables]
[  200.939525]  ? nf_tables_setelem_notify.constprop.49+0x1a0/0x1a0 [nf_tables]
[  200.947525]  ? nf_tables_delchain+0x6e0/0x6e0 [nf_tables]
[  200.952383]  ? nft_add_set_elem+0x1700/0x1700 [nf_tables]
[  200.959532]  ? nla_parse+0xab/0x230
[  200.963529]  ? nfnetlink_rcv_batch+0xd06/0x10d0 [nfnetlink]
[  200.968384]  ? nfnetlink_net_init+0x130/0x130 [nfnetlink]
[  200.975525]  ? debug_show_all_locks+0x290/0x290
[  200.980363]  ? debug_show_all_locks+0x290/0x290
[  200.986356]  ? sched_clock_cpu+0x132/0x170
[  200.990352]  ? find_held_lock+0x39/0x1b0
[  200.994355]  ? sched_clock_local+0x10d/0x130
[  200.999531]  ? memset+0x1f/0x40

Signed-off-by: Taehee Yoo <ap420073@xxxxxxxxx>
---
 net/netfilter/nft_set_hash.c | 42 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 35 insertions(+), 7 deletions(-)

diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
index 6f9a136..695d5e8 100644
--- a/net/netfilter/nft_set_hash.c
+++ b/net/netfilter/nft_set_hash.c
@@ -341,6 +341,39 @@ static void nft_rhash_gc(struct work_struct *work)
 			   nft_set_gc_interval(set));
 }
 
+static void nft_rhash_iterate_destroy(const struct nft_set *set,
+				      struct rhashtable *ht)
+{
+	struct nft_rhash_elem *he, *phe = NULL;
+	struct rhashtable_iter hti;
+	struct nft_set *pset = (struct nft_set *)set;
+
+	rhashtable_walk_enter(ht, &hti);
+	rhashtable_walk_start(&hti);
+
+	while ((he = rhashtable_walk_next(&hti))) {
+		if (IS_ERR(he)) {
+			if (PTR_ERR(he) != -EAGAIN)
+				break;
+			continue;
+		}
+		if (nft_set_elem_mark_busy(&he->ext))
+			continue;
+
+		rhashtable_remove_fast(ht, &he->node, nft_rhash_params);
+		if (pset->size)
+			atomic_dec(&pset->nelems);
+		if (phe)
+			nft_set_elem_destroy(pset, phe, true);
+		phe = he;
+	}
+	if (phe)
+		nft_set_elem_destroy(pset, phe, true);
+
+	rhashtable_walk_stop(&hti);
+	rhashtable_walk_exit(&hti);
+}
+
 static unsigned int nft_rhash_privsize(const struct nlattr * const nla[],
 				       const struct nft_set_desc *desc)
 {
@@ -377,18 +410,13 @@ static int nft_rhash_init(const struct nft_set *set,
 	return 0;
 }
 
-static void nft_rhash_elem_destroy(void *ptr, void *arg)
-{
-	nft_set_elem_destroy(arg, ptr, true);
-}
-
 static void nft_rhash_destroy(const struct nft_set *set)
 {
 	struct nft_rhash *priv = nft_set_priv(set);
 
 	cancel_delayed_work_sync(&priv->gc_work);
-	rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
-				    (void *)set);
+	nft_rhash_iterate_destroy(set, &priv->ht);
+	rhashtable_destroy(&priv->ht);
 }
 
 static u32 nft_hash_buckets(u32 size)
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux