On Tue, Sep 12, 2017 at 7:06 PM, Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> wrote: > On Tue, Sep 12, 2017 at 05:48:51PM +0200, Andrey Konovalov wrote: >> On Mon, Sep 11, 2017 at 8:54 PM, Dmitry Torokhov >> <dmitry.torokhov@xxxxxxxxx> wrote: >> > On Mon, Sep 11, 2017 at 8:15 AM, Andrey Konovalov <andreyknvl@xxxxxxxxxx> wrote: >> >> On Mon, Sep 11, 2017 at 3:25 PM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote: >> >>> On Mon, 11 Sep 2017, Andrey Konovalov wrote: >> >>> >> >>>> Hi! >> >>>> >> >>>> I've been getting stall reports like this one while fuzzing the USB >> >>>> stack with gadgetfs. I'm wondering whether this is a bug in gadgetfs >> >>>> or is this report induced by the changes I've made to the USB core >> >>>> code. I didn't touch gadgetfs code though (except for adding a few >> >>>> printk's). >> >>>> >> >>>> I'm on commit 81a84ad3cb5711cec79f4dd53a4ce026b092c432 >> >>> >> >>> It's possible that this was caused by commit f16443a034c7 ("USB: >> >>> gadgetfs, dummy-hcd, net2280: fix locking for callbacks"). I've been >> >>> meaning to repair the commit but haven't done it yet. >> >>> >> >>> Can you test with that commit reverted? You may end up seeing other >> >>> problems instead -- the ones that commit was intended to solve -- but >> >>> perhaps the stalls won't occur. >> >> >> >> So I've reverted both: the changes I made to USB core and the commit >> >> you mentioned, still saw the stalls. >> >> >> >> I've manged to find a way to reproduce this and now I'm not sure the >> >> problem is actually in gadgetfs, it might be the usbtouchscreen >> >> driver. >> >> >> >> The crash log is below. >> >> >> >> Thanks! >> >> >> >> gadgetfs: bound to dummy_udc driver >> >> usb 1-1: new full-speed USB device number 2 using dummy_hcd >> >> gadgetfs: connected >> >> gadgetfs: disconnected >> >> gadgetfs: connected >> >> usb 1-1: config 8 interface 0 altsetting 9 endpoint 0x8F has an >> >> invalid bInterval 0, changing to 10 >> >> usb 1-1: config 8 interface 0 altsetting 9 endpoint 0x8F has invalid >> >> maxpacket 839, setting to 64 >> >> usb 1-1: config 8 interface 0 altsetting 9 endpoint 0x7 has invalid >> >> maxpacket 1839, setting to 64 >> >> usb 1-1: config 8 interface 0 has no altsetting 0 >> >> usb 1-1: New USB device found, idVendor=0403, idProduct=f9e9 >> >> usb 1-1: New USB device strings: Mfr=4, Product=8, SerialNumber=255 >> >> usb 1-1: Product: a >> >> usb 1-1: Manufacturer: a >> >> usb 1-1: SerialNumber: a >> >> gadgetfs: configuration #8 >> >> input: a a as /devices/platform/dummy_hcd.0/usb1/1-1/1-1:8.0/input/input8 >> >> evbug: Connected device: input8 (a a at usb-dummy_hcd.0-1/input0) >> >> kworker/0:0: page allocation failure: order:0, >> >> mode:0x1280020(GFP_ATOMIC|__GFP_NOTRACK), nodemask=(null) >> >> kworker/0:0 cpuset=/ mems_allowed=0 >> > >> > It seems you are running out of memory. >> > >> >> Swap cache stats: add 0, delete 0, find 0/0 >> >> Free swap = 0kB >> >> Total swap = 0kB >> > >> > And no swap. I think you need to give the box a bit more memory (or >> > there might be a leak somewhere). >> >> Increasing the amount of memory doesn't help. It looks like >> usbtouch_irq() gets called in an infinite loop, and calls >> usb_submit_urb on each iteration, until the kernel runs out of memory. > > Yes, that is exactly how USB interrupt-driven devices work. Their URB > completion routine handles the data and immediately resubmits URB to get > more data. The device/HCD will signal interrupt once more data is > available and the process starts over again. The only time we stop > resubmitting URBs if we get one of the following errors: > > case -ETIME: > /* this urb is timing out */ > dev_dbg(dev, > "%s - urb timed out - was the device unplugged?\n", > __func__); > return; > case -ECONNRESET: > case -ENOENT: > case -ESHUTDOWN: > case -EPIPE: > /* this urb is terminated, clean up */ > dev_dbg(dev, "%s - urb shutting down with status: %d\n", > __func__, urb->status); > return; > > So I'd start looking into dummy_hcd and see why it does not discard > processed URBs fast enough in your setup. I now have a C reproducer (attached), which causes this behavior on upstream kernel built with attached .config on commit 81a84ad3cb5711cec79f4dd53a4ce026b092c432, so I'm not sure if the issue is with my particular setup. > > Thanks. > > -- > Dmitry > > -- > You received this message because you are subscribed to the Google Groups "syzkaller" group. > To unsubscribe from this group and stop receiving emails from it, send an email to syzkaller+unsubscribe@xxxxxxxxxxxxxxxx. > For more options, visit https://groups.google.com/d/optout.
Attachment:
.config
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> 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] = syscall(__NR_mmap, 0x20003000ul, 0x1000ul, 0x3ul, 0x32ul, 0xfffffffffffffffful, 0x0ul); *(uint32_t*)0x20003000 = (uint32_t)0x0; *(uint8_t*)0x20003004 = (uint8_t)0x9; *(uint8_t*)0x20003005 = (uint8_t)0x2; *(uint16_t*)0x20003006 = (uint16_t)0x36; *(uint8_t*)0x20003008 = (uint8_t)0x1; *(uint8_t*)0x20003009 = (uint8_t)0x8; *(uint8_t*)0x2000300a = (uint8_t)0x600; *(uint8_t*)0x2000300b = (uint8_t)0x80; *(uint8_t*)0x2000300c = (uint8_t)0x8; *(uint8_t*)0x2000300d = (uint8_t)0x9; *(uint8_t*)0x2000300e = (uint8_t)0x4; *(uint8_t*)0x2000300f = (uint8_t)0x0; *(uint8_t*)0x20003010 = (uint8_t)0x9; *(uint8_t*)0x20003011 = (uint8_t)0x4; *(uint8_t*)0x20003012 = (uint8_t)0xff; *(uint8_t*)0x20003013 = (uint8_t)0x3; *(uint8_t*)0x20003014 = (uint8_t)0x0; *(uint8_t*)0x20003015 = (uint8_t)0x7; *(uint8_t*)0x20003016 = (uint8_t)0x9; *(uint8_t*)0x20003017 = (uint8_t)0x5; *(uint8_t*)0x20003018 = (uint8_t)0x9; *(uint8_t*)0x20003019 = (uint8_t)0x10; *(uint16_t*)0x2000301a = (uint16_t)0x1; *(uint8_t*)0x2000301c = (uint8_t)0x5; *(uint8_t*)0x2000301d = (uint8_t)0xfffffffffffff800; *(uint8_t*)0x2000301e = (uint8_t)0x2bba; *(uint8_t*)0x2000301f = (uint8_t)0x9; *(uint8_t*)0x20003020 = (uint8_t)0x5; *(uint8_t*)0x20003021 = (uint8_t)0x898f; *(uint8_t*)0x20003022 = (uint8_t)0x3; *(uint16_t*)0x20003023 = (uint16_t)0x7c113347; *(uint8_t*)0x20003025 = (uint8_t)0x0; *(uint8_t*)0x20003026 = (uint8_t)0xbc; *(uint8_t*)0x20003027 = (uint8_t)0x5; *(uint8_t*)0x20003028 = (uint8_t)0x9; *(uint8_t*)0x20003029 = (uint8_t)0x5; *(uint8_t*)0x2000302a = (uint8_t)0x7; *(uint8_t*)0x2000302b = (uint8_t)0x14; *(uint16_t*)0x2000302c = (uint16_t)0x972f; *(uint8_t*)0x2000302e = (uint8_t)0x1f; *(uint8_t*)0x2000302f = (uint8_t)0x7; *(uint8_t*)0x20003030 = (uint8_t)0x3f; *(uint8_t*)0x20003031 = (uint8_t)0x9; *(uint8_t*)0x20003032 = (uint8_t)0x5; *(uint8_t*)0x20003033 = (uint8_t)0x8; *(uint8_t*)0x20003034 = (uint8_t)0x0; *(uint16_t*)0x20003035 = (uint16_t)0x7; *(uint8_t*)0x20003037 = (uint8_t)0x81; *(uint8_t*)0x20003038 = (uint8_t)0x7ff; *(uint8_t*)0x20003039 = (uint8_t)0x200; *(uint8_t*)0x2000303a = (uint8_t)0x12; *(uint8_t*)0x2000303b = (uint8_t)0x1; *(uint16_t*)0x2000303c = (uint16_t)0xffffffffffffffff; *(uint8_t*)0x2000303e = (uint8_t)0x7fd; *(uint8_t*)0x2000303f = (uint8_t)0x4; *(uint8_t*)0x20003040 = (uint8_t)0x3; *(uint8_t*)0x20003041 = (uint8_t)0x1000; *(uint16_t*)0x20003042 = (uint16_t)0x403; *(uint16_t*)0x20003044 = (uint16_t)0x1000f9e9; *(uint16_t*)0x20003046 = (uint16_t)0x4; *(uint8_t*)0x20003048 = (uint8_t)0x4; *(uint8_t*)0x20003049 = (uint8_t)0x8; *(uint8_t*)0x2000304a = (uint8_t)0x7ff; *(uint8_t*)0x2000304b = (uint8_t)0x1; r[65] = syz_usb_config(0x4cul, 0x20003000ul); } int main() { gadgetfs_mkdir(); gadgetfs_mount(); loop(); return 0; }