// https://syzkaller.appspot.com/bug?id=fad611d7ddd914f0b4488742a63b93f31b321ca0 #include #include #include #include #include #include #include #include #include void do_mkdir(const char *path) { int res = mkdir(path, 0777); if (res < 0 && errno != EEXIST) { printf("[-] Failed to mkdir %s: %s\n", path, strerror(errno)); exit(1); } printf("[+] mkdir %s successful.\n", path); } void try_mkdir(const char *path) { int res = mkdir(path, 0777); if (res < 0 && errno != EEXIST) { printf("[-] Failed to mkdir %s: %s\n", path, strerror(errno)); } else { printf("[+] mkdir %s successful.\n", path); } } void do_rmdir(const char *path) { int res = rmdir(path); if (res < 0) { printf("[-] Failed to rmdir %s: %s\n", path, strerror(errno)); exit(1); } printf("[+] rmdir %s successful.\n", path); } int main(void) { setvbuf(stdout, NULL, _IONBF, 0); int res = mount("configfs", "/sys/kernel/config", "configfs", 0, NULL); if (res < 0 && errno != EBUSY) { printf("[-] Failed to mount configfs: %s\n", strerror(errno)); exit(1); } printf("[+] mount configfs successful.\n"); do_mkdir("/sys/kernel/config/usb_gadget/g1"); // 1. Record gadget_subsys.su_mutex -> opts->dep_lock try_mkdir("/sys/kernel/config/usb_gadget/g1/functions/tcm.0"); // 2. Record opts->dep_lock -> inode_lock // The target/usb_gadget fabric is auto-created when tcm_usb_gadget is loaded try_mkdir("/sys/kernel/config/target"); try_mkdir("/sys/kernel/config/target/usb_gadget"); try_mkdir("/sys/kernel/config/target/usb_gadget/naa.1234"); try_mkdir("/sys/kernel/config/target/usb_gadget/naa.1234/tpgt_1"); // 3. Record inode_lock -> frag_sem do_mkdir("/sys/kernel/config/usb_gadget/g1/configs/c.1"); do_rmdir("/sys/kernel/config/usb_gadget/g1/configs/c.1"); // 4. Record frag_sem -> gadget_subsys.su_mutex (Closes the cycle and triggers lockdep) do_mkdir("/sys/kernel/config/usb_gadget/g1/functions/uvc.0"); // streaming and uncompressed groups are created automatically by uvc.0 do_mkdir("/sys/kernel/config/usb_gadget/g1/functions/uvc.0/streaming/uncompressed/u"); do_mkdir("/sys/kernel/config/usb_gadget/g1/functions/uvc.0/streaming/uncompressed/u/f"); const char *attr_path = "/sys/kernel/config/usb_gadget/g1/functions/uvc.0/streaming/uncompressed/u/f/dwMaxVideoFrameBufferSize"; int fd = open(attr_path, O_WRONLY); if (fd < 0) { printf("[-] Failed to open %s: %s\n", attr_path, strerror(errno)); exit(1); } printf("[+] open %s successful.\n", attr_path); res = write(fd, "1024\n", 5); if (res < 0) { printf("[-] Failed to write to %s: %s\n", attr_path, strerror(errno)); } else { printf("[+] write to %s successful.\n", attr_path); } close(fd); printf("[+] All operations completed successfully.\n"); return 0; }