Thread (6 messages) flat view 6 messages, 2 authors, 2d ago

Re: [PATCH nf 1/1] netfilter: nf_dup: prevent asynchronous duplicate recursion

From: zihan xi <hidden>
Date: 2026-08-29 12:21:00
Also in: lkml, netfilter-devel, stable

On Sat, Aug 29, 2026 at 5:27 PM Florian Westphal [off-list ref] wrote:
Zihan Xi [off-list ref] wrote:
quoted
nf_dup_ipv4() and nf_dup_ipv6() use current->in_nf_duplicate to keep
duplicated packets from being duplicated again while ip_local_out() or
ip6_local_out() walks netfilter hooks. The task flag is cleared as soon
as the output function returns.

NFQUEUE can retain a duplicate and return from the output hook. A later
NF_ACCEPT verdict resumes the same skb at the following hook from the
verdict task, after in_nf_duplicate has been cleared. A later TEE target
or dup expression can then duplicate it again. With an earlier queue
hook and a later duplication hook, one packet can sustain an unbounded
packet generation loop.

Record the duplication state in the cloned skb as well as the task. The
skb flag survives queuing, reinjection, and skb metadata copies, so an
asynchronously resumed duplicate cannot enter either IPv4 or IPv6
duplication helper again. Copy the flag through nf_copy() so fragments
retain the same state. Keep the task flag for the nested xtables jumpstack.
Not sure about this one.  I think this is a case of "behaves as
intended", you get oops because you *ask* the kernel to oops.

I think there are a great many other ways to OOM the kernel,
outside of dup/TEE/nfqueue.

IFF we prented that this is a real problem, then I would
prefer to solve this in nf_dup, not involving sk_buff changes.

I cannot see a sensible use case for nf_dup outside of
physical hardware (sending packets to some external
packet logging machine for instance).

So. I think a better solution would be to either disable
dup in user namespaces entirely, or, restore the "old" behaviour
of passing the clone directly (no reentry) if we were configured
from user namespace.
Hi Florian,

Thanks for the review and for outlining the two possible directions.

I take your suggestion to mean that, if we decide this is worth addressing, the
fix should stay within nf_dup rather than add state to struct sk_buff. Before
deciding whether to pursue a patch, I rechecked the practical impact.

The current reproducer intentionally drives the system into OOM, and this is
not a memory-corruption issue. An unprivileged trigger requires user and
network namespaces, NFQUEUE, TEE/dup support, and a userspace verdict service.
CAP_NET_ADMIN is available in the child network namespace when user namespaces
are enabled. However, vm.panic_on_oom is global and cannot be enabled by the
child namespace. With the normal panic_on_oom=0 setting, the demonstrated effect
is resource pressure and possible OOM-killer activity, rather than a direct
kernel panic. I have not demonstrated privilege escalation or a memory-safety
impact.

The crash log in the cover letter came from a separate root validation run with
panic_on_oom=1. It should not be taken as evidence that an unprivileged user can
directly panic the host.

Based on this reassessment, I do not think the original struct sk_buff guard
series is justified. My current preference is therefore to withdraw that
series, unless you think a defense-in-depth change is still desirable.

If you do prefer to keep a small nf_dup-only change, I can prepare either:

1. disable IPv4/IPv6 dup in network namespaces owned by a non-initial user
   namespace; or
2. restore the historical direct ip_output()/ip6_output() path there.

The second option preserves one duplicate but bypasses the clone's LOCAL_OUT and
POST_ROUTING netfilter processing, so it changes observable semantics. The
first option removes dup/TEE functionality in those namespaces but avoids that
hook bypass.

Please let me know whether you prefer that I withdraw the series or prepare one
of these defense-in-depth changes. I will hold off on sending a v2 of the
struct sk_buff-field patch until then.

Best regards,
Zihan Xi
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help