// https://syzkaller.appspot.com/bug?id=5073831ae6fda2a5f8332c1075c7474f260a49f7 #include #include #include #include #include #include #include #include #include #define UDC_NAME_LENGTH_MAX 128 struct usb_raw_init { __u8 driver_name[UDC_NAME_LENGTH_MAX]; __u8 device_name[UDC_NAME_LENGTH_MAX]; __u8 speed; }; enum usb_raw_event_type { USB_RAW_EVENT_INVALID = 0, USB_RAW_EVENT_CONNECT = 1, USB_RAW_EVENT_CONTROL = 2, }; struct usb_raw_event { __u32 type; __u32 length; __u8 data[]; }; struct usb_raw_ep_io { __u16 ep; __u16 flags; __u32 length; __u8 data[]; }; #define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init) #define USB_RAW_IOCTL_RUN _IO('U', 1) #define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event) #define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io) #define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io) char dev_desc[] = { 18, 1, 0x00, 0x02, 0, 0, 0, 64, 0x24, 0x04, // idVendor (0x0424) 0x2c, 0x01, // idProduct (0x012c) 0x00, 0x01, 0, 0, 0, 1 }; char conf_desc[] = { 9, 2, 46, 0, 1, 1, 0, 0xc0, 50, 9, 4, 0, 0, 4, 0xff, 0xff, 0xff, 0, 7, 5, 0x81, 2, 0x00, 0x02, 0, 7, 5, 0x02, 2, 0x00, 0x02, 0, 7, 5, 0x83, 2, 0x00, 0x02, 0, 7, 5, 0x04, 2, 0x00, 0x02, 0, }; void trigger_read_lock() { int fd = open("/sys/kernel/debug/wakeup_sources", O_RDONLY); if (fd >= 0) { char buf[128]; if (read(fd, buf, sizeof(buf)) < 0) { printf("[-] Failed to read wakeup_sources: %s\n", strerror(errno)); } else { printf("[+] Successfully read wakeup_sources.\n"); } close(fd); } else { printf("[-] Failed to open wakeup_sources: %s\n", strerror(errno)); } } int main() { // Register the read-side of wakeup_srcu with lockdep trigger_read_lock(); int fd = open("/dev/raw-gadget", O_RDWR); if (fd < 0) { printf("[-] Failed to open /dev/raw-gadget: %s\n", strerror(errno)); return 1; } printf("[+] Successfully opened /dev/raw-gadget.\n"); struct usb_raw_init init = { .driver_name = "dummy_udc", .device_name = "dummy_udc.0", .speed = 3, // USB_SPEED_HIGH }; if (ioctl(fd, USB_RAW_IOCTL_INIT, &init) < 0) { printf("[-] Failed to USB_RAW_IOCTL_INIT: %s\n", strerror(errno)); return 1; } printf("[+] USB_RAW_IOCTL_INIT successful.\n"); if (ioctl(fd, USB_RAW_IOCTL_RUN, 0) < 0) { printf("[-] Failed to USB_RAW_IOCTL_RUN: %s\n", strerror(errno)); return 1; } printf("[+] USB_RAW_IOCTL_RUN successful.\n"); int probed = 0; while (!probed) { struct usb_raw_event *event = malloc(sizeof(struct usb_raw_event) + sizeof(struct usb_ctrlrequest)); if (!event) { printf("[-] Failed to allocate memory for event.\n"); return 1; } if (ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event) < 0) { printf("[-] Failed to USB_RAW_IOCTL_EVENT_FETCH: %s\n", strerror(errno)); free(event); break; } if (event->type == USB_RAW_EVENT_CONTROL) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)event->data; if (req->bRequestType & USB_DIR_IN) { uint32_t len = 0; char *data = NULL; char hc_info[4] = {4, 0, 0, 1}; char port_status[15] = {15, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; if (req->bRequestType == 0x80 && req->bRequest == 0x06) { if ((req->wValue >> 8) == 0x01) { len = sizeof(dev_desc); data = dev_desc; } else if ((req->wValue >> 8) == 0x02) { len = sizeof(conf_desc); data = conf_desc; } } else if (req->bRequestType == 0xc0) { if (req->bRequest == 1) { len = 4; data = hc_info; } else if (req->bRequest == 0) { len = 15; data = port_status; probed = 1; } } if (len > req->wLength) len = req->wLength; struct usb_raw_ep_io *io = malloc(sizeof(struct usb_raw_ep_io) + len); if (!io) { printf("[-] Failed to allocate memory for io.\n"); free(event); return 1; } io->ep = 0; io->flags = 0; io->length = len; if (data) memcpy(io->data, data, len); if (ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io) < 0) { printf("[-] Failed to USB_RAW_IOCTL_EP0_WRITE: %s\n", strerror(errno)); } free(io); } else { uint32_t len = req->wLength; struct usb_raw_ep_io *io = malloc(sizeof(struct usb_raw_ep_io) + len); if (!io) { printf("[-] Failed to allocate memory for io.\n"); free(event); return 1; } io->ep = 0; io->flags = 0; io->length = len; if (ioctl(fd, USB_RAW_IOCTL_EP0_READ, io) < 0) { printf("[-] Failed to USB_RAW_IOCTL_EP0_READ: %s\n", strerror(errno)); } free(io); } } free(event); } printf("[+] Device probed.\n"); // Wait for vub300_probe to finish, then disconnect to drop the first reference sleep(1); close(fd); printf("[+] Device disconnected.\n"); // Wait for the inactivity timer to fire in softirq context, triggering the write-side sleep(3); printf("[+] Waited for inactivity timer.\n"); // Trigger lockdep warning again just in case trigger_read_lock(); return 0; }