From d2012975619251bdfeb7a5159faa7727ea9cddd3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 27 Dec 2013 10:44:23 +0100 Subject: [PATCH] netfilter: nf_tables: fix oops when updating table with user chains This patch fixes a crash while trying to deactivate a table that contains user chains. You can reproduce it via: % nft add table table1 % nft add chain table1 chain1 % nft-table-upd ip table1 dormant [ 253.021026] BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 [ 253.021114] IP: [] nf_register_hook+0x35/0x6f [ 253.021167] PGD 30fa5067 PUD 30fa2067 PMD 0 [ 253.021208] Oops: 0000 [#1] SMP [...] [ 253.023305] Call Trace: [ 253.023331] [] nf_tables_newtable+0x11c/0x258 [nf_tables] [ 253.023385] [] nfnetlink_rcv_msg+0x1f4/0x226 [nfnetlink] [ 253.023438] [] ? nfnetlink_rcv_msg+0x7a/0x226 [nfnetlink] [ 253.023491] [] ? nfnetlink_bind+0x45/0x45 [nfnetlink] [ 253.023542] [] netlink_rcv_skb+0x3c/0x88 [ 253.023586] [] nfnetlink_rcv+0x3af/0x3e4 [nfnetlink] [ 253.023638] [] ? _raw_read_unlock+0x22/0x34 [ 253.023683] [] netlink_unicast+0xe2/0x161 [ 253.023727] [] netlink_sendmsg+0x304/0x332 [ 253.023773] [] __sock_sendmsg_nosec+0x25/0x27 [ 253.023820] [] sock_sendmsg+0x5a/0x7b [ 253.023861] [] ? copy_from_user+0x2a/0x2c [ 253.023905] [] ? move_addr_to_kernel+0x35/0x60 [ 253.023952] [] SYSC_sendto+0x119/0x15c [ 253.023995] [] ? sysret_check+0x1b/0x56 [ 253.024039] [] ? trace_hardirqs_on_caller+0x140/0x1db [ 253.024090] [] ? trace_hardirqs_on_thunk+0x3a/0x3f [ 253.024141] [] SyS_sendto+0x9/0xb [ 253.026219] [] system_call_fastpath+0x16/0x1b Reported-by: Alex Wei Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index d9fcd279942f..d65c80b0e84d 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -312,6 +312,9 @@ static int nf_tables_table_enable(struct nft_table *table) int err, i = 0; list_for_each_entry(chain, &table->chains, list) { + if (!(chain->flags & NFT_BASE_CHAIN)) + continue; + err = nf_register_hook(&nft_base_chain(chain)->ops); if (err < 0) goto err; @@ -321,6 +324,9 @@ static int nf_tables_table_enable(struct nft_table *table) return 0; err: list_for_each_entry(chain, &table->chains, list) { + if (!(chain->flags & NFT_BASE_CHAIN)) + continue; + if (i-- <= 0) break; @@ -333,8 +339,10 @@ static int nf_tables_table_disable(struct nft_table *table) { struct nft_chain *chain; - list_for_each_entry(chain, &table->chains, list) - nf_unregister_hook(&nft_base_chain(chain)->ops); + list_for_each_entry(chain, &table->chains, list) { + if (chain->flags & NFT_BASE_CHAIN) + nf_unregister_hook(&nft_base_chain(chain)->ops); + } return 0; } -- 2.30.2