Re: usb/gadget: stalls in dummy_timer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
}

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux