Skip to content

Commit 13210fc

Browse files
committed
netfilter: nf_tables: imbalance in flowtable binding
All these cases cause imbalance between BIND and UNBIND calls: - Delete an interface from a flowtable with multiple interfaces - Add a (device to a) flowtable with --check flag - Delete a netns containing a flowtable - In an interactive nft session, create a table with owner flag and flowtable inside, then quit. Fix it by calling FLOW_BLOCK_UNBIND when unregistering hooks, then remove late FLOW_BLOCK_UNBIND call when destroying flowtable. Fixes: ff4bf2f ("netfilter: nf_tables: add nft_unregister_flowtable_hook()") Reported-by: Phil Sutter <[email protected]> Tested-by: Phil Sutter <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 4f619d5 commit 13210fc

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8822,13 +8822,16 @@ static void nft_unregister_flowtable_hook(struct net *net,
88228822
}
88238823

88248824
static void __nft_unregister_flowtable_net_hooks(struct net *net,
8825+
struct nft_flowtable *flowtable,
88258826
struct list_head *hook_list,
88268827
bool release_netdev)
88278828
{
88288829
struct nft_hook *hook, *next;
88298830

88308831
list_for_each_entry_safe(hook, next, hook_list, list) {
88318832
nf_unregister_net_hook(net, &hook->ops);
8833+
flowtable->data.type->setup(&flowtable->data, hook->ops.dev,
8834+
FLOW_BLOCK_UNBIND);
88328835
if (release_netdev) {
88338836
list_del(&hook->list);
88348837
kfree_rcu(hook, rcu);
@@ -8837,9 +8840,10 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,
88378840
}
88388841

88398842
static void nft_unregister_flowtable_net_hooks(struct net *net,
8843+
struct nft_flowtable *flowtable,
88408844
struct list_head *hook_list)
88418845
{
8842-
__nft_unregister_flowtable_net_hooks(net, hook_list, false);
8846+
__nft_unregister_flowtable_net_hooks(net, flowtable, hook_list, false);
88438847
}
88448848

88458849
static int nft_register_flowtable_net_hooks(struct net *net,
@@ -9481,8 +9485,6 @@ static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
94819485

94829486
flowtable->data.type->free(&flowtable->data);
94839487
list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
9484-
flowtable->data.type->setup(&flowtable->data, hook->ops.dev,
9485-
FLOW_BLOCK_UNBIND);
94869488
list_del_rcu(&hook->list);
94879489
kfree_rcu(hook, rcu);
94889490
}
@@ -10870,6 +10872,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
1087010872
&nft_trans_flowtable_hooks(trans),
1087110873
trans->msg_type);
1087210874
nft_unregister_flowtable_net_hooks(net,
10875+
nft_trans_flowtable(trans),
1087310876
&nft_trans_flowtable_hooks(trans));
1087410877
} else {
1087510878
list_del_rcu(&nft_trans_flowtable(trans)->list);
@@ -10878,6 +10881,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
1087810881
NULL,
1087910882
trans->msg_type);
1088010883
nft_unregister_flowtable_net_hooks(net,
10884+
nft_trans_flowtable(trans),
1088110885
&nft_trans_flowtable(trans)->hook_list);
1088210886
}
1088310887
break;
@@ -11140,11 +11144,13 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
1114011144
case NFT_MSG_NEWFLOWTABLE:
1114111145
if (nft_trans_flowtable_update(trans)) {
1114211146
nft_unregister_flowtable_net_hooks(net,
11147+
nft_trans_flowtable(trans),
1114311148
&nft_trans_flowtable_hooks(trans));
1114411149
} else {
1114511150
nft_use_dec_restore(&table->use);
1114611151
list_del_rcu(&nft_trans_flowtable(trans)->list);
1114711152
nft_unregister_flowtable_net_hooks(net,
11153+
nft_trans_flowtable(trans),
1114811154
&nft_trans_flowtable(trans)->hook_list);
1114911155
}
1115011156
break;
@@ -11737,7 +11743,8 @@ static void __nft_release_hook(struct net *net, struct nft_table *table)
1173711743
list_for_each_entry(chain, &table->chains, list)
1173811744
__nf_tables_unregister_hook(net, table, chain, true);
1173911745
list_for_each_entry(flowtable, &table->flowtables, list)
11740-
__nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list,
11746+
__nft_unregister_flowtable_net_hooks(net, flowtable,
11747+
&flowtable->hook_list,
1174111748
true);
1174211749
}
1174311750

0 commit comments

Comments
 (0)