Re: usb/storage/uas: slab-out-of-bounds in uas_probe

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

 



On Thu, Sep 21, 2017 at 6:10 PM, Greg Kroah-Hartman
<gregkh@xxxxxxxxxxxxxxxxxxx> wrote:
> On Thu, Sep 21, 2017 at 05:39:05PM +0200, Andrey Konovalov wrote:
>> Hi!
>>
>> I've got the following report while fuzzing the kernel with syzkaller.
>>
>> On commit ebb2c2437d8008d46796902ff390653822af6cc4 (Sep 18).
>>
>> The issue occurs when we iterate over interface altsettings, but I
>> don't see the driver doing anything wrong. I might be missing
>> something, or this might be an issue in USB core altsettings parsing.
>
>
> Any chance you happen to have the descriptors that you were feeding into
> the kernel at this crash?  That might help in figuring out what "went
> wrong".

Here's the data that I feed into dummy_udc:

00 00 00 00 09 02 12 00 01 34 05 80 07 09 04 6e
09 00 08 06 62 00 12 01 05 00 cb f7 71 83 04 00
05 00 ab f6 07 81 08 01

Also attaching a C reproducer (requires dummy_hcd and gadgetfs) and my .config.

>
> thanks,
>
> greg k-h
// autogenerated by syzkaller (http://github.com/google/syzkaller)

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadgetfs.h>
#include <linux/usbdevice_fs.h>
#include <poll.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

void fail(const char* msg)
{
	printf("%s", msg);
	exit(EXIT_FAILURE);
}

void gfs_mkdir()
{
	if (mkdir("/dev/gadget", 0755) != 0 && errno != EEXIST)
		fail("can't mkdir /dev/gadget\n");
}

void gfs_mount()
{
	int attempts = 0;
	while (mount("none", "/dev/gadget", "gadgetfs", 0, NULL) != 0) {
		if (++attempts >= 100)
			fail("can't mount gadgetfs");
		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:
		buffer[0] = 0;
		rv = write(fd, &buffer[0], 1);
		return 0;
	}
	return 1;
}

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

static int
gfs_handle_event_setup_get_interface(int fd,
				     struct usb_ctrlrequest* setup)
{
	char buffer[256];
	buffer[0] = 0;
	int rv = write(fd, &buffer[0], setup->wLength);
	if (rv < 0) {
		return -1;
	}
	return 1;
}

static int
gfs_handle_event_setup_set_interface(int fd,
				     struct usb_ctrlrequest* setup)
{
	return 0;
}

static int gfs_handle_event_setup_stall(int fd,
					struct usb_ctrlrequest* setup)
{
	int status;
	if (setup->bRequestType & USB_DIR_IN)
		status = read(fd, &status, 0);
	else
		status = write(fd, &status, 0);
	return 1;
}

static int gfs_handle_event_setup(int fd, struct usb_ctrlrequest* setup)
{
	int rv;
	switch (setup->bRequest) {
	case USB_REQ_GET_DESCRIPTOR:
		if (setup->bRequestType != USB_DIR_IN)
			goto stall;
		rv = gfs_handle_event_setup_get_descriptor(fd, setup);
		if (rv != 1)
			goto stall;
		return 1;
	case USB_REQ_SET_CONFIGURATION:
		if (setup->bRequestType != USB_DIR_OUT)
			goto stall;
		rv = gfs_handle_event_setup_set_configuration(fd, setup);
		if (rv != 1)
			goto stall;
		return 1;
	case USB_REQ_GET_INTERFACE:
		if (setup->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE) ||
		    setup->wIndex != 0 || setup->wLength > 1)
			goto stall;
		rv = gfs_handle_event_setup_get_interface(fd, setup);
		if (rv != 1)
			goto stall;
		return 1;
	case USB_REQ_SET_INTERFACE:
		if (setup->bRequestType != USB_RECIP_INTERFACE ||
		    setup->wIndex != 0 || setup->wLength > 1)
			goto stall;
		rv = gfs_handle_event_setup_set_interface(fd, setup);
		if (rv != 1)
			goto stall;
		return 1;
	default:
		rv = 0;
		rv = write(fd, &rv, 1);
		return 0;
	}

stall:
	gfs_handle_event_setup_stall(fd, setup);

	return 1;
}

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 5

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 < 20; 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;
		unsigned n;
		for (n = 0; n < rv / sizeof(struct usb_gadgetfs_event); n++) {
			gfs_handle_event(fd, &events[n]);
		}
	}

	return 0;
}

struct usb_device_id {
	uint16_t idVendor;
	uint16_t idProduct;
	uint16_t bcdDevice;
	uint8_t bDeviceClass;
	uint8_t bDeviceSubClass;
	uint8_t bDeviceProtocol;
	uint8_t bIntClass;
	uint8_t bIntSubClass;
	uint8_t bIntProtocol;
	uint8_t bIntNumber;
};

