// https://syzkaller.appspot.com/bug?id=980a08699caf55e6401409c4b99dedfa5fe6350e #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include static volatile int running = 1; static volatile int racing = 0; static void write_file(const char *path, const char *val) { int fd = open(path, O_WRONLY); if (fd < 0) { printf("[-] Failed to open %s: %s\n", path, strerror(errno)); exit(1); } size_t len = strlen(val); ssize_t n = write(fd, val, len); if (n < 0) { printf("[-] Failed to write '%s' to %s: %s\n", val, path, strerror(errno)); close(fd); exit(1); } if ((size_t)n != len) { printf("[-] Incomplete write to %s: wrote %zd of %zu bytes\n", path, n, len); close(fd); exit(1); } int res = close(fd); if (res < 0) { printf("[-] Failed to close %s: %s\n", path, strerror(errno)); exit(1); } } static void *writer_thread(void *arg) { int id = (int)(intptr_t)arg; int fd = open("/sys/devices/system/machinecheck/machinecheck0/check_interval", O_WRONLY); if (fd < 0) { printf("[-] Writer %d failed to open check_interval: %s\n", id, strerror(errno)); exit(1); } printf("[+] Writer %d successfully opened check_interval.\n", id); int val = (id == 1) ? 1 : 2; char buf[4]; while (running) { while (!racing && running) { usleep(1000); } if (!running) break; while (racing) { val = (val == 1) ? 2 : 1; buf[0] = (char)('0' + val); buf[1] = '\n'; ssize_t ret = pwrite(fd, buf, 2, 0); if (ret < 0) { if (errno == EINTR) continue; printf("[-] Writer %d failed pwrite: %s\n", id, strerror(errno)); close(fd); exit(1); } if (ret != 2) { printf("[-] Writer %d unexpected pwrite return %zd\n", id, ret); close(fd); exit(1); } int yres = sched_yield(); if (yres < 0) { printf("[-] Writer %d failed sched_yield: %s\n", id, strerror(errno)); close(fd); exit(1); } } } int res = close(fd); if (res < 0) { printf("[-] Writer %d failed to close check_interval fd: %s\n", id, strerror(errno)); exit(1); } printf("[+] Writer %d closed check_interval fd.\n", id); return NULL; } int main(void) { setvbuf(stdout, NULL, _IONBF, 0); printf("[*] Starting reproducer for WARNING in mce_timer_fn...\n"); /* 1. Check number of configured CPUs */ long num_cpus = sysconf(_SC_NPROCESSORS_CONF); if (num_cpus < 2) { printf("[-] Insufficient CPUs: found %ld, need at least 2 for CPU hotplug\n", num_cpus); exit(1); } printf("[+] Detected %ld configured CPUs.\n", num_cpus); /* 2. Verify interfaces exist and are writable */ int fd_test = open("/sys/devices/system/cpu/cpu1/online", O_WRONLY); if (fd_test < 0) { printf("[-] Failed to open /sys/devices/system/cpu/cpu1/online for writing: %s\n", strerror(errno)); exit(1); } int res = close(fd_test); if (res < 0) { printf("[-] Failed to close cpu1/online test fd: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully verified /sys/devices/system/cpu/cpu1/online writable.\n"); fd_test = open("/sys/devices/system/machinecheck/machinecheck0/check_interval", O_WRONLY); if (fd_test < 0) { printf("[-] Failed to open /sys/devices/system/machinecheck/machinecheck0/check_interval for writing: %s\n", strerror(errno)); exit(1); } res = close(fd_test); if (res < 0) { printf("[-] Failed to close check_interval test fd: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully verified /sys/devices/system/machinecheck/machinecheck0/check_interval writable.\n"); /* 3. Initial setup */ printf("[*] Initializing check_interval to 10...\n"); write_file("/sys/devices/system/machinecheck/machinecheck0/check_interval", "10\n"); printf("[+] check_interval initialized to 10 successfully.\n"); printf("[*] Ensuring CPU 1 is initially online...\n"); write_file("/sys/devices/system/cpu/cpu1/online", "1\n"); printf("[+] CPU 1 online initialization successful.\n"); usleep(100000); /* 4. Start writer threads */ pthread_t tid1, tid2; res = pthread_create(&tid1, NULL, writer_thread, (void *)(intptr_t)1); if (res != 0) { printf("[-] Failed to create writer thread 1: %s\n", strerror(res)); exit(1); } printf("[+] Created writer thread 1 successfully.\n"); res = pthread_create(&tid2, NULL, writer_thread, (void *)(intptr_t)2); if (res != 0) { printf("[-] Failed to create writer thread 2: %s\n", strerror(res)); exit(1); } printf("[+] Created writer thread 2 successfully.\n"); /* 5. Hotplug racing loop */ int max_iterations = 30; for (int iter = 1; iter <= max_iterations; iter++) { printf("[*] === Iteration %d / %d ===\n", iter, max_iterations); /* Step A: Bring CPU 1 online */ write_file("/sys/devices/system/cpu/cpu1/online", "1\n"); printf("[+] Iteration %d: CPU 1 brought online.\n", iter); /* Step B: Allow CPU 1 to settle and arm timers */ usleep(50000); /* Step C: Enable high-frequency racing before triggering teardown */ racing = 1; usleep(1000); /* Step D: Offline CPU 1 while writer threads hammer check_interval */ printf("[*] Iteration %d: Offlining CPU 1...\n", iter); write_file("/sys/devices/system/cpu/cpu1/online", "0\n"); printf("[+] Iteration %d: CPU 1 offlined successfully.\n", iter); /* Step E: Disable racing to give CPU 0 time to handle timer softirqs */ racing = 0; /* Step F: Wait 3 seconds for the migrated MCE timer to fire on CPU 0 */ printf("[*] Iteration %d: Waiting 3s for migrated timer to fire on CPU 0...\n", iter); sleep(3); } /* 6. Clean up */ printf("[*] Finished all iterations. Stopping writer threads...\n"); running = 0; res = pthread_join(tid1, NULL); if (res != 0) { printf("[-] Failed to join writer thread 1: %s\n", strerror(res)); exit(1); } printf("[+] Writer thread 1 joined.\n"); res = pthread_join(tid2, NULL); if (res != 0) { printf("[-] Failed to join writer thread 2: %s\n", strerror(res)); exit(1); } printf("[+] Writer thread 2 joined.\n"); /* Restore CPU 1 online */ write_file("/sys/devices/system/cpu/cpu1/online", "1\n"); printf("[+] Restored CPU 1 online.\n"); printf("[+] Reproducer finished.\n"); return 0; }