# CVE-2021-22555: Turning \x00\x00 into 10000$

15-year-old Netfilter compat-mode memset OOB write in xt_compat_target_from_user yields kernel UAF, KASLR/SMEP/SMAP bypass, root and container escape.

- Payout: $10,000
- Severity: high
- Program: Google
- Credited: Andy Nguyen
- Disclosed: 2021-07-07
- CVE: CVE-2021-22555
- Write-up quality: 10/10
- Original: https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html
- Library page: https://bugbountylibrary.com/r/blog%3Agoogle-github-io-security-research-pocs-linux-cve-2021-22555-writeup-html
- Tags: domain:desktop impact:internal-access impact:privesc impact:rce kind:bounty platform:blog sev:high tech:linux technique:chained technique:source-review vuln:memory-corruption vuln:privilege-escalation

**Target:** Linux Netfilter setsockopt IPT_SO_SET_REPLACE compat translation (net/netfilter/x_tables.c)
**Root cause:** xt_compat_target_from_user() calls memset(t->data + target->targetsize, 0, pad) where targetsize is not accounted for in the allocation, writing up to 0x4C zero bytes past the xt_table_info buffer.
**Steps:**
1. Unshare user+net namespace to gain CAP_NET_ADMIN.
2. Spray 4096 msg queues with 4096-byte primary messages, then 1024-byte secondary messages, each tagged with queue index.
3. Create holes every 1024th primary message.
4. Trigger setsockopt(IPT_SO_SET_REPLACE) with NFLOG target and padding to place xt_table_info in a hole and zero 2 bytes of adjacent primary msg's next pointer.
5. Use msgrcv MSG_COPY to find mismatched tags identifying fake/real queue indices.
6. Free real secondary via msgrcv, reclaim with unix-socket sk_buff fake msg_msg (m_ts enlarged) to leak adjacent msg headers and heap addresses.
7. Rebuild fake msg_msg with self-pointing mlist, free it, reclaim with pipe_buffer to leak anon_pipe_buf_ops and compute kbase.
8. Reclaim with fake pipe_buffer whose ops points to fake pipe_buf_operations with release = stack pivot gadget; close pipes to run ROP: commit_creds(prepare_kernel_cred(NULL)), switch_task_namespaces(find_task_by_vpid(1), init_nsproxy).
9. setns into /proc/1/ns/{mnt,pid,net} and execve /bin/bash.
**How found:** Inspired by CVE-2016-3134/4997, grepped memcpy/memset in Netfilter code; found targetsize not accounted in allocation. Noticed unreliable victim allocation due to GFP_KERNEL_ACCOUNT separate slabs pre-5.9 (confirmed by Jann Horn), leading to msgsnd/msg_msg as spray primitive; Jann Horn suggested pipe_buffer as victim.
**Exploitation:** Requires CAP_NET_ADMIN via user+net namespace. OOB zero write corrupts msg_msg mlist.next to create two primaries referencing one secondary, giving UAF. Fake msg_msg via unix socket sk_buff leaks heap and KASLR, then fake pipe_buffer ops->release pivots to kernel ROP installing root creds and switching namespaces, escaping the kCTF pod.
**Escalation:** Chained OOB write -> msg_msg UAF -> info leak (SMAP/KASLR bypass) -> pipe_buffer UAF -> kernel ROP -> namespace switch -> container escape and root shell.
**Insight:** When a heap primitive is GFP_KERNEL_ACCOUNT, all spray/victim objects must share that flag or they land in separate slabs pre-5.9; msg_msg's mlist.next is a prime corruption target for turning a small OOB zero into a UAF, and pipe_buffer.ops leaks kernel base via anon_pipe_buf_ops.
