// https://syzkaller.appspot.com/bug?id=8d5962eb786ecb9cded9906aad76fa06f81b067f #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void move_all_procs_to_cpu0(void) { DIR *dir = opendir("/proc"); if (!dir) return; struct dirent *ent; while ((ent = readdir(dir)) != NULL) { if (isdigit(ent->d_name[0])) { int pid = atoi(ent->d_name); if (pid == getpid()) continue; cpu_set_t set; CPU_ZERO(&set); CPU_SET(0, &set); sched_setaffinity(pid, sizeof(set), &set); // Ignore errors for pinned threads } } closedir(dir); } volatile int spinner_ready = 0; void *spinner_thread(void *arg) { long cpu = (long)arg; cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(cpu, &cpuset); if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) < 0) { printf("[-] Failed to sched_setaffinity for CPU %ld: %s\n", cpu, strerror(errno)); exit(1); } printf("[+] sched_setaffinity for CPU %ld successful.\n", cpu); struct sched_param param; param.sched_priority = 98; if (sched_setscheduler(0, SCHED_FIFO, ¶m) < 0) { printf("[-] Failed to sched_setscheduler SCHED_FIFO for CPU %ld: %s\n", cpu, strerror(errno)); exit(1); } printf("[+] sched_setscheduler SCHED_FIFO for CPU %ld successful.\n", cpu); spinner_ready = 1; printf("[+] Spinner on CPU %ld entering infinite loop.\n", cpu); while (1) { int msqid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); if (msqid >= 0) { msgctl(msqid, IPC_RMID, NULL); } } return NULL; } int main() { long ncpus = sysconf(_SC_NPROCESSORS_ONLN); if (ncpus < 1) { printf("[-] Failed to get number of CPUs\n"); exit(1); } printf("[+] sysconf _SC_NPROCESSORS_ONLN successful, %ld CPUs.\n", ncpus); int fd = open("/proc/sys/kernel/sched_rt_runtime_us", O_WRONLY); if (fd >= 0) { if (write(fd, "-1\n", 3) < 0) { printf("[-] Failed to write to sched_rt_runtime_us: %s\n", strerror(errno)); } else { printf("[+] write to sched_rt_runtime_us successful.\n"); } close(fd); } else { printf("[-] Failed to open sched_rt_runtime_us: %s\n", strerror(errno)); } fd = open("/proc/sys/kernel/hung_task_timeout_secs", O_WRONLY); if (fd >= 0) { if (write(fd, "10\n", 3) < 0) { printf("[-] Failed to write to hung_task_timeout_secs: %s\n", strerror(errno)); } else { printf("[+] write to hung_task_timeout_secs successful.\n"); } close(fd); } else { printf("[-] Failed to open hung_task_timeout_secs: %s\n", strerror(errno)); } sync(); printf("[+] sync successful.\n"); if (ncpus > 1) { move_all_procs_to_cpu0(); printf("[+] move_all_procs_to_cpu0 successful.\n"); } // Pin main thread to CPU 0 cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(0, &cpuset); if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) < 0) { printf("[-] Failed to sched_setaffinity for main thread: %s\n", strerror(errno)); exit(1); } printf("[+] sched_setaffinity for main thread successful.\n"); struct sched_param param; param.sched_priority = 99; if (sched_setscheduler(0, SCHED_FIFO, ¶m) < 0) { printf("[-] Failed to sched_setscheduler SCHED_FIFO for main thread: %s\n", strerror(errno)); exit(1); } printf("[+] sched_setscheduler SCHED_FIFO for main thread successful.\n"); long target_cpu = (ncpus > 1) ? 1 : 0; pthread_t thread; if (pthread_create(&thread, NULL, spinner_thread, (void *)target_cpu) != 0) { printf("[-] Failed to pthread_create spinner_thread: %s\n", strerror(errno)); exit(1); } printf("[+] pthread_create spinner_thread on CPU %ld successful.\n", target_cpu); while (!spinner_ready) { usleep(1000); } usleep(500000); /* 500ms delay to ensure spinner is spinning and queueing RCU callbacks */ int tun_fd = open("/dev/net/tun", O_RDWR); if (tun_fd < 0) { printf("[-] Failed to open /dev/net/tun: %s\n", strerror(errno)); exit(1); } printf("[+] open /dev/net/tun successful.\n"); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; strncpy(ifr.ifr_name, "tun0", IFNAMSIZ); if (ioctl(tun_fd, TUNSETIFF, (void *)&ifr) < 0) { printf("[-] Failed to ioctl TUNSETIFF: %s\n", strerror(errno)); exit(1); } printf("[+] ioctl TUNSETIFF successful.\n"); printf("[*] Trigger closing TUN fd to trigger unregister_netdevice...\n"); if (close(tun_fd) < 0) { printf("[-] Failed to close TUN fd: %s\n", strerror(errno)); exit(1); } printf("[+] close TUN fd successful.\n"); printf("[*] Main thread sleeping for 60 seconds to wait for khungtaskd...\n"); sleep(60); printf("[+] Reproducer finished.\n"); return 0; }