All of lore.kernel.org
 help / color / mirror / Atom feed
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>

             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.