Skip to content

Commit 58e5f04

Browse files
committed
netfilter: nf_tables: fix GC transaction races with netns and netlink event exit path
JIRA: https://issues.redhat.com/browse/RHEL-1720 JIRA: https://issues.redhat.com/browse/RHEL-1721 Upstream Status: commit 6a33d8b commit 6a33d8b Author: Pablo Neira Ayuso <[email protected]> Date: Tue Aug 15 15:39:00 2023 +0200 netfilter: nf_tables: fix GC transaction races with netns and netlink event exit path Netlink event path is missing a synchronization point with GC transactions. Add GC sequence number update to netns release path and netlink event path, any GC transaction losing race will be discarded. Fixes: 5f68718 ("netfilter: nf_tables: GC transaction API to avoid race with control plane") Signed-off-by: Pablo Neira Ayuso <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Florian Westphal <[email protected]>
1 parent 5911169 commit 58e5f04

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9403,6 +9403,22 @@ static void nft_set_commit_update(struct list_head *set_update_list)
94039403
}
94049404
}
94059405

9406+
static unsigned int nft_gc_seq_begin(struct nftables_pernet *nft_net)
9407+
{
9408+
unsigned int gc_seq;
9409+
9410+
/* Bump gc counter, it becomes odd, this is the busy mark. */
9411+
gc_seq = READ_ONCE(nft_net->gc_seq);
9412+
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9413+
9414+
return gc_seq;
9415+
}
9416+
9417+
static void nft_gc_seq_end(struct nftables_pernet *nft_net, unsigned int gc_seq)
9418+
{
9419+
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9420+
}
9421+
94069422
static int nf_tables_commit(struct net *net, struct sk_buff *skb)
94079423
{
94089424
struct nftables_pernet *nft_net = nft_pernet(net);
@@ -9488,9 +9504,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
94889504

94899505
WRITE_ONCE(nft_net->base_seq, base_seq);
94909506

9491-
/* Bump gc counter, it becomes odd, this is the busy mark. */
9492-
gc_seq = READ_ONCE(nft_net->gc_seq);
9493-
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9507+
gc_seq = nft_gc_seq_begin(nft_net);
94949508

94959509
/* step 3. Start new generation, rules_gen_X now in use. */
94969510
net->nft.gencursor = nft_gencursor_next(net);
@@ -9688,7 +9702,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
96889702
nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
96899703
nf_tables_commit_audit_log(&adl, nft_net->base_seq);
96909704

9691-
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9705+
nft_gc_seq_end(nft_net, gc_seq);
96929706
nf_tables_commit_release(net);
96939707

96949708
return 0;
@@ -10678,13 +10692,17 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
1067810692
struct net *net = n->net;
1067910693
unsigned int deleted;
1068010694
bool restart = false;
10695+
unsigned int gc_seq;
1068110696

1068210697
if (event != NETLINK_URELEASE || n->protocol != NETLINK_NETFILTER)
1068310698
return NOTIFY_DONE;
1068410699

1068510700
nft_net = nft_pernet(net);
1068610701
deleted = 0;
1068710702
mutex_lock(&nft_net->commit_mutex);
10703+
10704+
gc_seq = nft_gc_seq_begin(nft_net);
10705+
1068810706
if (!list_empty(&nf_tables_destroy_list))
1068910707
rcu_barrier();
1069010708
again:
@@ -10707,6 +10725,8 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
1070710725
if (restart)
1070810726
goto again;
1070910727
}
10728+
nft_gc_seq_end(nft_net, gc_seq);
10729+
1071010730
mutex_unlock(&nft_net->commit_mutex);
1071110731

1071210732
return NOTIFY_DONE;
@@ -10745,12 +10765,20 @@ static void __net_exit nf_tables_pre_exit_net(struct net *net)
1074510765
static void __net_exit nf_tables_exit_net(struct net *net)
1074610766
{
1074710767
struct nftables_pernet *nft_net = nft_pernet(net);
10768+
unsigned int gc_seq;
1074810769

1074910770
mutex_lock(&nft_net->commit_mutex);
10771+
10772+
gc_seq = nft_gc_seq_begin(nft_net);
10773+
1075010774
if (!list_empty(&nft_net->commit_list) ||
1075110775
!list_empty(&nft_net->module_list))
1075210776
__nf_tables_abort(net, NFNL_ABORT_NONE);
10777+
1075310778
__nft_release_tables(net);
10779+
10780+
nft_gc_seq_end(nft_net, gc_seq);
10781+
1075410782
mutex_unlock(&nft_net->commit_mutex);
1075510783
WARN_ON_ONCE(!list_empty(&nft_net->tables));
1075610784
WARN_ON_ONCE(!list_empty(&nft_net->module_list));

0 commit comments

Comments
 (0)