From: Florian Westphal <fw@strlen.de>
To: Zihan Xi <zihanx@nebusec.ai>
Cc: linux-kernel@vger.kernel.org, netfilter-devel@vger.kernel.org,
mingo@redhat.com, peterz@infradead.org, juri.lelli@redhat.com,
vincent.guittot@linaro.org, dietmar.eggemann@arm.com,
rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de,
vschneid@redhat.com, kprateek.nayak@amd.com, pablo@netfilter.org,
phil@nwl.cc, davem@davemloft.net, edumazet@kernel.org,
pabeni@redhat.com, horms@kernel.org, kaber@trash.net,
jengelh@medozas.de, lukas@wunner.de, vega@nebusec.ai,
root@tr0jan.top
Subject: Re: [PATCH nf v7 1/1] netfilter: nf_dup: preserve duplication guard across NFQUEUE
Date: Sun, 11 Oct 2026 16:58:40 +0200 [thread overview]
Message-ID: <asukIMajFpbzx3PH@strlen.de> (raw)
In-Reply-To: <9c51ddfce3069d585b6c9b87e7e1bf3a3b0a2761.1791688819.git.zihanx@nebusec.ai>
Zihan Xi <zihanx@nebusec.ai> wrote:
> nf_dup_ipv4() and nf_dup_ipv6() set current->in_nf_duplicate while the
> cloned skb traverses output hooks. NFQUEUE can retain the clone and return
> NF_STOLEN while that traversal is in progress. Once ip_local_out() or
> ip6_local_out() returns, the task-local guard is cleared. NF_ACCEPT then
> resumes hook traversal after the queued hook in the verdict task, where
> the guard is no longer set. A later dup rule can clone the packet again,
> causing repeated packet processing and resource consumption.
I find this waaaaay too complex.
> include/linux/sched.h | 2 ++
> include/net/netfilter/nf_queue.h | 1 +
> net/ipv4/netfilter/ip_tables.c | 5 ++++-
> net/ipv4/netfilter/nf_dup_ipv4.c | 5 ++++-
> net/ipv6/netfilter/ip6_tables.c | 5 ++++-
> net/ipv6/netfilter/nf_dup_ipv6.c | 6 +++++-
> net/netfilter/nf_dup_netdev.c | 13 ++++++++++++-
> net/netfilter/nf_queue.c | 4 ++++
> net/netfilter/nfnetlink_queue.c | 8 +++++++-
> 9 files changed, 43 insertions(+), 6 deletions(-)
Holy cow... This is waaaay to large/complex, sorry.
> unsigned in_nf_duplicate:1;
> + unsigned in_nf_dup_netdev:1; /* netdev dup output is active */
> + unsigned in_nf_duplicate_reinject:1; /* NFQUEUE resume */
I don't understand this.
> struct nf_hook_state state;
> + bool in_nf_duplicate; /* skb is on a duplication path */
OK.
> diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
> index 809441ced..7c2027ef8 100644
> --- a/net/ipv4/netfilter/ip_tables.c
> +++ b/net/ipv4/netfilter/ip_tables.c
> @@ -14,6 +14,7 @@
> #include <linux/vmalloc.h>
> #include <linux/netdevice.h>
> #include <linux/module.h>
> +#include <linux/preempt.h>
> #include <net/ip.h>
> #include <net/compat.h>
> #include <linux/uaccess.h>
> @@ -270,7 +271,9 @@ ipt_do_table(void *priv,
> * but it is no problem since absolute verdict is issued by these.
> */
> if (static_key_false(&xt_tee_enabled))
> - jumpstack += private->stacksize * current->in_nf_duplicate;
> + jumpstack += private->stacksize *
> + (current->in_nf_duplicate ||
> + (in_task() && current->in_nf_duplicate_reinject));
? Aside from me not getting the need for in_nf_duplicate_reinject, why
is the in_task() needed but for in_nf_duplicate its not needed...?
As those are bits they even reside on same address...
> {
> struct iphdr *iph;
> + bool in_nf_duplicate_reinject = in_task() &&
> + current->in_nf_duplicate_reinject;
Same question.
> #include <linux/slab.h>
> #include <linux/init.h>
> #include <linux/module.h>
> @@ -219,6 +220,9 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
> *entry = (struct nf_queue_entry) {
> .skb = skb,
> .skb_dev = skb->dev,
> + .in_nf_duplicate = current->in_nf_duplicate ||
> + (in_task() && current->in_nf_duplicate_reinject) ||
> + current->in_nf_dup_netdev,
Why not simply
.in_nf_dup_netdev = current->in_nf_duplicate ?
> + bool old_in_nf_duplicate_reinject;
>
> net = entry->state.net;
> pf = entry->state.pf;
> + old_in_nf_duplicate_reinject = current->in_nf_duplicate_reinject;
> + current->in_nf_duplicate_reinject |= entry->in_nf_duplicate;
Don't understand the need to store the old current state here.
Nor the "|=".
> @@ -378,7 +382,7 @@ static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
> if (!hooks || i >= hooks->num_hook_entries) {
> kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP);
> nf_queue_entry_free(entry);
> - return;
> + goto out;
> }
>
> hook_entry = &hooks->hooks[i];
> @@ -417,6 +421,8 @@ static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
> }
>
> nf_queue_entry_free(entry);
> +out:
> + current->in_nf_duplicate_reinject = old_in_nf_duplicate_reinject;
... nor this. AFAICS the only change we really need is to move the
local_bh_disable/enable pair to cover the hook iteration is well in
nf_reinject() to avoid BH interference clearing current->in_nf_duplicate
resp. acting on wron rect "current" task state.
I think we either need to find a way to make this patch way simpler or
go back to the "no duplication/TEE in userns". As I already wrote
earlier, I see no use case for dup/TEE is namespaces, except for CI
maybe.
Also, I think there are many many other ways to make kernel eat lots of
RAM, so I don't think there is any need to ftarget nf tree either.
Sorry, I know you've been spinning on this for a while, but this is too
hard for me to comprehend.
next prev parent reply other threads:[~2026-10-11 14:58 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-11 11:28 [PATCH nf v7 0/1] netfilter: nf_dup: preserve duplication guard across NFQUEUE Zihan Xi
2026-10-11 11:28 ` [PATCH nf v7 1/1] " Zihan Xi
2026-10-11 14:58 ` Florian Westphal [this message]
2026-10-12 1:34 ` zihan xi
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=asukIMajFpbzx3PH@strlen.de \
--to=fw@strlen.de \
--cc=bsegall@google.com \
--cc=davem@davemloft.net \
--cc=dietmar.eggemann@arm.com \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=jengelh@medozas.de \
--cc=juri.lelli@redhat.com \
--cc=kaber@trash.net \
--cc=kprateek.nayak@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
--cc=peterz@infradead.org \
--cc=phil@nwl.cc \
--cc=root@tr0jan.top \
--cc=rostedt@goodmis.org \
--cc=vega@nebusec.ai \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=zihanx@nebusec.ai \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.