* [PATCH nf-next] netfilter: nfnetlink_queue: hash queue instance by portid too
@ 2026-09-16 22:00 Pablo Neira Ayuso
2026-09-17 4:36 ` Florian Westphal
0 siblings, 1 reply; 4+ messages in thread
From: Pablo Neira Ayuso @ 2026-09-16 22:00 UTC (permalink / raw)
To: netfilter-devel; +Cc: fw
netlink_release() calls netlink_remove() before delivering the
NETLINK_URELEASE event. And a new queue instance can be created before
delivering such NETLINK_URELEASE event. This allows for two different
queue instances with the same portid to co-exist for a little while.
Since the instance that is going away is destroyed by portid via netlink
notifier, both the newly created instance and the one that is going away
with the same portid are destroyed.
Fixes: 7af4cc3fa158 ("[NETFILTER]: Add "nfnetlink_queue" netfilter queue handler over nfnetlink")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
@Florian: this is the rare race that Clashiko uncover with your fix.
This is a pre-existing issue. I have to check if nfnetlink_log
is also affected.
net/netfilter/nfnetlink_queue.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a3bc00280051..cbb586231fbd 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -69,6 +69,7 @@
struct nfqnl_instance {
struct hlist_node hlist; /* global list of queues */
+ struct hlist_node hlist_portid; /* global list of queues, by portid */
struct rhashtable nfqnl_packet_map;
struct rcu_work rwork;
@@ -101,6 +102,7 @@ static unsigned int nfnl_queue_net_id __read_mostly;
struct nfnl_queue_net {
spinlock_t instances_lock;
struct hlist_head instance_table[INSTANCE_BUCKETS];
+ struct hlist_head instance_table_portid[INSTANCE_BUCKETS];
};
static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net)
@@ -113,6 +115,11 @@ static inline u_int8_t instance_hashfn(u_int16_t queue_num)
return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;
}
+static inline u8 instance_portid_hashfn(u32 portid)
+{
+ return portid % INSTANCE_BUCKETS;
+}
+
static const struct rhashtable_params nfqnl_rhashtable_params = {
.head_offset = offsetof(struct nf_queue_entry, hash_node),
.key_offset = offsetof(struct nf_queue_entry, id),
@@ -136,6 +143,20 @@ instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num)
return NULL;
}
+static struct nfqnl_instance *
+instance_lookup_by_portid(struct nfnl_queue_net *q, u32 portid)
+{
+ struct nfqnl_instance *inst;
+ struct hlist_head *head;
+
+ head = &q->instance_table[instance_portid_hashfn(portid)];
+ hlist_for_each_entry(inst, head, hlist) {
+ if (inst->peer_portid == portid)
+ return inst;
+ }
+ return NULL;
+}
+
static struct nfqnl_instance *
instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
{
@@ -160,7 +181,8 @@ instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
goto out_free;
spin_lock(&q->instances_lock);
- if (instance_lookup(q, queue_num)) {
+ if (instance_lookup(q, queue_num) ||
+ instance_lookup_by_portid(q, queue_num)) {
err = -EEXIST;
goto out_unlock;
}
@@ -172,6 +194,8 @@ instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
h = instance_hashfn(queue_num);
hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]);
+ h = instance_portid_hashfn(portid);
+ hlist_add_head(&inst->hlist_portid, &q->instance_table_portid[h]);
spin_unlock(&q->instances_lock);
@@ -208,6 +232,7 @@ static void
__instance_destroy(struct nfqnl_instance *inst)
{
hlist_del_rcu(&inst->hlist);
+ hlist_del(&inst->hlist_portid);
INIT_RCU_WORK(&inst->rwork, instance_destroy_work);
queue_rcu_work(nfq_cleanup_wq, &inst->rwork);
@@ -2121,8 +2146,10 @@ static int __net_init nfnl_queue_net_init(struct net *net)
unsigned int i;
struct nfnl_queue_net *q = nfnl_queue_pernet(net);
- for (i = 0; i < INSTANCE_BUCKETS; i++)
+ for (i = 0; i < INSTANCE_BUCKETS; i++) {
INIT_HLIST_HEAD(&q->instance_table[i]);
+ INIT_HLIST_HEAD(&q->instance_table_portid[i]);
+ }
spin_lock_init(&q->instances_lock);
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH nf-next] netfilter: nfnetlink_queue: hash queue instance by portid too
2026-09-16 22:00 [PATCH nf-next] netfilter: nfnetlink_queue: hash queue instance by portid too Pablo Neira Ayuso
@ 2026-09-17 4:36 ` Florian Westphal
2026-09-17 8:54 ` Pablo Neira Ayuso
0 siblings, 1 reply; 4+ messages in thread
From: Florian Westphal @ 2026-09-17 4:36 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> netlink_release() calls netlink_remove() before delivering the
> NETLINK_URELEASE event. And a new queue instance can be created before
> delivering such NETLINK_URELEASE event. This allows for two different
> queue instances with the same portid to co-exist for a little while.
> Since the instance that is going away is destroyed by portid via netlink
> notifier, both the newly created instance and the one that is going away
> with the same portid are destroyed.
>
> Fixes: 7af4cc3fa158 ("[NETFILTER]: Add "nfnetlink_queue" netfilter queue handler over nfnetlink")
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> ---
> @Florian: this is the rare race that Clashiko uncover with your fix.
> This is a pre-existing issue. I have to check if nfnetlink_log
> is also affected.
AFAICS its complete bullshit report.
Needs threads that race to kill and resurrect the same queue all over
again, constantly.
Don't do that, then?!
What kind of userspace does this?! I mean, what's the point?
We could make nfqueue refcounted, like _log, but I see no reason
whatsover.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH nf-next] netfilter: nfnetlink_queue: hash queue instance by portid too
2026-09-17 4:36 ` Florian Westphal
@ 2026-09-17 8:54 ` Pablo Neira Ayuso
2026-09-17 9:30 ` Florian Westphal
0 siblings, 1 reply; 4+ messages in thread
From: Pablo Neira Ayuso @ 2026-09-17 8:54 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Thu, Sep 17, 2026 at 06:36:34AM +0200, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > netlink_release() calls netlink_remove() before delivering the
> > NETLINK_URELEASE event. And a new queue instance can be created before
> > delivering such NETLINK_URELEASE event. This allows for two different
> > queue instances with the same portid to co-exist for a little while.
> > Since the instance that is going away is destroyed by portid via netlink
> > notifier, both the newly created instance and the one that is going away
> > with the same portid are destroyed.
> >
> > Fixes: 7af4cc3fa158 ("[NETFILTER]: Add "nfnetlink_queue" netfilter queue handler over nfnetlink")
> > Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> > ---
> > @Florian: this is the rare race that Clashiko uncover with your fix.
> > This is a pre-existing issue. I have to check if nfnetlink_log
> > is also affected.
>
> AFAICS its complete bullshit report.
It's theoretical, yes.
> Needs threads that race to kill and resurrect the same queue all over
> again, constantly.
I think this can happen with different queue number and same netlink
portid.
> Don't do that, then?!
> What kind of userspace does this?! I mean, what's the point?
The goal of my patch reject duplicates netlink portid.
> We could make nfqueue refcounted, like _log, but I see no reason
> whatsover.
I don't see how refcounting will fix this race.
The problem is that the netlink notifier path encounters two different
queue instances with the same portid, and it destroys both of them,
the new and the stale one.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH nf-next] netfilter: nfnetlink_queue: hash queue instance by portid too
2026-09-17 8:54 ` Pablo Neira Ayuso
@ 2026-09-17 9:30 ` Florian Westphal
0 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2026-09-17 9:30 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > Needs threads that race to kill and resurrect the same queue all over
> > again, constantly.
>
> I think this can happen with different queue number and same netlink
> portid.
You mean using several nfqueue instances at once from same fd?
Nobody does that. This is a 20 years old interface.
And what would be the point...? Other than trying to crash the kernel,
that is?
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-17 9:30 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-16 22:00 [PATCH nf-next] netfilter: nfnetlink_queue: hash queue instance by portid too Pablo Neira Ayuso
2026-09-17 4:36 ` Florian Westphal
2026-09-17 8:54 ` Pablo Neira Ayuso
2026-09-17 9:30 ` Florian Westphal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox