// https://syzkaller.appspot.com/bug?id=fad611d7ddd914f0b4488742a63b93f31b321ca0 #include #include #include #include #include #include #include #include void do_mkdir(const char *path) { if (mkdir(path, 0777) != 0) { if (errno != EEXIST) { printf("[-] Failed to mkdir %s: %s\n", path, strerror(errno)); exit(1); } } printf("[+] mkdir %s successful.\n", path); } void do_rmdir(const char *path) { if (rmdir(path) != 0) { printf("[-] Failed to rmdir %s: %s\n", path, strerror(errno)); // Don't exit on rmdir failure to allow further cleanup } else { printf("[+] rmdir %s successful.\n", path); } } void do_write(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); printf("[+] write to %s successful.\n", path); } int main(void) { if (mount("none", "/sys/kernel/config", "configfs", 0, NULL) != 0) { if (errno != EBUSY) { printf("[-] Failed to mount configfs: %s\n", strerror(errno)); exit(1); } } printf("[+] configfs mounted.\n"); // 1. gadget_subsys.su_mutex -> opts->dep_lock // Creating tcm.0 loads usb_f_tcm and target_core_mod do_mkdir("/sys/kernel/config/usb_gadget/g1"); do_mkdir("/sys/kernel/config/usb_gadget/g1/functions/tcm.0"); // 2. opts->dep_lock -> inode_lock // Now target_core_mod is loaded, so /sys/kernel/config/target exists. // Create the fabric directory first do_mkdir("/sys/kernel/config/target/usb_gadget"); // Then create the WWN and TPG do_mkdir("/sys/kernel/config/target/usb_gadget/naa.6001405000000000"); do_mkdir("/sys/kernel/config/target/usb_gadget/naa.6001405000000000/tpgt_1"); // 4. frag_sem -> gadget_subsys.su_mutex do_mkdir("/sys/kernel/config/usb_gadget/g1/functions/uvc.0"); // control and extensions are default groups, so they are created automatically. // We just need to create our custom extension. do_mkdir("/sys/kernel/config/usb_gadget/g1/functions/uvc.0/control/extensions/ext1"); do_write("/sys/kernel/config/usb_gadget/g1/functions/uvc.0/control/extensions/ext1/baSourceID", "1\n"); // 3. inode_lock -> frag_sem // Removing a configfs directory acquires inode_lock then frag_sem. // This closes the circular dependency loop and triggers the lockdep splat. do_mkdir("/sys/kernel/config/usb_gadget/g2"); do_rmdir("/sys/kernel/config/usb_gadget/g2"); // Clean up other directories to ensure we don't leave a mess, // and to potentially trigger more lockdep checks. do_rmdir("/sys/kernel/config/usb_gadget/g1/functions/uvc.0/control/extensions/ext1"); do_rmdir("/sys/kernel/config/target/usb_gadget/naa.6001405000000000/tpgt_1"); do_rmdir("/sys/kernel/config/usb_gadget/g1/functions/tcm.0"); printf("[+] All steps completed successfully.\n"); return 0; }