All of lore.kernel.org
 help / color / mirror / Atom feed
* [BUG] netfilter: unbounded nftables reject recursion on inet OUTPUT
@ 2026-09-21  6:13 Yu Junzhe
  2026-09-21  9:28 ` Florian Westphal
  0 siblings, 1 reply; 3+ messages in thread
From: Yu Junzhe @ 2026-09-21  6:13 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal; +Cc: netfilter-devel, coreteam

Hello,

I am reporting unbounded hook recursion on inet OUTPUT: an nftables
output chain that does a TCP flags payload-set followed by
"reject with tcp reset" makes nf_send_reset() re-enter the same
NF_INET_LOCAL_OUT hook until the kernel stack is exhausted.

Summary
=======

nft_reject_inet_eval() calls nf_send_reset(), which builds a RST skb
and transmits it with ip_local_out(). That walks the same OUTPUT
hooks again.

The only loop guard in nf_reject_ip_tcphdr_get() is the packet-content
check:

  /* No RST for RST. */
  if (oth->rst)
          return NULL;

If a payload-set runs first and rewrites the TCP flags byte to SYN,
that guard never sees RST, so another RST is generated. The cycle is:

  nft_do_chain
    -> nft_reject_inet_eval
      -> nf_send_reset
        -> ip_local_out
          -> nf_hook_slow
            -> nft_do_chain

nft_reject_inet_validate() allows NF_INET_LOCAL_OUT.

This is a legal nftables configuration (payload set + reject with tcp
reset on an output base chain), including with CAP_NET_ADMIN in a
network namespace. I do not claim privilege escalation; the result we
see is local DoS (stack overflow, then panic).

I am aware of the existing recursion bound on the netdev fwd/neigh
xmit path. nf_send_reset() via ip_local_out() does not use it.

Affected
========

- Confirmed on Linux 6.6.144, KASAN guest (CONFIG_VMAP_STACK not set).
  On that config the overflowing SP walks into adjacent slab; KASAN
  first reports a write in __unwind_start while tracking __alloc_skb
  from the next RST. Those frames are collateral. The defect is
  unbounded hook recursion.
- Source review of torvalds/linux master as of 2026-09-21:
  nf_send_reset() still calls ip_local_out(); the only loop guard is
  still if (oth->rst); nft_reject_inet_validate() still allows
  NF_INET_LOCAL_OUT. The PoC was not re-run on tip.
- Files: net/ipv4/netfilter/nf_reject_ipv4.c,
  net/netfilter/nft_reject_inet.c
- Config: CONFIG_NF_TABLES=y, CONFIG_NF_TABLES_INET=y,
  CONFIG_NFT_REJECT_INET=y (KASAN used for the report)

Ruleset that triggers it
========================

  table inet t {
          chain out {
                  type filter hook output priority 0;
                  tcp flags set syn
                  reject with tcp reset
          }
  }

Then connect() to 127.0.0.1 in that netns (a SYN on lo).

Crash excerpt (minimized PoC, Linux 6.6.144 KASAN)
==================================================

BUG: KASAN: use-after-free in __unwind_start+0x36/0x840
Write of size 112 at addr ff1100000659ff88 by task repro/221
CPU: 1 PID: 221 Comm: repro Not tainted 6.6.144 #1
Call Trace:
  __alloc_skb
  nf_send_reset
  nft_reject_inet_eval
  nft_do_chain
  nft_do_chain_inet
  nf_hook_slow
  __ip_local_out
  ip_local_out
  nf_send_reset
  nft_reject_inet_eval
  nft_do_chain
  ... (repeats until stack exhaustion; then GPF / panic)

Reproducer
==========

A self-contained C PoC (raw NETLINK_NETFILTER batch, no nft binary)
and a Docker/QEMU package are available on request. VM-only: the
program overflows the guest kernel stack. Please do not run it on a
host kernel.

I am happy to test patches or send the reproducer.

Thanks,
Yu Junzhe
FuzzAnything <fuzzanything@gmail.com>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [BUG] netfilter: unbounded nftables reject recursion on inet OUTPUT
  2026-09-21  6:13 [BUG] netfilter: unbounded nftables reject recursion on inet OUTPUT Yu Junzhe
@ 2026-09-21  9:28 ` Florian Westphal
  2026-09-21 10:32   ` Fernando Fernandez Mancera
  0 siblings, 1 reply; 3+ messages in thread
From: Florian Westphal @ 2026-09-21  9:28 UTC (permalink / raw)
  To: Yu Junzhe; +Cc: Pablo Neira Ayuso, netfilter-devel, coreteam

Yu Junzhe <junzheyu1@gmail.com> wrote:
> I am reporting unbounded hook recursion on inet OUTPUT: an nftables
> output chain that does a TCP flags payload-set followed by
> "reject with tcp reset" makes nf_send_reset() re-enter the same
> NF_INET_LOCAL_OUT hook until the kernel stack is exhausted.
>
> Summary
> =======
> 
> nft_reject_inet_eval() calls nf_send_reset(), which builds a RST skb
> and transmits it with ip_local_out(). That walks the same OUTPUT
> hooks again.

Can you send us a patch for this?

> The only loop guard in nf_reject_ip_tcphdr_get() is the packet-content
> check:
> 
>   /* No RST for RST. */
>   if (oth->rst)
>           return NULL;
> 
> If a payload-set runs first and rewrites the TCP flags byte to SYN,
> that guard never sees RST, so another RST is generated. The cycle is:
> 
>   nft_do_chain
>     -> nft_reject_inet_eval
>       -> nf_send_reset
>         -> ip_local_out
>           -> nf_hook_slow
>             -> nft_do_chain
> 
> nft_reject_inet_validate() allows NF_INET_LOCAL_OUT.
> 
> This is a legal nftables configuration (payload set + reject with tcp
> reset on an output base chain), including with CAP_NET_ADMIN in a
> network namespace. I do not claim privilege escalation; the result we
> see is local DoS (stack overflow, then panic).
> 
> I am aware of the existing recursion bound on the netdev fwd/neigh
> xmit path. nf_send_reset() via ip_local_out() does not use it.

Tell your coding assistant to move it to include/net/netfilter/nf_recursion.h,
add that include to the existing users, then extend all reset functions
(icmp and tcp reset) to use those helpers.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [BUG] netfilter: unbounded nftables reject recursion on inet OUTPUT
  2026-09-21  9:28 ` Florian Westphal
