cve-2026-43499.c (3883B)
1 /* 2 * CVE-2026-43499 — GhostLock 3 * 4 * A futex PI requeue race condition leading to a use-after-free in the 5 * kernel's futex subsystem. An unprivileged user can trigger a kernel 6 * stack UAF by racing FUTEX_WAIT_REQUEUE_PI against FUTEX_CMP_REQUEUE_PI 7 * when a PI-chain deadlock is present. 8 * 9 * WARNING — the actual race inherently corrupts kernel PI state on a 10 * vulnerable system, which has a high risk to cause a kernel panic. 11 * This detector therefore does NOT attempt the live exploit. Instead it 12 * checks the two known mitigations: 13 * 14 * 1. Kernel version >= 7.1 15 * 2. CONFIG_FUTEX_PI=n (probed via FUTEX_LOCK_PI returning -ENOSYS) 16 * 17 * If *both* checks indicate a vulnerable configuration the detector 18 * reports fail. It *may* report false positives if a backported fix is used. 19 */ 20 21 #define _GNU_SOURCE 22 #include <errno.h> 23 #include <linux/futex.h> 24 #include <stdint.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <sys/syscall.h> 28 #include <sys/utsname.h> 29 #include <unistd.h> 30 31 #include "setup.h" 32 33 /* ---- kernel version helpers ---- */ 34 struct kernel_version { 35 unsigned int major; 36 unsigned int minor; 37 unsigned int patch; 38 }; 39 40 static int parse_version(const char *r, struct kernel_version *kv) { 41 memset(kv, 0, sizeof(*kv)); 42 if (sscanf(r, "%u.%u.%u", &kv->major, &kv->minor, &kv->patch) < 2) 43 return -1; 44 return 0; 45 } 46 47 static int version_ge(const struct kernel_version *kv, 48 unsigned int major, unsigned int minor, unsigned int patch) { 49 if (kv->major > major) return 1; 50 if (kv->major < major) return 0; 51 if (kv->minor > minor) return 1; 52 if (kv->minor < minor) return 0; 53 return kv->patch >= patch; 54 } 55 56 /* ---- futex PI availability probe ---- */ 57 static int chk_futex_pi_available(void) { 58 uint32_t futex = 0; 59 long rc; 60 61 /* Try FUTEX_LOCK_PI — on a CONFIG_FUTEX_PI=n kernel this returns 62 * -ENOSYS. We lock-then-unlock so the futex is left at 0. */ 63 rc = syscall(SYS_futex, &futex, FUTEX_LOCK_PI, 0, 0, 0, 0); 64 if (rc == -1 && (errno == ENOSYS || errno == EINVAL)) 65 return 0; /* CONFIG_FUTEX_PI is off — safe */ 66 67 /* If we got the lock (rc == 0) or any other error, unlock to clean up. */ 68 if (rc == 0) 69 syscall(SYS_futex, &futex, FUTEX_UNLOCK_PI, 0, 0, 0, 0); 70 71 return 1; /* futex PI is available → potentially vulnerable */ 72 } 73 74 /* ---- detector ---- */ 75 int detector_cve_2026_43499(struct cve_context *ctx) { 76 struct kernel_version kv; 77 struct utsname uts; 78 int pi_on; 79 80 if (uname(&uts) < 0) { 81 /* Can't determine kernel version — assume safe */ 82 return 0; 83 } 84 85 if (parse_version(uts.release, &kv) < 0) { 86 /* Can't parse version — assume safe */ 87 return 0; 88 } 89 90 if (ctx->verbose) 91 fprintf(stderr, "[cve-2026-43499] kernel %u.%u.%u\n", 92 kv.major, kv.minor, kv.patch); 93 94 /* Mitigation 1: kernel >= 7.1 */ 95 if (version_ge(&kv, 7, 1, 0)) { 96 if (ctx->verbose) 97 fprintf(stderr, "[cve-2026-43499] kernel >= 7.1 — not vulnerable\n"); 98 return 0; 99 } 100 101 /* Mitigation 2: CONFIG_FUTEX_PI=n */ 102 pi_on = chk_futex_pi_available(); 103 if (!pi_on) { 104 if (ctx->verbose) 105 fprintf(stderr, "[cve-2026-43499] CONFIG_FUTEX_PI=n — not vulnerable\n"); 106 return 0; 107 } 108 109 /* Both mitigations are absent — system is likely vulnerable */ 110 if (ctx->verbose) 111 fprintf(stderr, 112 "[cve-2026-43499] kernel < 7.1 and CONFIG_FUTEX_PI=y — " 113 "vulnerable to GhostLock\n"); 114 115 return 1; 116 } 117 118 /* ---- constructor ---- */ 119 __attribute__((constructor)) 120 void detector_cve_2026_43499_setup(void) { 121 detector_queue_append( 122 "CVE-2026-43499", "GhostLock", 123 "Update the Linux kernel to >= 7.1 or apply CONFIG_FUTEX_PI=n.\n" 124 " This *may* be a false positive, testing has a high chance of causing kernel panics,\n" 125 " which the author has opted for not to risk.", 126 detector_cve_2026_43499); 127 }