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] " 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®