Re: [PATCH 2/9] netfilter/nf_tables: Add folio_scratchpad collector to struct nftables_pernet

[email protected]
Newsgroups org.freedesktop.lists.dri-devel,org.kernel.vger.bpf
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] Asynchronous reset and synchronous abort paths cause severe use-after-free, memory corruption, and spinlock corruption due to sharing a single per-net scratchpad across overlapping batch lifecycles.
- [High] Transaction batches that consist exclusively of creation operations permanently leak the memory used for their `nft_trans` objects.
- [Medium] Re-initialization of the scratchpad during an abort drops the feature-toggle static key and hardcodes the allocation order, causing memory over-allocation on some architectures.
--

--- Patch [2]: [PATCH 2/9] netfilter/nf_tables: Add folio_scratchpad collector to struct nftables_pernet ---
commit 210be9d0ffcaa1541a9b10d23109de51629b6996
Author: Jim Cromie <[email protected]>

netfilter/nf_tables: Add folio_scratchpad collector to struct nftables_pernet

This commit introduces a folio_scratchpad to struct nftables_pernet to handle
variable-sized transaction object allocations. It aims to improve allocation
and teardown speed by replacing standard SLUB allocations with bulk teardown.

> --- a/net/netfilter/nf_tables_api.c
> +++ b/net/netfilter/nf_tables_api.c
> [ ... ]
> @@ -221,7 +238,7 @@ static void nft_trans_list_del(struct nft_trans *trans)
>  static void nft_trans_destroy(struct nft_trans *trans)
>  {
>         nft_trans_list_del(trans);
> -       kfree(trans);
> +       nft_trans_free(trans);
>  }

[Severity: High]
During commit for creation operations, nft_trans_destroy() unlinks the
transaction and calls nft_trans_free(), which is a no-op for scratchpad
chunks.

By the time the code reaches nf_tables_commit_release(), the commit_list is
completely empty.

This causes nf_tables_commit_release() to return early and skip scheduling
the destroy worker. Since the asynchronous worker never runs,
folio_scratchpad_reset() is never called.

Can batches consisting only of creation operations permanently leak memory?

> [ ... ]
> @@ -10267,6 +10286,8 @@ static void nf_tables_trans_destroy_work(struct work_struct *w)
>                 nft_trans_list_del(trans);
>                 nft_commit_release(trans);
>         }
> +
> +       folio_scratchpad_reset(&nft_net->trans_scratchpad);
>  }

[Severity: Critical]
When nf_tables_commit_release() schedules nf_tables_trans_destroy_work()
and drops the commit_mutex, a new batch can immediately begin allocating
transactions from this exact same scratchpad.

Meanwhile, the asynchronous worker for the previous batch will unconditionally
call folio_scratchpad_reset() here.

This rewinds the allocator's free pointer and destroys the memory actively
being used by the new batch.

Does this shared per-net scratchpad suffer from a race condition between
concurrent batches?

> [ ... ]
> @@ -11491,6 +11514,9 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb,
>         else
>                 nf_tables_module_autoload_cleanup(net);
>  
> +       folio_scratchpad_free(&nft_net->trans_scratchpad);
> +       folio_scratchpad_init(&nft_net->trans_scratchpad, 4);
> +
>         mutex_unlock(&nft_net->commit_mutex);

[Severity: Critical]
If the first batch's async worker is currently accessing the folios or
waiting on the internal scratchpad spinlock, calling
folio_scratchpad_free() and folio_scratchpad_init() here will free the
underlying folios and re-initialize the spinlock.

Does this synchronous abort corrupt the allocator state if the previous
batch's asynchronous worker is still running?

[Severity: Medium]
In nf_tables_init_net(), the scratchpad is initialized properly using
folio_scratchpad_init_key() with get_order(SZ_64K) and the
nft_trans_scratchpad_key.

Passing the literal 4 here instead of get_order(SZ_64K) forces the
allocator to request 1MB pages on systems with 64KB pages.

Additionally, folio_scratchpad_init() sets sp->key = NULL, which
permanently strips the feature toggle validation from all subsequent
allocations in this network namespace.

Does this re-initialization hardcode the allocation order and drop the
feature toggle?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.