From: Florian Westphal <fw@strlen.de>
To: Jakub Kicinski <kuba@kernel.org>
Cc: pablo@netfilter.org, netfilter-devel@vger.kernel.org,
davem@davemloft.net, netdev@vger.kernel.org, pabeni@redhat.com,
edumazet@google.com, horms@kernel.org, ja@ssi.bg
Subject: Re: [PATCH net 02/10] netfilter: nfnetlink_queue: hold nfnl mutex in event notifier
Date: Fri, 18 Sep 2026 11:51:21 +0200 [thread overview]
Message-ID: <aq0Fr087oC6MH4kQ@strlen.de> (raw)
In-Reply-To: <20260918020409.3513342-1-kuba@kernel.org>
Jakub Kicinski <kuba@kernel.org> wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> netfilter: nfnetlink_queue: hold nfnl mutex in event notifier
>
> This takes the NFNL_SUBSYS_QUEUE mutex around the instance destroy loop in
> nfqnl_rcv_nl_event() so that the NETLINK_URELEASE notifier can no longer run
> in parallel with nfqnl_recv_config(). The stale comment in nfqnl_recv_config()
> is updated to describe the new serialization.
This fixes a unpriv netns root exploit. At least I think so. Its
simple enough to look at and should be small enough to backport.
The LLM report makes me wonder:
1. Does this patch not fix it? If so, how does the reproducer need
to be changed to make it trigger KASAN/UaF again? Doesn't say.
2. Does this add a regression? Doesn't say. Tests I have pass.
> > diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
> > index c727668b0c5be..a3bc002800510 100644
> > --- a/net/netfilter/nfnetlink_queue.c
> > +++ b/net/netfilter/nfnetlink_queue.c
> > @@ -1593,6 +1593,7 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
> > if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
> > int i;
> >
> > + nfnl_lock(NFNL_SUBSYS_QUEUE);
> > /* destroy all instances for this portid */
> > spin_lock(&q->instances_lock);
> > for (i = 0; i < INSTANCE_BUCKETS; i++) {
>
> [Severity: Medium]
> This is a pre-existing issue, not something introduced here, but does waiting
> on the nfnl queue mutex here make it easier to destroy an instance that belongs
> to a different socket?
So what?
This is a 20 year old interface. NOONE, and I really mean, NO ONE, has
raised a bug report in all these years.
*WHAT* does a *SENSIBLE* userspace program need to do so that it ends up
in a bad state?
From where I'm standing, there is a crash bug that is fixed by
this patch without observable new regression.
Aside from not crashing, kernel should also not have to perform absurd
stunts to somehow make sense of whatever crap userspace is trying to do.
> The destroy loop in nfqnl_rcv_nl_event() picks victims by portid only:
>
> hlist_for_each_entry_safe(inst, t2, head, hlist) {
> if (n->portid == inst->peer_portid)
> __instance_destroy(inst);
> }
>
> and net/netlink/af_netlink.c:netlink_release() makes the portid reusable well
> before the notifier runs:
>
> netlink_release()
> netlink_remove(sk); /* portid is free for reuse here */
> sock_orphan(sk);
> ...
> blocking_notifier_call_chain(&netlink_chain,
> NETLINK_URELEASE, &n);
>
> With the new nfnl_lock(NFNL_SUBSYS_QUEUE), the notifier now blocks for the
> whole duration of any NFQNL_MSG_CONFIG handling (including instance_create()
> and its sleeping rhashtable_init()), in any netns, since
> net/netfilter/nfnetlink.c:nfnl_lock() takes the single global
> table[NFNL_SUBSYS_QUEUE].mutex. So this sequence looks possible:
>
> thread 1: close() of a NETLINK_NETFILTER socket with portid X
> netlink_remove() releases X, notifier is pending
This is normally done by some applications when they shut down as
part of SIGTERM for example. Others just exit().
> thread 2: binds portid X, sends NFQNL_CFG_CMD_BIND
> nfnetlink_rcv_msg() -> nfqnl_recv_config() under the queue mutex
> instance_create() links a fresh instance with peer_portid == X
Why would one try do that...? Just... don't do that?
And I don't follow how this can work. LLM clains thread 1 is now
blocked in nfnl_lock(NFNL_SUBSYS_QUEUE), which thread 2 holds.
Therefore, as thread 1 couldn't yet run the notifier, the old queue is
still registered... no?
> thread 1: notifier finally acquires the mutex, matches
> inst->peer_portid == X and calls __instance_destroy() on the
> brand new instance
> Can the ownership check that the new comment relies on detect this?
>
> queue = instance_lookup(q, queue_num);
> if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
>
> peer_portid matches in the recycled-portid case, so the check passes and the
> instance is still torn down by the older socket's notification.
Not following :-/
Even if that test passes, why does it not hit the 'return -EBUSY' in
NFQNL_CFG_CMD_BIND?
If it did not, then instance_lookup() did not return a result, i.e.
queue was already done? Can't make sense of anything anymore.
> There is no memory safety problem, the instance is unlinked once and freed via
> queue_rcu_work(). The visible effect is that a live socket's queue silently
> disappears, its queued packets are flushed, packets hitting the NFQUEUE rule
> then fail with -ESRCH (dropped unless fail-open or bypass is set), and later
> CONFIG messages for that queue number return -ENODEV. It requires
> CAP_NET_ADMIN in the netns and a concurrent close/bind, and no later commit in
> this series touches net/netfilter/nfnetlink_queue.c.
I have no idea how to sensibly change this patch to address this 'bug'.
And thats my main source of frustration with all the LLM walls we have
now in place.
A human telling me that I fucked up usually has the courtesy of providing
an alternative solution or a hint to get things move in the right
direction again.
Or even 'I don't like it because of problem XYZ but I don't have a better
idea either'.
LLM just says 'something is wrong, you figure out the details of fixing
this'. I would like to make better patches, but I don't know how.
next prev parent reply other threads:[~2026-09-18 9:51 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 23:16 [PATCH net 00/10] Netfilter/IPVS fixes for net Pablo Neira Ayuso
2026-09-16 23:16 ` [PATCH net 01/10] netfilter: flowtable: publish HW_DEAD after worker is done Pablo Neira Ayuso
2026-09-17 0:40 ` patchwork-bot+netdevbpf
2026-09-18 2:04 ` Jakub Kicinski
2026-09-18 8:38 ` Pablo Neira Ayuso
2026-09-18 8:56 ` my summary of LLM judgement in this PR [was Re: [PATCH net 01/10] netfilter: flowtable: publish HW_DEAD after worker is done] Pablo Neira Ayuso
2026-09-21 20:56 ` Jakub Kicinski
2026-09-16 23:16 ` [PATCH net 02/10] netfilter: nfnetlink_queue: hold nfnl mutex in event notifier Pablo Neira Ayuso
2026-09-18 2:04 ` Jakub Kicinski
2026-09-18 8:39 ` Pablo Neira Ayuso
2026-09-18 9:51 ` Florian Westphal [this message]
2026-09-16 23:16 ` [PATCH net 03/10] netfilter: ip6t_rpfilter: reject routes without inet6_dev Pablo Neira Ayuso
2026-09-18 2:04 ` Jakub Kicinski
2026-09-18 8:39 ` Pablo Neira Ayuso
2026-09-16 23:16 ` [PATCH net 04/10] netfilter: ip6t_rt: fix zero-address non-strict match out-of-bounds read Pablo Neira Ayuso
2026-09-16 23:16 ` [PATCH net 05/10] netfilter: nft_synproxy: use the family-aware checksum helper Pablo Neira Ayuso
2026-09-16 23:16 ` [PATCH net 06/10] ipvs: revalidate ihl before icmp_send Pablo Neira Ayuso
2026-09-16 23:16 ` [PATCH net 07/10] ipvs: filter some flags received in the backup server Pablo Neira Ayuso
2026-09-18 2:04 ` Jakub Kicinski
2026-09-18 8:39 ` Pablo Neira Ayuso
2026-09-18 10:23 ` Julian Anastasov
2026-09-16 23:16 ` [PATCH net 08/10] netfilter: ctnetlink: fix suspicious RCU usage in expect_iter_name Pablo Neira Ayuso
2026-09-16 23:16 ` [PATCH net 09/10] net: remove WARN_ON_ONCE() from the dev_fill_forward_path() loop check Pablo Neira Ayuso
2026-09-16 23:16 ` [PATCH net 10/10] netfilter: nf_tables: skip expired catchall elements on insert and delete Pablo Neira Ayuso
2026-09-18 2:04 ` Jakub Kicinski
2026-09-18 8:41 ` Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aq0Fr087oC6MH4kQ@strlen.de \
--to=fw@strlen.de \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=ja@ssi.bg \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox