Skip to content

Commit b93cdbe

Browse files
committed
netfilter: nf_tables: fix GC transaction races with netns and netlink event exit path
jira VULN-597 subsystem-sync netfilter:nf_tables 4.18.0-534 commit-author Pablo Neira Ayuso <pablo@netfilter.org> commit 6a33d8b upstream-diff There's a lot of fuzz and code differences - resolved in favor of the 534 release code. 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 <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de> (cherry picked from commit 6a33d8b) Signed-off-by: Greg Rose <g.v.rose@ciq.com>
1 parent 501d15e commit b93cdbe

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8136,10 +8136,27 @@ static void nft_set_commit_update(struct list_head *set_update_list)
81368136
}
81378137
}
81388138

8139+
static unsigned int nft_gc_seq_begin(struct nftables_pernet *nft_net)
8140+
{
8141+
unsigned int gc_seq;
8142+
8143+
/* Bump gc counter, it becomes odd, this is the busy mark. */
8144+
gc_seq = READ_ONCE(nft_net->gc_seq);
8145+
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
8146+
8147+
return gc_seq;
8148+
}
8149+
8150+
static void nft_gc_seq_end(struct nftables_pernet *nft_net, unsigned int gc_seq)
8151+
{
8152+
WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
8153+
}
8154+
81398155
static int nf_tables_commit(struct net *net, struct sk_buff *skb)
81408156
{
81418157
struct nftables_pernet *nft_net = nft_pernet(net);
81428158
struct nft_trans *trans, *next;
8159+
unsigned int base_seq, gc_seq;
81438160
LIST_HEAD(set_update_list);
81448161
struct nft_trans_elem *te;
81458162
struct nft_chain *chain;
@@ -8195,6 +8212,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
81958212

81968213
WRITE_ONCE(net->nft.base_seq, base_seq);
81978214

8215+
gc_seq = nft_gc_seq_begin(nft_net);
8216+
81988217
/* step 3. Start new generation, rules_gen_X now in use. */
81998218
net->nft.gencursor = nft_gencursor_next(net);
82008219

@@ -8351,6 +8370,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
83518370
nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
83528371
nf_tables_commit_audit_log(&adl, net->nft.base_seq);
83538372

8373+
nft_gc_seq_end(nft_net, gc_seq);
83548374
nf_tables_commit_release(net);
83558375

83568376
return 0;
@@ -8498,7 +8518,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
84988518
break;
84998519
}
85008520
te = (struct nft_trans_elem *)trans->data;
8501-
te->set->ops->remove(net, te->set, &te->elem);
8521+
nft_setelem_remove(net, te->set, &te->elem);
85028522
atomic_dec(&te->set->nelems);
85038523

85048524
if (te->set->ops->abort &&
@@ -9221,15 +9241,20 @@ static void __net_exit nf_tables_pre_exit_net(struct net *net)
92219241
static void __net_exit nf_tables_exit_net(struct net *net)
92229242
{
92239243
struct nftables_pernet *nft_net = nft_pernet(net);
9244+
unsigned int gc_seq;
92249245

92259246
mutex_lock(&net->nft_commit_mutex);
92269247

9248+
gc_seq = nft_gc_seq_begin(nft_net);
9249+
92279250
if (!list_empty(&net->nft.commit_list) ||
9228-
!list_empty(&net->nft_module_list))
9229-
__nf_tables_abort(net, NFNL_ABORT_NONE);
9251+
!list_empty(&net->nft_module_list))
9252+
__nf_tables_abort(net, NFNL_ABORT_NONE);
92309253

92319254
__nft_release_tables(net);
92329255

9256+
nft_gc_seq_end(nft_net, gc_seq);
9257+
92339258
mutex_unlock(&net->nft_commit_mutex);
92349259
WARN_ON_ONCE(!list_empty(&net->nft.tables));
92359260
WARN_ON_ONCE(!list_empty(&net->nft_module_list));

0 commit comments

Comments
 (0)