From: Zihan Xi <zihanx@nebusec.ai>
To: netfilter-devel@vger.kernel.org
Cc: fw@strlen.de, pablo@netfilter.org, phil@nwl.cc,
netdev@vger.kernel.org, zihanx@nebusec.ai,
stable@vger.kernel.org, Vega <vega@nebusec.ai>,
Luxing Yin <root@tr0jan.top>
Subject: [PATCH nf v5 1/1] netfilter: nf_dup: reject TEE and IPv4/IPv6/netdev nft dup in userns
Date: Tue, 29 Sep 2026 12:58:32 +0000 [thread overview]
Message-ID: <20260929125832.25316-2-zihanx@nebusec.ai> (raw)
In-Reply-To: <20260929125832.25316-1-zihanx@nebusec.ai>
The packet-duplication frontends can permit repeated packet duplication and
resource consumption when configured in a network namespace owned by a
non-initial user namespace. Users with CAP_NET_ADMIN in that namespace can
configure the affected rules.
No use case for TEE or nft dup in such namespaces has been identified.
Reject TEE and IPv4/IPv6/netdev nft dup rule or expression setup with
-EPERM there, without adding checks to packet-processing fast paths.
This is a namespace policy restriction, not a general fix for asynchronous
duplication behavior. Rules remain installable in init_user_ns-owned
network namespaces, and their existing packet-processing behavior is
unchanged.
Fixes: cd58bcd9787e ("netfilter: xt_TEE: have cloned packet travel through Xtables too")
Fixes: 502061f81d3e ("netfilter: nf_tables: add packet duplication to the netdev family")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: LLM
Co-developed-by: Luxing Yin <root@tr0jan.top>
Signed-off-by: Luxing Yin <root@tr0jan.top>
Signed-off-by: Zihan Xi <zihanx@nebusec.ai>
---
changes in v5:
- describe the patch as a non-initial-userns setup restriction, not a
general recursion fix; state that init_user_ns behavior is unchanged
- remove path-specific trigger details and run-specific metrics from the
public commit and cover prose
- drop d877f07112f1 from Fixes: because it added a later frontend, not the
shared duplication behavior addressed by this restriction
- record the v5 build and setup-time validation, distinguishing them from
earlier unpatched-baseline and root-OOM runs
- v4 Link:
https://lore.kernel.org/all/cover.1790408011.git.zihanx@nebusec.ai/
changes in v4:
- add Fixes tags for TEE, IPv4/IPv6 nft dup, and netdev nft dup
frontends
- clarify that fcd53c51d037 only added a synchronous guard
- clarify that this restricts non-initial user namespaces and does not
fix asynchronous recursion in init_user_ns-owned network namespaces
- state explicitly that the netdev loop was not runtime-reproduced
- v3 Link:
https://lore.kernel.org/all/cover.1790042930.git.zihanx@nebusec.ai/
changes in v3:
- reroll the fix against the latest nf.git main after no follow-up on v2
- add the Co-developed-by trailer and matching Signed-off-by
- v2 Link:
https://lore.kernel.org/all/cover.1788425393.git.zihanx@nebusec.ai/
changes in v2:
- drop the persistent struct sk_buff::nf_duplicated field and nf_copy()
change from v1
- disable IPv4/IPv6 duplication in non-initial user namespaces
- v1 Link:
https://lore.kernel.org/all/cover.1787903722.git.zihanx@nebusec.ai/
---
net/ipv4/netfilter/nft_dup_ipv4.c | 4 ++++
net/ipv6/netfilter/nft_dup_ipv6.c | 4 ++++
net/netfilter/nft_dup_netdev.c | 4 ++++
net/netfilter/xt_TEE.c | 4 ++++
4 files changed, 16 insertions(+)
diff --git a/net/ipv4/netfilter/nft_dup_ipv4.c b/net/ipv4/netfilter/nft_dup_ipv4.c
index d53a65ddbd7b..db62e30456e4 100644
--- a/net/ipv4/netfilter/nft_dup_ipv4.c
+++ b/net/ipv4/netfilter/nft_dup_ipv4.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netlink.h>
+#include <linux/user_namespace.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h>
@@ -37,6 +38,9 @@ static int nft_dup_ipv4_init(const struct nft_ctx *ctx,
struct nft_dup_ipv4 *priv = nft_expr_priv(expr);
int err;
+ if (ctx->net->user_ns != &init_user_ns)
+ return -EPERM;
+
if (tb[NFTA_DUP_SREG_ADDR] == NULL)
return -EINVAL;
diff --git a/net/ipv6/netfilter/nft_dup_ipv6.c b/net/ipv6/netfilter/nft_dup_ipv6.c
index 95ec27b3971c..6219ef57633e 100644
--- a/net/ipv6/netfilter/nft_dup_ipv6.c
+++ b/net/ipv6/netfilter/nft_dup_ipv6.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netlink.h>
+#include <linux/user_namespace.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h>
@@ -35,6 +36,9 @@ static int nft_dup_ipv6_init(const struct nft_ctx *ctx,
struct nft_dup_ipv6 *priv = nft_expr_priv(expr);
int err;
+ if (ctx->net->user_ns != &init_user_ns)
+ return -EPERM;
+
if (tb[NFTA_DUP_SREG_ADDR] == NULL)
return -EINVAL;
diff --git a/net/netfilter/nft_dup_netdev.c b/net/netfilter/nft_dup_netdev.c
index 06866799e946..8d9dfd18475c 100644
--- a/net/netfilter/nft_dup_netdev.c
+++ b/net/netfilter/nft_dup_netdev.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netlink.h>
+#include <linux/user_namespace.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h>
@@ -37,6 +38,9 @@ static int nft_dup_netdev_init(const struct nft_ctx *ctx,
{
struct nft_dup_netdev *priv = nft_expr_priv(expr);
+ if (ctx->net->user_ns != &init_user_ns)
+ return -EPERM;
+
if (tb[NFTA_DUP_SREG_DEV] == NULL)
return -EINVAL;
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 5d34ceb893ed..51c643987526 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/route.h>
+#include <linux/user_namespace.h>
#include <linux/netfilter/x_tables.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@ -95,6 +96,9 @@ static int tee_tg_check(const struct xt_tgchk_param *par)
struct xt_tee_tginfo *info = par->targinfo;
struct xt_tee_priv *priv;
+ if (par->net->user_ns != &init_user_ns)
+ return -EPERM;
+
/* 0.0.0.0 and :: not allowed */
if (memcmp(&info->gw, &tee_zero_address,
sizeof(tee_zero_address)) == 0)
--
2.43.0
prev parent reply other threads:[~2026-09-29 12:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-29 12:58 [PATCH nf v5 0/1] netfilter: nf_dup: reject TEE and IPv4/IPv6/netdev nft dup in userns Zihan Xi
2026-09-29 12:58 ` Zihan Xi [this message]
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=20260929125832.25316-2-zihanx@nebusec.ai \
--to=zihanx@nebusec.ai \
--cc=fw@strlen.de \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
--cc=phil@nwl.cc \
--cc=root@tr0jan.top \
--cc=stable@vger.kernel.org \
--cc=vega@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