@ 2026-09-21 10:32   ` Fernando Fernandez Mancera
  0 siblings, 0 replies; 3+ messages in thread
From: Fernando Fernandez Mancera @ 2026-09-21 10:32 UTC (permalink / raw)
  To: Florian Westphal, Yu Junzhe; +Cc: Pablo Neira Ayuso, netfilter-devel, coreteam

On 9/21/26 11:28 AM, Florian Westphal wrote:
> Yu Junzhe <junzheyu1@gmail.com> wrote:
>> I am reporting unbounded hook recursion on inet OUTPUT: an nftables
>> output chain that does a TCP flags payload-set followed by
>> "reject with tcp reset" makes nf_send_reset() re-enter the same
>> NF_INET_LOCAL_OUT hook until the kernel stack is exhausted.
>>
>> Summary
>> =======
>>
>> nft_reject_inet_eval() calls nf_send_reset(), which builds a RST skb
>> and transmits it with ip_local_out(). That walks the same OUTPUT
>> hooks again.
> 
> Can you send us a patch for this?

Hi! Sorry, I have a patch for this already. So no need to do overlap 
work, will send it shortly.

Thanks for the report, I manage to trigger this easily.

> 
>> The only loop guard in nf_reject_ip_tcphdr_get() is the packet-content
>> check:
>>
>>    /* No RST for RST. */
>>    if (oth->rst)
>>            return NULL;
>>
>> If a payload-set runs first and rewrites the TCP flags byte to SYN,
>> that guard never sees RST, so another RST is generated. The cycle is:
>>
>>    nft_do_chain
>>      -> nft_reject_inet_eval
>>        -> nf_send_reset
>>          -> ip_local_out
>>            -> nf_hook_slow
>>              -> nft_do_chain
>>
>> nft_reject_inet_validate() allows NF_INET_LOCAL_OUT.
>>
>> This is a legal nftables configuration (payload set + reject with tcp
>> reset on an output base chain), including with CAP_NET_ADMIN in a
>> network namespace. I do not claim privilege escalation; the result we
>> see is local DoS (stack overflow, then panic).
>>
>> I am aware of the existing recursion bound on the netdev fwd/neigh
>> xmit path. nf_send_reset() via ip_local_out() does not use it.
> 
> Tell your coding assistant to move it to include/net/netfilter/nf_recursion.h,
> add that include to the existing users, then extend all reset functions
> (icmp and tcp reset) to use those helpers.
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-21 10:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-21  6:13 [BUG] netfilter: unbounded nftables reject recursion on inet OUTPUT Yu Junzhe
2026-09-21  9:28 ` Florian Westphal
2026-09-21 10:32   ` Fernando Fernandez Mancera

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.