// https://syzkaller.appspot.com/bug?id=65192f83eca6269573e333029a80de2d5ec0f400 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SETUP_UNBUFFERED_IO() setvbuf(stdout, NULL, _IONBF, 0) static inline double timer_elapsed_sec(struct timespec* start) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return (double)(now.tv_sec - start->tv_sec) + (double)(now.tv_nsec - start->tv_nsec) / 1e9; } #define TIMER_START(t) \ struct timespec t; \ clock_gettime(CLOCK_MONOTONIC, &t); #define TIMER_NOT_EXPIRED(t, sec) (timer_elapsed_sec(&(t)) < (double)(sec)) int uinput_fd; volatile int stop = 0; void *input_thread(void *arg) { struct input_event ev[2]; memset(ev, 0, sizeof(ev)); while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) { ev[0].type = EV_KEY; ev[0].code = KEY_SCROLLLOCK; ev[0].value = 1; // press ev[1].type = EV_SYN; ev[1].code = SYN_REPORT; ev[1].value = 0; if (write(uinput_fd, ev, sizeof(ev)) < 0) { // Ignore errors in loop } ev[0].value = 0; // release if (write(uinput_fd, ev, sizeof(ev)) < 0) { // Ignore errors in loop } } return NULL; } void *tty_thread(void *arg) { while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) { int fd = open("/dev/tty63", O_RDWR); if (fd >= 0) { close(fd); } } return NULL; } int main() { SETUP_UNBUFFERED_IO(); int tty_fd = open("/dev/tty63", O_RDWR); if (tty_fd < 0) { printf("[-] Failed to open /dev/tty63: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully opened /dev/tty63.\n"); // Map KEY_SCROLLLOCK to K_HOLD across all shift states for (int i = 0; i < 256; i++) { struct kbentry ke; ke.kb_table = i; ke.kb_index = KEY_SCROLLLOCK; // 70 ke.kb_value = 0x0209; // K_HOLD (K(KT_SPEC, 9)) if (ioctl(tty_fd, KDSKBENT, &ke) < 0) { // Some tables might not exist or be modifiable, just continue } } printf("[+] Successfully mapped KEY_SCROLLLOCK to K_HOLD.\n"); // Switch foreground console to VT 63 to route keyboard events here if (ioctl(tty_fd, VT_ACTIVATE, 63) < 0) { printf("[-] Failed to VT_ACTIVATE: %s\n", strerror(errno)); } else { printf("[+] Successfully activated VT 63.\n"); } if (ioctl(tty_fd, VT_WAITACTIVE, 63) < 0) { printf("[-] Failed to VT_WAITACTIVE: %s\n", strerror(errno)); } else { printf("[+] Successfully waited for VT 63.\n"); } close(tty_fd); uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if (uinput_fd < 0) { printf("[-] Failed to open /dev/uinput: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully opened /dev/uinput.\n"); if (ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY) < 0) { printf("[-] Failed to ioctl UI_SET_EVBIT: %s\n", strerror(errno)); exit(1); } if (ioctl(uinput_fd, UI_SET_KEYBIT, KEY_SCROLLLOCK) < 0) { printf("[-] Failed to ioctl UI_SET_KEYBIT: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully configured uinput bits.\n"); struct uinput_user_dev uidev; memset(&uidev, 0, sizeof(uidev)); snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "syz-repro"); uidev.id.bustype = BUS_USB; uidev.id.vendor = 0x1234; uidev.id.product = 0x5678; uidev.id.version = 1; if (write(uinput_fd, &uidev, sizeof(uidev)) < 0) { printf("[-] Failed to write uinput_user_dev: %s\n", strerror(errno)); exit(1); } if (ioctl(uinput_fd, UI_DEV_CREATE) < 0) { printf("[-] Failed to ioctl UI_DEV_CREATE: %s\n", strerror(errno)); exit(1); } printf("[+] Successfully created uinput device.\n"); // Launch multiple threads to increase race probability pthread_t t1[4], t2[4]; for (int i = 0; i < 4; i++) { if (pthread_create(&t1[i], NULL, input_thread, NULL) != 0) { printf("[-] Failed to create input_thread\n"); exit(1); } if (pthread_create(&t2[i], NULL, tty_thread, NULL) != 0) { printf("[-] Failed to create tty_thread\n"); exit(1); } } printf("[+] Successfully started threads. Racing for 10 seconds...\n"); TIMER_START(start); while (TIMER_NOT_EXPIRED(start, 10.0)) { usleep(100000); } __atomic_store_n(&stop, 1, __ATOMIC_RELAXED); for (int i = 0; i < 4; i++) { pthread_join(t1[i], NULL); pthread_join(t2[i], NULL); } printf("[+] Successfully joined threads.\n"); ioctl(uinput_fd, UI_DEV_DESTROY); close(uinput_fd); printf("[+] Done.\n"); return 0; }