Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 214 additions & 0 deletions pocs/linux/kernelctf/CVE-2026-23231_cos/docs/exploit.md

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions pocs/linux/kernelctf/CVE-2026-23231_cos/docs/vulnerability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Vulnerability: Use-After-Free in nf_tables_addchain() Error Path (CVE-2026-23231)

## Summary

A use-after-free vulnerability exists in the netfilter `nf_tables` subsystem, specifically in the error path of `nf_tables_addchain()`. If hook registration fails after the chain has been published, the error path calls `nft_chain_del()` and then immediately calls `nf_tables_chain_destroy()` without an intervening `synchronize_rcu()`.

This violates the RCU publish/grace-period/free contract and creates two separate UAF conditions covered by CVE-2026-23231:

- **Control-plane UAF**: `nf_tables_dump_chains()` traverses `table->chains` under `rcu_read_lock()`, so a concurrent dump can still walk the chain after it has been removed with `list_del_rcu()` but before readers quiesce.
- **Packet-path UAF**: for `NFPROTO_INET`, `nf_register_net_hook()` can briefly install the IPv4 hook before IPv6 registration fails. Packets entering `nft_do_chain()` through that transient IPv4 hook can still dereference `chain->blob_gen_X` after the chain has been freed.

The exploit in this submission uses the second condition: partial `NFPROTO_INET` hook registration failure caused by exhausting IPv6 `LOCAL_OUT` hooks.

## Affected Component

- **Subsystem**: netfilter / nf_tables
- **Source file**: `net/netfilter/nf_tables_api.c`
- **Function**: `nf_tables_addchain()`

## Vulnerability Type

- **Cause**: Use-After-Free (UAF) due to missing RCU grace period
- **Root cause**: `nf_tables_addchain()` frees the chain immediately after `list_del_rcu()` on the hook-registration failure path, allowing concurrent RCU readers to observe freed memory

## Requirements to Trigger

- **User namespaces**: Not required for the bug in general, but required for this exploit so an unprivileged user can create a network namespace and gain `CAP_NET_ADMIN` inside it.
- **Capabilities**: `CAP_NET_ADMIN` (inside the attacker's network namespace for this exploit)
- **Kernel configuration**: `CONFIG_NF_TABLES`, `CONFIG_NF_TABLES_INET`
- **Other**: Ability to saturate IPv6 hooks to `MAX_HOOK_COUNT` (1024) to force the IPv6 hook registration failure

## Commit Which Introduced the Vulnerability

- **Commit**: [`91c7b38dc9f0`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=91c7b38dc9f0de4f7f444b796d14476bc12df7bc) ("netfilter: nf_tables: use new transaction infrastructure to handle chain")
- This commit introduced the transaction-based chain handling and the vulnerable teardown path that removes a chain with `list_del_rcu()` and then frees it without waiting for an RCU grace period when hook registration fails.

## Commit Which Fixed the Vulnerability

- **Fix**: Add `synchronize_rcu()` between `nft_chain_del()` and `nf_tables_chain_destroy()` in the `err_register_hook` error path of `nf_tables_addchain()`.
- **Patch commit**: [`71e99ee20fc3`](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=71e99ee20fc3f662555118cf1159443250647533) ("netfilter: nf_tables: fix use-after-free in nf_tables_addchain()")

## Affected Kernel Versions

- **Introduced in**: 3.16 (when `91c7b38dc9f0` first shipped)
- **Affected stable ranges**: 3.16 - 6.1.164, 6.2 - 6.6.127, 6.7 - 6.12.74, 6.13 - 6.18.13, and 6.19 - 6.19.3
- **Fixed in**: 6.1.165, 6.6.128, 6.12.75, 6.18.14, 6.19.4, and mainline 7.0-rc1

## Blocking the Vulnerability

The vulnerability can be prevented by any of the following:

- **Disabling user namespaces** (`kernel.unprivileged_userns_clone=0` or equivalent) prevents this exploit path from obtaining `CAP_NET_ADMIN` in a private network namespace.
- **Blocking `NETLINK_NETFILTER` socket creation** from unprivileged contexts.
- **Disabling nf_tables support** (`CONFIG_NF_TABLES=n`) or, more narrowly, disabling INET chains (`CONFIG_NF_TABLES_INET=n`).
- **Limiting `nf_tables` access** via security modules (e.g., SELinux, AppArmor policies denying netfilter configuration).

## KASAN Report

```
BUG: KASAN: use-after-free in nft_do_chain+0x1214/0x12a0
Read of size 8 at addr ffff888103ef0b00 by task init/76
...
Allocated by task 77:
nf_tables_addchain.constprop.0+0x8f9/0x1f80
Freed by task 77:
nf_tables_chain_destroy+0xb8/0x530
nf_tables_addchain.constprop.0+0xe6f/0x1f80
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# kernelCTF exploit build for cos-113-18244.521.88
#
# Default target builds the kernelXDK-integrated version (exploit_xdk.cpp).
# Use 'make exploit_original' for the original C version (exploit.c).

KERNELXDK_INCLUDE_DIR ?=
KERNELXDK_LIB_DIR ?=

CXX ?= g++
CC ?= gcc
CXXFLAGS := -g -std=c++20 -I. -static -O2 -Wall -pthread
CFLAGS := -g -static -O2 -Wall -pthread

ifneq ($(strip $(KERNELXDK_INCLUDE_DIR)),)
CXXFLAGS += -I$(KERNELXDK_INCLUDE_DIR)
endif

LDFLAGS := -lkernelXDK -pthread
ifneq ($(strip $(KERNELXDK_LIB_DIR)),)
LDFLAGS := -L$(KERNELXDK_LIB_DIR) $(LDFLAGS)
endif

.PHONY: all prerequisites run clean

all: exploit

prerequisites: target_db.kxdb

# Download kernelXDK target database if not present
target_db.kxdb:
wget -q -O $@ https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb

# kernelXDK-integrated version (C++)
exploit: exploit_xdk.cpp target_db.kxdb
$(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS)

# Original C version (does not require kernelXDK)
exploit_original: exploit.c
$(CC) $(CFLAGS) -o $@ $<

run: exploit
./exploit

clean:
rm -f exploit exploit_original target_db.kxdb
Binary file not shown.
Loading
Loading