On Fri, Sep 15, 2017 at 8:57 PM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote: > On Thu, 14 Sep 2017, Andrey Konovalov wrote: > >> On Thu, Sep 14, 2017 at 7:49 PM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote: >> > On Thu, 14 Sep 2017, Andrey Konovalov wrote: >> > >> >> Looked at this a little more. >> >> >> >> dummy_timer() stucks in an infinite loop. It calls >> >> usb_hcd_giveback_urb(), which in turn calls usbtouch_irq(), which >> >> calls usb_submit_urb(), which calls dummy_urb_enqueue() and puts urb >> >> back into dummy urb queue. dummy_timer() then does goto restart, finds >> >> the urb and calls usb_hcd_giveback_urb() again. And this process goes >> >> on again and again. It seems that something should either process the >> >> urb and set urb->status or it should just expire. >> > >> > There is some throttling code, but it applies only to bulk transfers. >> > Probably because the bandwidth limits for other types are slightly >> > different. However, I don't think we need to worry about this level of >> > detail, since the driver makes a number of other approximations anyway. >> > >> > Try the patch below; it should fix the problem. >> >> Hi Alan, >> >> Just tried your patch, my reproducer still hangs the kernel until all >> memory is exhausted. >> >> Thanks! > > Hmmm. Your reproducer doesn't run on my system. The mmap system call > fails, perhaps because this laptop has a 32-bit kernel. So I can't > tell what's going on. > > Can you collect a usbmon trace that shows what happens while the > reproducer runs? If it turns out to be extremely large, just post an > initial portion of it. I've attached the usbmon trace. It's actually quite short, probably due to the fact that the kernel enters infinite loop. I've also attached a reproducer that should compile on a 32 bit system, however I haven't tested whether it reproduces the issue. > > Alan Stern >
Attachment:
dummy_timer-stall-usbmon
Description: Binary data
// autogenerated by syzkaller (http://github.com/google/syzkaller) #define _GNU_SOURCE #include <assert.h> #include <errno.h> #include <fcntl.h> #include <linux/usb/ch9.h> #include <linux/usb/gadgetfs.h> #include <poll.h> #include <sched.h> #include <signal.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <sys/inotify.h> #include <sys/mount.h> #include <sys/prctl.h> #include <sys/resource.h> #include <sys/syscall.h> #include <sys/time.h> #include <sys/wait.h> #include <unistd.h> #include <sys/stat.h> #include <sys/mman.h> void gadgetfs_mkdir() { mkdir("/dev/gadget", 0755) != 0; } void gadgetfs_mount() { while (mount("none", "/dev/gadget", "gadgetfs", 0, NULL) != 0) { usleep(10 * 1000); umount2("/dev/gadget", MNT_FORCE | MNT_DETACH); } } static int gfs_handle_event_setup_get_descriptor(int fd, struct usb_ctrlrequest* setup) { char buffer[128]; int rv; switch (setup->wValue >> 8) { case USB_DT_STRING: buffer[0] = 4; buffer[1] = USB_DT_STRING; if ((setup->wValue & 0x0ff) == 0) { buffer[2] = 0x09; buffer[3] = 0x04; } else { buffer[2] = 0x61; buffer[3] = 0x00; } rv = write(fd, &buffer[0], 4); if (rv != 4) { return -1; } break; default: break; } return 0; } static int gfs_handle_event_setup_set_configuration(int fd, struct usb_ctrlrequest* setup) { int rv = read(fd, &rv, 0); if (rv != 0) { return -1; } return 0; } static int gfs_handle_event_setup(int fd, struct usb_ctrlrequest* setup) { switch (setup->bRequest) { case USB_REQ_GET_DESCRIPTOR: gfs_handle_event_setup_get_descriptor(fd, setup); break; case USB_REQ_SET_CONFIGURATION: gfs_handle_event_setup_set_configuration(fd, setup); break; case USB_REQ_GET_INTERFACE: break; case USB_REQ_SET_INTERFACE: break; default: break; } return 0; } static int gfs_handle_event(int fd, struct usb_gadgetfs_event* event) { switch (event->type) { case GADGETFS_NOP: break; case GADGETFS_CONNECT: break; case GADGETFS_SETUP: gfs_handle_event_setup(fd, &event->u.setup); break; case GADGETFS_DISCONNECT: break; case GADGETFS_SUSPEND: break; default: break; } return 0; } #define GFS_MAX_EVENTS 1 static int gfs_handle_ep0(int fd) { struct pollfd pfd; struct usb_gadgetfs_event events[GFS_MAX_EVENTS]; pfd.fd = fd; pfd.events = POLLIN | POLLOUT | POLLHUP; int i; for (i = 0; i < 15; i++) { int rv = poll(&pfd, 1, 100); if (rv < 0) { return -1; } if (rv == 0) continue; rv = read(fd, &events[0], sizeof(events)); if (rv < 0) { return -2; } if (rv == 0) continue; gfs_handle_event(fd, &events[0]); } return 0; } static uintptr_t syz_usb_config(uintptr_t a0, uintptr_t a1) { int fd = open("/dev/gadget/dummy_udc", O_RDWR); if (fd < 0) return -1; usleep(30 * 1000); int64_t length = a0; char* data = (char*)a1; int rv = write(fd, data, length); if (rv < 0) { return -2; } gfs_handle_ep0(fd); return fd; } long r[66]; void loop() { memset(r, -1, sizeof(r)); r[0] = (long)mmap((void*)0x23000ul, 0x1000ul, 0x3ul, 0x32ul, 0xfffffffful, 0x0ul); *(uint32_t*)0x23000 = (uint32_t)0x0; *(uint8_t*)0x23004 = (uint8_t)0x9; *(uint8_t*)0x23005 = (uint8_t)0x2; *(uint16_t*)0x23006 = (uint16_t)0x36; *(uint8_t*)0x23008 = (uint8_t)0x1; *(uint8_t*)0x23009 = (uint8_t)0x8; *(uint8_t*)0x2300a = (uint8_t)0x600; *(uint8_t*)0x2300b = (uint8_t)0x80; *(uint8_t*)0x2300c = (uint8_t)0x8; *(uint8_t*)0x2300d = (uint8_t)0x9; *(uint8_t*)0x2300e = (uint8_t)0x4; *(uint8_t*)0x2300f = (uint8_t)0x0; *(uint8_t*)0x23010 = (uint8_t)0x9; *(uint8_t*)0x23011 = (uint8_t)0x4; *(uint8_t*)0x23012 = (uint8_t)0xff; *(uint8_t*)0x23013 = (uint8_t)0x3; *(uint8_t*)0x23014 = (uint8_t)0x0; *(uint8_t*)0x23015 = (uint8_t)0x7; *(uint8_t*)0x23016 = (uint8_t)0x9; *(uint8_t*)0x23017 = (uint8_t)0x5; *(uint8_t*)0x23018 = (uint8_t)0x9; *(uint8_t*)0x23019 = (uint8_t)0x10; *(uint16_t*)0x2301a = (uint16_t)0x1; *(uint8_t*)0x2301c = (uint8_t)0x5; *(uint8_t*)0x2301d = (uint8_t)0xfffff800; *(uint8_t*)0x2301e = (uint8_t)0x2bba; *(uint8_t*)0x2301f = (uint8_t)0x9; *(uint8_t*)0x23020 = (uint8_t)0x5; *(uint8_t*)0x23021 = (uint8_t)0x898f; *(uint8_t*)0x23022 = (uint8_t)0x3; *(uint16_t*)0x23023 = (uint16_t)0x7c113347; *(uint8_t*)0x23025 = (uint8_t)0x0; *(uint8_t*)0x23026 = (uint8_t)0xbc; *(uint8_t*)0x23027 = (uint8_t)0x5; *(uint8_t*)0x23028 = (uint8_t)0x9; *(uint8_t*)0x23029 = (uint8_t)0x5; *(uint8_t*)0x2302a = (uint8_t)0x7; *(uint8_t*)0x2302b = (uint8_t)0x14; *(uint16_t*)0x2302c = (uint16_t)0x972f; *(uint8_t*)0x2302e = (uint8_t)0x1f; *(uint8_t*)0x2302f = (uint8_t)0x7; *(uint8_t*)0x23030 = (uint8_t)0x3f; *(uint8_t*)0x23031 = (uint8_t)0x9; *(uint8_t*)0x23032 = (uint8_t)0x5; *(uint8_t*)0x23033 = (uint8_t)0x8; *(uint8_t*)0x23034 = (uint8_t)0x0; *(uint16_t*)0x23035 = (uint16_t)0x7; *(uint8_t*)0x23037 = (uint8_t)0x81; *(uint8_t*)0x23038 = (uint8_t)0x7ff; *(uint8_t*)0x23039 = (uint8_t)0x200; *(uint8_t*)0x2303a = (uint8_t)0x12; *(uint8_t*)0x2303b = (uint8_t)0x1; *(uint16_t*)0x2303c = (uint16_t)0xffffffff; *(uint8_t*)0x2303e = (uint8_t)0x7fd; *(uint8_t*)0x2303f = (uint8_t)0x4; *(uint8_t*)0x23040 = (uint8_t)0x3; *(uint8_t*)0x23041 = (uint8_t)0x1000; *(uint16_t*)0x23042 = (uint16_t)0x403; *(uint16_t*)0x23044 = (uint16_t)0x1000f9e9; *(uint16_t*)0x23046 = (uint16_t)0x4; *(uint8_t*)0x23048 = (uint8_t)0x4; *(uint8_t*)0x23049 = (uint8_t)0x8; *(uint8_t*)0x2304a = (uint8_t)0x7ff; *(uint8_t*)0x2304b = (uint8_t)0x1; r[65] = syz_usb_config(0x4cul, 0x23000ul); } int main() { gadgetfs_mkdir(); gadgetfs_mount(); loop(); return 0; }