Skip to content

Commit ca02f6e

Browse files
committed
netfilter: nf_tables: fix GC transaction races with netns and netlink event exit path
jira VULN-430 cve CVE-2023-4244 commit-author Pablo Neira Ayuso <[email protected]> commit 6a33d8b 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]> (cherry picked from commit 6a33d8b) Signed-off-by: Marcin Wcisło <[email protected]>
1 parent 394c480 commit ca02f6e

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
@@ -9428,6 +9428,22 @@ static void nft_set_commit_update(struct list_head *set_update_list)
94289428
}
94299429
}
94309430

9431+
static unsigned int nft_gc_seq_begin(struct nftables_pernet *nft_net)
9432+
{
9433+
unsigned int gc_seq;
9434+
9435+
/* Bump gc counter, it becomes odd, this is the busy mark. */
9436+
gc_seq = READ_ONCE(nft_net->gc_seq);
9437+
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9438+
9439+
return gc_seq;
9440+
}
9441+
9442+
static void nft_gc_seq_end(struct nftables_pernet *nft_net, unsigned int gc_seq)
9443+
{
9444+
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9445+
}
9446+
94319447
static int nf_tables_commit(struct net *net, struct sk_buff *skb)
94329448
{
94339449
struct nftables_pernet *nft_net = nft_pernet(net);
@@ -9513,9 +9529,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
95139529

95149530
WRITE_ONCE(nft_net->base_seq, base_seq);
95159531

9516-
/* Bump gc counter, it becomes odd, this is the busy mark. */
9517-
gc_seq = READ_ONCE(nft_net->gc_seq);
9518-
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9532+
gc_seq = nft_gc_seq_begin(nft_net);
95199533

95209534
/* step 3. Start new generation, rules_gen_X now in use. */
95219535
net->nft.gencursor = nft_gencursor_next(net);
@@ -9713,7 +9727,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
97139727
nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
97149728
nf_tables_commit_audit_log(&adl, nft_net->base_seq);
97159729

9716-
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
9730+
nft_gc_seq_end(nft_net, gc_seq);
97179731
nf_tables_commit_release(net);
97189732

97199733
return 0;
@@ -10699,13 +10713,17 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
1069910713
struct net *net = n->net;
1070010714
unsigned int deleted;
1070110715
bool restart = false;
10716+
unsigned int gc_seq;
1070210717

1070310718
if (event != NETLINK_URELEASE || n->protocol != NETLINK_NETFILTER)
1070410719
return NOTIFY_DONE;
1070510720

1070610721
nft_net = nft_pernet(net);
1070710722
deleted = 0;
1070810723
mutex_lock(&nft_net->commit_mutex);
10724+
10725+
gc_seq = nft_gc_seq_begin(nft_net);
10726+
1070910727
if (!list_empty(&nf_tables_destroy_list))
1071010728
rcu_barrier();
1071110729
again:
@@ -10728,6 +10746,8 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
1072810746
if (restart)
1072910747
goto again;
1073010748
}
10749+
nft_gc_seq_end(nft_net, gc_seq);
10750+
1073110751
mutex_unlock(&nft_net->commit_mutex);
1073210752

1073310753
return NOTIFY_DONE;
@@ -10766,12 +10786,20 @@ static void __net_exit nf_tables_pre_exit_net(struct net *net)
1076610786
static void __net_exit nf_tables_exit_net(struct net *net)
1076710787
{
1076810788
struct nftables_pernet *nft_net = nft_pernet(net);
10789+
unsigned int gc_seq;
1076910790

1077010791
mutex_lock(&nft_net->commit_mutex);
10792+
10793+
gc_seq = nft_gc_seq_begin(nft_net);
10794+
1077110795
if (!list_empty(&nft_net->commit_list) ||
1077210796
!list_empty(&nft_net->module_list))
1077310797
__nf_tables_abort(net, NFNL_ABORT_NONE);
10798+
1077410799
__nft_release_tables(net);
10800+
10801+
nft_gc_seq_end(nft_net, gc_seq);
10802+
1077510803
mutex_unlock(&nft_net->commit_mutex);
1077610804
WARN_ON_ONCE(!list_empty(&nft_net->tables));
1077710805
WARN_ON_ONCE(!list_empty(&nft_net->module_list));

0 commit comments

Comments
 (0)