Skip to content

Commit e774e89

Browse files
committed
netfilter: nf_tables: split async and sync catchall in two functions
jira VULN-430 cve CVE-2023-4244 commit-author Pablo Neira Ayuso <[email protected]> commit 8837ba3 list_for_each_entry_safe() does not work for the async case which runs under RCU, therefore, split GC logic for catchall in two functions instead, one for each of the sync and async GC variants. The catchall sync GC variant never sees a _DEAD bit set on ever, thus, this handling is removed in such case, moreover, allocate GC sync batch via GFP_KERNEL. Fixes: 93995bf ("netfilter: nf_tables: remove catchall element in GC sync path") Reported-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]> (cherry picked from commit 8837ba3) Signed-off-by: Marcin Wcisło <[email protected]>
1 parent 1b3a51c commit e774e89

File tree

1 file changed

+34
-28
lines changed

1 file changed

+34
-28
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9296,16 +9296,14 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
92969296
call_rcu(&trans->rcu, nft_trans_gc_trans_free);
92979297
}
92989298

9299-
static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
9300-
unsigned int gc_seq,
9301-
bool sync)
9299+
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
9300+
unsigned int gc_seq)
93029301
{
9303-
struct nft_set_elem_catchall *catchall, *next;
9302+
struct nft_set_elem_catchall *catchall;
93049303
const struct nft_set *set = gc->set;
9305-
struct nft_elem_priv *elem_priv;
93069304
struct nft_set_ext *ext;
93079305

9308-
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
9306+
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
93099307
ext = nft_set_elem_ext(set, catchall->elem);
93109308

93119309
if (!nft_set_elem_expired(ext))
@@ -9315,41 +9313,49 @@ static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
93159313

93169314
nft_set_elem_dead(ext);
93179315
dead_elem:
9318-
if (sync)
9319-
gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
9320-
else
9321-
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
9316+
gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
9317+
if (!gc)
9318+
return NULL;
9319+
9320+
nft_trans_gc_elem_add(gc, catchall->elem);
9321+
}
9322+
9323+
return gc;
9324+
}
93229325

9326+
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
9327+
{
9328+
struct nft_set_elem_catchall *catchall, *next;
9329+
const struct nft_set *set = gc->set;
9330+
struct nft_elem_priv *elem_priv;
9331+
struct nft_set_elem elem;
9332+
struct nft_set_ext *ext;
9333+
9334+
WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net));
9335+
9336+
list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
9337+
ext = nft_set_elem_ext(set, catchall->elem);
9338+
9339+
if (!nft_set_elem_expired(ext))
9340+
continue;
9341+
9342+
gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
93239343
if (!gc)
93249344
return NULL;
93259345

93269346
elem_priv = catchall->elem;
9327-
if (sync) {
9328-
struct nft_set_elem elem = {
9329-
.priv = elem_priv,
9330-
};
93319347

9332-
nft_setelem_data_deactivate(gc->net, gc->set, &elem);
9333-
nft_setelem_catchall_destroy(catchall);
9334-
}
9348+
memset(&elem, 0, sizeof(elem));
9349+
elem.priv = catchall->elem;
93359350

9351+
nft_setelem_data_deactivate(gc->net, gc->set, &elem);
9352+
nft_setelem_catchall_destroy(catchall);
93369353
nft_trans_gc_elem_add(gc, elem_priv);
93379354
}
93389355

93399356
return gc;
93409357
}
93419358

9342-
struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
9343-
unsigned int gc_seq)
9344-
{
9345-
return nft_trans_gc_catchall(gc, gc_seq, false);
9346-
}
9347-
9348-
struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
9349-
{
9350-
return nft_trans_gc_catchall(gc, 0, true);
9351-
}
9352-
93539359
static void nf_tables_module_autoload_cleanup(struct net *net)
93549360
{
93559361
struct nftables_pernet *nft_net = nft_pernet(net);

0 commit comments

Comments
 (0)