From: Yu Junzhe <junzheyu1@gmail.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>, Florian Westphal <fw@strlen.de>
Cc: netfilter-devel@vger.kernel.org, coreteam@netfilter.org
Subject: [BUG] netfilter: nf_tables_netdev_event UAF of JUMP binding chain
Date: Thu, 24 Sep 2026 06:38:21 +0000 [thread overview]
Message-ID: <20260924063821.573-1-junzheyu1@gmail.com> (raw)
Hello,
I am reporting a slab use-after-free in nf_tables_netdev_event(): deleting
a netdev hooked by an nftables ingress base chain can free a binding-chain
successor while the notifier is still walking table->chains. Triggering it
requires CAP_NET_ADMIN (including in a network namespace). I do not claim
privilege escalation; the result we see is local DoS (KASAN slab UAF read).
Summary
=======
nf_tables_netdev_event() walks table->chains with list_for_each_entry_safe.
On NETDEV_UNREGISTER it releases the netdev ingress base chain. A JUMP to an
NFT_CHAIN_BINDING successor is deactivated (nft_chain_del + bound = false)
and then nft_immediate_destroy() kfree's that successor. The walker's saved
nr still points at the freed nft_chain, so the loop increment reads
chain->list.next.
The deactivate/destroy path:
__nft_release_basechain_now()
-> nft_rule_expr_deactivate(..., NFT_TRANS_RELEASE)
-> nft_immediate_deactivate(): nft_chain_del(chain); chain->bound = false;
-> nft_immediate_destroy(): nf_tables_chain_destroy() when !chain->bound
list_for_each_entry_safe only protects deleting the current entry, not a
sibling freed inside the loop body.
Affected
========
- Confirmed on Linux 6.6.144, KASAN guest.
- Files: net/netfilter/nft_chain_filter.c, net/netfilter/nft_immediate.c,
net/netfilter/nf_tables_api.c
- Config: CONFIG_NF_TABLES=y, CONFIG_NF_TABLES_NETDEV=y, CONFIG_BRIDGE=y
(KASAN used for the report)
- Source review of torvalds/linux master as of 2026-09-18:
nft_immediate_deactivate() still unlinks binding chains on NFT_TRANS_RELEASE
and nft_immediate_destroy() still destroys them when !chain->bound.
__nft_release_basechain() is gone from nf_tables_api.c and the notifier
only unregisters hooks on tip, so this PoC's live RTM_DELLINK trigger was
not re-run on tip.
Ruleset that triggers it
========================
table netdev t {
chain in {
type filter hook ingress device "br0" priority 0;
jump j
}
chain j {
flags binding;
}
}
Create br0 in a network namespace, load the ruleset, then RTM_DELLINK br0
while the namespace is still alive (NETDEV_UNREGISTER). Netns teardown alone
is too late: nft pernet exit wins that race.
Crash excerpt (minimized PoC, Linux 6.6.144 KASAN)
==================================================
BUG: KASAN: slab-use-after-free in nf_tables_netdev_event+0x699/0x7d0
Read of size 8 at addr ff11000009aefd20 by task repro/220
CPU: 0 PID: 220 Comm: repro Not tainted 6.6.144 #1
Call Trace:
kasan_report
nf_tables_netdev_event+0x699/0x7d0
notifier_call_chain
unregister_netdevice_many_notify
rtnl_dellink
rtnetlink_rcv_msg
Allocated by task 220:
nf_tables_addchain
nf_tables_newchain
Freed by task 220:
nf_tables_chain_destroy
nft_immediate_destroy
__nft_release_basechain_now
__nft_release_basechain
nf_tables_netdev_event+0x63a/0x7d0
The KASAN read is 8 bytes at offset 32 of a kmalloc-128 object (nft_chain.list).
Reproducer
==========
A self-contained C PoC (raw NETLINK_NETFILTER batch plus RTM_NEWLINK/
RTM_DELLINK, no nft binary) and a Docker/QEMU package are available on
request. VM-only: the program triggers a guest KASAN UAF. 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>
next reply other threads:[~2026-09-24 6:38 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 6:38 Yu Junzhe [this message]
2026-09-24 7:05 ` [BUG] netfilter: nf_tables_netdev_event UAF of JUMP binding chain Florian Westphal
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=20260924063821.573-1-junzheyu1@gmail.com \
--to=junzheyu1@gmail.com \
--cc=coreteam@netfilter.org \
--cc=fw@strlen.de \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
/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.