static void gfs_patch_usb_descriptor(uintptr_t a1, uintptr_t a2)
{
	struct usb_device_id* id = (struct usb_device_id*)a2;
	struct usb_interface_descriptor* iface =
	    (struct
	     usb_interface_descriptor*)(a1 + 4 +
					sizeof(struct usb_config_descriptor));
	struct usb_device_descriptor* dev =
	    (struct
	     usb_device_descriptor*)(a1 + 4 +
				     sizeof(struct usb_config_descriptor) +
				     sizeof(struct usb_interface_descriptor) +
				     sizeof(struct usb_endpoint_descriptor) *
					 iface->bNumEndpoints);
	dev->idVendor = id->idVendor;
	dev->idProduct = id->idProduct;
	dev->bcdDevice = id->bcdDevice;
	dev->bDeviceClass = id->bDeviceClass;
	dev->bDeviceSubClass = id->bDeviceSubClass;
	dev->bDeviceProtocol = id->bDeviceProtocol;
	iface->bInterfaceClass = id->bIntClass;
	iface->bInterfaceSubClass = id->bIntSubClass;
	iface->bInterfaceProtocol = id->bIntProtocol;
	iface->bInterfaceNumber = id->bIntNumber;
}

static uintptr_t syz_usb_config(uintptr_t a0, uintptr_t a1,
				uintptr_t a2)
{
	gfs_patch_usb_descriptor(a1, a2);

	int fd = open("/dev/gadget/dummy_udc", O_RDWR);
	if (fd < 0)
		return -1;

	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[45];

void loop()
{
	memset(r, -1, sizeof(r));
	r[0] = syscall(__NR_mmap, 0x20000000ul, 0x46a000ul, 0x3ul, 0x32ul,
		       0xfffffffffffffffful, 0x0ul);
	*(uint32_t*)0x201a5f2b = (uint32_t)0x0;
	*(uint8_t*)0x201a5f2f = (uint8_t)0x9;
	*(uint8_t*)0x201a5f30 = (uint8_t)0x2;
	*(uint16_t*)0x201a5f31 = (uint16_t)0x12;
	*(uint8_t*)0x201a5f33 = (uint8_t)0x1;
	*(uint8_t*)0x201a5f34 = (uint8_t)0xfffffffffffff434;
	*(uint8_t*)0x201a5f35 = (uint8_t)0x5;
	*(uint8_t*)0x201a5f36 = (uint8_t)0x80;
	*(uint8_t*)0x201a5f37 = (uint8_t)0x7;
	*(uint8_t*)0x201a5f38 = (uint8_t)0x9;
	*(uint8_t*)0x201a5f39 = (uint8_t)0x4;
	*(uint8_t*)0x201a5f3a = (uint8_t)0x0;
	*(uint8_t*)0x201a5f3b = (uint8_t)0x9;
	*(uint8_t*)0x201a5f3c = (uint8_t)0x0;
	*(uint8_t*)0x201a5f3d = (uint8_t)0x1;
	*(uint8_t*)0x201a5f3e = (uint8_t)0xa0;
	*(uint8_t*)0x201a5f3f = (uint8_t)0x1e360;
	*(uint8_t*)0x201a5f40 = (uint8_t)0x0;
	*(uint8_t*)0x201a5f41 = (uint8_t)0x12;
	*(uint8_t*)0x201a5f42 = (uint8_t)0x1;
	*(uint16_t*)0x201a5f43 = (uint16_t)0x5;
	*(uint8_t*)0x201a5f45 = (uint8_t)0x4;
	*(uint8_t*)0x201a5f46 = (uint8_t)0x1;
	*(uint8_t*)0x201a5f47 = (uint8_t)0x7fff;
	*(uint8_t*)0x201a5f48 = (uint8_t)0xc583;
	*(uint16_t*)0x201a5f49 = (uint16_t)0x3;
	*(uint16_t*)0x201a5f4b = (uint16_t)0x9;
	*(uint16_t*)0x201a5f4d = (uint16_t)0x80000000;
	*(uint8_t*)0x201a5f4f = (uint8_t)0x7;
	*(uint8_t*)0x201a5f50 = (uint8_t)0x81;
	*(uint8_t*)0x201a5f51 = (uint8_t)0x8;
	*(uint8_t*)0x201a5f52 = (uint8_t)0x1;
	*(uint16_t*)0x20356000 = (uint16_t)0x4;
	*(uint16_t*)0x20356002 = (uint16_t)0x5;
	*(uint16_t*)0x20356004 = (uint16_t)0xf6ab;
	*(uint8_t*)0x20356006 = (uint8_t)0x9cb;
	*(uint8_t*)0x20356007 = (uint8_t)0xfffffffffffffff7;
	*(uint8_t*)0x20356008 = (uint8_t)0x1c71;
	*(uint8_t*)0x20356009 = (uint8_t)0x8;
	*(uint8_t*)0x2035600a = (uint8_t)0x6;
	*(uint8_t*)0x2035600b = (uint8_t)0x62;
	*(uint8_t*)0x2035600c = (uint8_t)0xffffffffffff666e;
	r[43] = syz_usb_config(0x28ul, 0x201a5f2bul, 0x20356000ul);
}

int main()
{
	gfs_mkdir();
	gfs_mount();
	loop();
	return 0;
}

Attachment: .config
Description: Binary data


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux