Unverified Commit 8bfb3889 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!2443 CVE-2023-37453

Merge Pull Request from: @ci-robot 
 
PR sync from: Lin Yujun <linyujun809@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/YPJAR6TGPUYQZDE6DNL35MO3Y44NB2HL/ 

Alan Stern (4):
  USB: core: Unite old scheme and new scheme descriptor reads
  USB: core: Change usb_get_device_descriptor() API
  USB: core: Fix race by not overwriting udev->descriptor in
    hub_port_init()
  USB: core: Fix oversight in SuperSpeed initialization


-- 
2.34.1
 
https://gitee.com/src-openeuler/kernel/issues/I819LJ 
 
Link:https://gitee.com/openeuler/kernel/pulls/2443

 

Reviewed-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 80d776ad 9f5abfa0
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -982,6 +982,7 @@ static int register_root_hub(struct usb_hcd *hcd)
{
	struct device *parent_dev = hcd->self.controller;
	struct usb_device *usb_dev = hcd->self.root_hub;
	struct usb_device_descriptor *descr;
	const int devnum = 1;
	int retval;

@@ -993,13 +994,16 @@ static int register_root_hub(struct usb_hcd *hcd)
	mutex_lock(&usb_bus_idr_lock);

	usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
	if (retval != sizeof usb_dev->descriptor) {
	descr = usb_get_device_descriptor(usb_dev);
	if (IS_ERR(descr)) {
		retval = PTR_ERR(descr);
		mutex_unlock(&usb_bus_idr_lock);
		dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
				dev_name(&usb_dev->dev), retval);
		return (retval < 0) ? retval : -EMSGSIZE;
		return retval;
	}
	usb_dev->descriptor = *descr;
	kfree(descr);

	if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
		retval = usb_get_bos_descriptor(usb_dev);
+202 −147
Original line number Diff line number Diff line
@@ -2646,12 +2646,17 @@ int usb_authorize_device(struct usb_device *usb_dev)
	}

	if (usb_dev->wusb) {
		result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
		if (result < 0) {
		struct usb_device_descriptor *descr;

		descr = usb_get_device_descriptor(usb_dev);
		if (IS_ERR(descr)) {
			result = PTR_ERR(descr);
			dev_err(&usb_dev->dev, "can't re-read device descriptor for "
				"authorization: %d\n", result);
			goto error_device_descriptor;
		}
		usb_dev->descriptor = *descr;
		kfree(descr);
	}

	usb_dev->authorized = 1;
@@ -4594,6 +4599,67 @@ static int hub_enable_device(struct usb_device *udev)
	return hcd->driver->enable_device(hcd, udev);
}

/*
 * Get the bMaxPacketSize0 value during initialization by reading the
 * device's device descriptor.  Since we don't already know this value,
 * the transfer is unsafe and it ignores I/O errors, only testing for
 * reasonable received values.
 *
 * For "old scheme" initialization, size will be 8 so we read just the
 * start of the device descriptor, which should work okay regardless of
 * the actual bMaxPacketSize0 value.  For "new scheme" initialization,
 * size will be 64 (and buf will point to a sufficiently large buffer),
 * which might not be kosher according to the USB spec but it's what
 * Windows does and what many devices expect.
 *
 * Returns: bMaxPacketSize0 or a negative error code.
 */
static int get_bMaxPacketSize0(struct usb_device *udev,
		struct usb_device_descriptor *buf, int size, bool first_time)
{
	int i, rc;

	/*
	 * Retry on all errors; some devices are flakey.
	 * 255 is for WUSB devices, we actually need to use
	 * 512 (WUSB1.0[4.8.1]).
	 */
	for (i = 0; i < GET_MAXPACKET0_TRIES; ++i) {
		/* Start with invalid values in case the transfer fails */
		buf->bDescriptorType = buf->bMaxPacketSize0 = 0;
		rc = usb_control_msg(udev, usb_rcvaddr0pipe(),
				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
				USB_DT_DEVICE << 8, 0,
				buf, size,
				initial_descriptor_timeout);
		switch (buf->bMaxPacketSize0) {
		case 8: case 16: case 32: case 64: case 9:
			if (buf->bDescriptorType == USB_DT_DEVICE) {
				rc = buf->bMaxPacketSize0;
				break;
			}
			fallthrough;
		default:
			if (rc >= 0)
				rc = -EPROTO;
			break;
		}

		/*
		 * Some devices time out if they are powered on
		 * when already connected. They need a second
		 * reset, so return early. But only on the first
		 * attempt, lest we get into a time-out/reset loop.
		 */
		if (rc > 0 || (rc == -ETIMEDOUT && first_time &&
				udev->speed > USB_SPEED_FULL))
			break;
	}
	return rc;
}

#define GET_DESCRIPTOR_BUFSIZE	64

/* Reset device, (re)assign address, get device descriptor.
 * Device connection must be stable, no more debouncing needed.
 * Returns device in USB_STATE_ADDRESS, except on error.
@@ -4603,10 +4669,17 @@ static int hub_enable_device(struct usb_device *udev)
 * the port lock.  For a newly detected device that is not accessible
 * through any global pointers, it's not necessary to lock the device,
 * but it is still necessary to lock the port.
 *
 * For a newly detected device, @dev_descr must be NULL.  The device
 * descriptor retrieved from the device will then be stored in
 * @udev->descriptor.  For an already existing device, @dev_descr
 * must be non-NULL.  The device descriptor will be stored there,
 * not in @udev->descriptor, because descriptors for registered
 * devices are meant to be immutable.
 */
static int
hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
		int retry_counter)
		int retry_counter, struct usb_device_descriptor *dev_descr)
{
	struct usb_device	*hdev = hub->hdev;
	struct usb_hcd		*hcd = bus_to_hcd(hdev->bus);
@@ -4618,6 +4691,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
	int			devnum = udev->devnum;
	const char		*driver_name;
	bool			do_new_scheme;
	const bool		initial = !dev_descr;
	int			maxp0;
	struct usb_device_descriptor	*buf, *descr;

	buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
	if (!buf)
		return -ENOMEM;

	/* root hub ports have a slightly longer reset period
	 * (from USB 2.0 spec, section 7.1.7.5)
@@ -4650,6 +4730,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
	}
	oldspeed = udev->speed;

	if (initial) {
		/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
		 * it's fixed size except for full speed devices.
		 * For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -4677,6 +4758,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
		default:
			goto fail;
		}
	}

	if (udev->speed == USB_SPEED_WIRELESS)
		speed = "variable speed Wireless";
@@ -4698,9 +4780,10 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
	if (udev->speed < USB_SPEED_SUPER)
		dev_info(&udev->dev,
				"%s %s USB device number %d using %s\n",
				(udev->config) ? "reset" : "new", speed,
				(initial ? "new" : "reset"), speed,
				devnum, driver_name);

	if (initial) {
		/* Set up TT records, if needed  */
		if (hdev->tt) {
			udev->tt = hdev->tt;
@@ -4715,6 +4798,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
			udev->tt = &hub->tt;
			udev->ttport = port1;
		}
	}

	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
	 * Because device hardware and firmware is sometimes buggy in
@@ -4732,9 +4816,6 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,

	for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
		if (do_new_scheme) {
			struct usb_device_descriptor *buf;
			int r = 0;

			retval = hub_enable_device(udev);
			if (retval < 0) {
				dev_err(&udev->dev,
@@ -4743,52 +4824,14 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
				goto fail;
			}

#define GET_DESCRIPTOR_BUFSIZE	64
			buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
			if (!buf) {
				retval = -ENOMEM;
				continue;
			}

			/* Retry on all errors; some devices are flakey.
			 * 255 is for WUSB devices, we actually need to use
			 * 512 (WUSB1.0[4.8.1]).
			 */
			for (operations = 0; operations < GET_MAXPACKET0_TRIES;
					++operations) {
				buf->bMaxPacketSize0 = 0;
				r = usb_control_msg(udev, usb_rcvaddr0pipe(),
					USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
					USB_DT_DEVICE << 8, 0,
					buf, GET_DESCRIPTOR_BUFSIZE,
					initial_descriptor_timeout);
				switch (buf->bMaxPacketSize0) {
				case 8: case 16: case 32: case 64: case 255:
					if (buf->bDescriptorType ==
							USB_DT_DEVICE) {
						r = 0;
						break;
					}
					fallthrough;
				default:
					if (r == 0)
						r = -EPROTO;
					break;
				}
				/*
				 * Some devices time out if they are powered on
				 * when already connected. They need a second
				 * reset. But only on the first attempt,
				 * lest we get into a time out/reset loop
				 */
				if (r == 0 || (r == -ETIMEDOUT &&
						retries == 0 &&
						udev->speed > USB_SPEED_FULL))
					break;
			maxp0 = get_bMaxPacketSize0(udev, buf,
					GET_DESCRIPTOR_BUFSIZE, retries == 0);
			if (maxp0 > 0 && !initial &&
					maxp0 != udev->descriptor.bMaxPacketSize0) {
				dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n");
				retval = -ENODEV;
				goto fail;
			}
			udev->descriptor.bMaxPacketSize0 =
					buf->bMaxPacketSize0;
			kfree(buf);

			retval = hub_port_reset(hub, port1, udev, delay, false);
			if (retval < 0)		/* error or disconnect */
@@ -4799,14 +4842,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
				retval = -ENODEV;
				goto fail;
			}
			if (r) {
				if (r != -ENODEV)
			if (maxp0 < 0) {
				if (maxp0 != -ENODEV)
					dev_err(&udev->dev, "device descriptor read/64, error %d\n",
							r);
				retval = -EMSGSIZE;
							maxp0);
				retval = maxp0;
				continue;
			}
#undef GET_DESCRIPTOR_BUFSIZE
		}

		/*
@@ -4848,18 +4890,22 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
				break;
		}

		retval = usb_get_device_descriptor(udev, 8);
		if (retval < 8) {
		/* !do_new_scheme || wusb */
		maxp0 = get_bMaxPacketSize0(udev, buf, 8, retries == 0);
		if (maxp0 < 0) {
			retval = maxp0;
			if (retval != -ENODEV)
				dev_err(&udev->dev,
					"device descriptor read/8, error %d\n",
					retval);
			if (retval >= 0)
				retval = -EMSGSIZE;
		} else {
			u32 delay;

			retval = 0;
			if (!initial && maxp0 != udev->descriptor.bMaxPacketSize0) {
				dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n");
				retval = -ENODEV;
				goto fail;
			}

			delay = udev->parent->hub_delay;
			udev->hub_delay = min_t(u32, delay,
@@ -4878,48 +4924,61 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
		goto fail;

	/*
	 * Some superspeed devices have finished the link training process
	 * and attached to a superspeed hub port, but the device descriptor
	 * got from those devices show they aren't superspeed devices. Warm
	 * reset the port attached by the devices can fix them.
	 * Check the ep0 maxpacket guess and correct it if necessary.
	 * maxp0 is the value stored in the device descriptor;
	 * i is the value it encodes (logarithmic for SuperSpeed or greater).
	 */
	if ((udev->speed >= USB_SPEED_SUPER) &&
			(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
		dev_err(&udev->dev, "got a wrong device descriptor, "
				"warm reset device\n");
		hub_port_reset(hub, port1, udev,
				HUB_BH_RESET_TIME, true);
		retval = -EINVAL;
		goto fail;
	}

	if (udev->descriptor.bMaxPacketSize0 == 0xff ||
			udev->speed >= USB_SPEED_SUPER)
		i = 512;
	i = maxp0;
	if (udev->speed >= USB_SPEED_SUPER) {
		if (maxp0 <= 16)
			i = 1 << maxp0;
		else
		i = udev->descriptor.bMaxPacketSize0;
	if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
		if (udev->speed == USB_SPEED_LOW ||
				!(i == 8 || i == 16 || i == 32 || i == 64)) {
			dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
			retval = -EMSGSIZE;
			goto fail;
		}
			i = 0;		/* Invalid */
	}
	if (usb_endpoint_maxp(&udev->ep0.desc) == i) {
		;	/* Initial ep0 maxpacket guess is right */
	} else if ((udev->speed == USB_SPEED_FULL ||
				udev->speed == USB_SPEED_HIGH) &&
			(i == 8 || i == 16 || i == 32 || i == 64)) {
		/* Initial guess is wrong; use the descriptor's value */
		if (udev->speed == USB_SPEED_FULL)
			dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
		else
			dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
		usb_ep0_reinit(udev);
	} else {
		/* Initial guess is wrong and descriptor's value is invalid */
		dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", maxp0);
		retval = -EMSGSIZE;
		goto fail;
	}

	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
	if (retval < (signed)sizeof(udev->descriptor)) {
	descr = usb_get_device_descriptor(udev);
	if (IS_ERR(descr)) {
		retval = PTR_ERR(descr);
		if (retval != -ENODEV)
			dev_err(&udev->dev, "device descriptor read/all, error %d\n",
					retval);
		if (retval >= 0)
			retval = -ENOMSG;
		goto fail;
	}
	if (initial)
		udev->descriptor = *descr;
	else
		*dev_descr = *descr;
	kfree(descr);

	/*
	 * Some superspeed devices have finished the link training process
	 * and attached to a superspeed hub port, but the device descriptor
	 * got from those devices show they aren't superspeed devices. Warm
	 * reset the port attached by the devices can fix them.
	 */
	if ((udev->speed >= USB_SPEED_SUPER) &&
			(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
		dev_err(&udev->dev, "got a wrong device descriptor, warm reset device\n");
		hub_port_reset(hub, port1, udev, HUB_BH_RESET_TIME, true);
		retval = -EINVAL;
		goto fail;
	}

@@ -4943,6 +5002,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
		hub_port_disable(hub, port1, 0);
		update_devnum(udev, devnum);	/* for disconnect processing */
	}
	kfree(buf);
	return retval;
}

@@ -5023,7 +5083,7 @@ hub_power_remaining(struct usb_hub *hub)


static int descriptors_changed(struct usb_device *udev,
		struct usb_device_descriptor *old_device_descriptor,
		struct usb_device_descriptor *new_device_descriptor,
		struct usb_host_bos *old_bos)
{
	int		changed = 0;
@@ -5034,8 +5094,8 @@ static int descriptors_changed(struct usb_device *udev,
	int		length;
	char		*buf;

	if (memcmp(&udev->descriptor, old_device_descriptor,
			sizeof(*old_device_descriptor)) != 0)
	if (memcmp(&udev->descriptor, new_device_descriptor,
			sizeof(*new_device_descriptor)) != 0)
		return 1;

	if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
@@ -5208,7 +5268,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
		}

		/* reset (non-USB 3.0 devices) and get descriptor */
		status = hub_port_init(hub, udev, port1, i);
		status = hub_port_init(hub, udev, port1, i, NULL);
		if (status < 0)
			goto loop;

@@ -5355,9 +5415,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
{
	struct usb_port *port_dev = hub->ports[port1 - 1];
	struct usb_device *udev = port_dev->child;
	struct usb_device_descriptor descriptor;
	struct usb_device_descriptor *descr;
	int status = -ENODEV;
	int retval;

	dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
			portchange, portspeed(hub, portstatus));
@@ -5384,23 +5443,20 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
			 * changed device descriptors before resuscitating the
			 * device.
			 */
			descriptor = udev->descriptor;
			retval = usb_get_device_descriptor(udev,
					sizeof(udev->descriptor));
			if (retval < 0) {
			descr = usb_get_device_descriptor(udev);
			if (IS_ERR(descr)) {
				dev_dbg(&udev->dev,
						"can't read device descriptor %d\n",
						retval);
						"can't read device descriptor %ld\n",
						PTR_ERR(descr));
			} else {
				if (descriptors_changed(udev, &descriptor,
				if (descriptors_changed(udev, descr,
						udev->bos)) {
					dev_dbg(&udev->dev,
							"device descriptor has changed\n");
					/* for disconnect() calls */
					udev->descriptor = descriptor;
				} else {
					status = 0; /* Nothing to do */
				}
				kfree(descr);
			}
#ifdef CONFIG_PM
		} else if (udev->state == USB_STATE_SUSPENDED &&
@@ -5828,7 +5884,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
	struct usb_device		*parent_hdev = udev->parent;
	struct usb_hub			*parent_hub;
	struct usb_hcd			*hcd = bus_to_hcd(udev->bus);
	struct usb_device_descriptor	descriptor = udev->descriptor;
	struct usb_device_descriptor	descriptor;
	struct usb_host_bos		*bos;
	int				i, j, ret = 0;
	int				port1 = udev->portnum;
@@ -5870,7 +5926,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
		/* ep0 maxpacket size may change; let the HCD know about it.
		 * Other endpoints will be handled by re-enumeration. */
		usb_ep0_reinit(udev);
		ret = hub_port_init(parent_hub, udev, port1, i);
		ret = hub_port_init(parent_hub, udev, port1, i, &descriptor);
		if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
			break;
	}
@@ -5882,7 +5938,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
	/* Device might have changed firmware (DFU or similar) */
	if (descriptors_changed(udev, &descriptor, bos)) {
		dev_info(&udev->dev, "device firmware changed\n");
		udev->descriptor = descriptor;	/* for disconnect() calls */
		goto re_enumerate;
	}

+12 −17
Original line number Diff line number Diff line
@@ -1039,39 +1039,34 @@ char *usb_cache_string(struct usb_device *udev, int index)
}

/*
 * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
 * @dev: the device whose device descriptor is being updated
 * @size: how much of the descriptor to read
 * usb_get_device_descriptor - read the device descriptor
 * @udev: the device whose device descriptor should be read
 * Context: !in_interrupt ()
 *
 * Updates the copy of the device descriptor stored in the device structure,
 * which dedicates space for this purpose.
 *
 * Not exported, only for use by the core.  If drivers really want to read
 * the device descriptor directly, they can call usb_get_descriptor() with
 * type = USB_DT_DEVICE and index = 0.
 *
 * This call is synchronous, and may not be used in an interrupt context.
 *
 * Return: The number of bytes received on success, or else the status code
 * returned by the underlying usb_control_msg() call.
 * Returns: a pointer to a dynamically allocated usb_device_descriptor
 * structure (which the caller must deallocate), or an ERR_PTR value.
 */
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
struct usb_device_descriptor *usb_get_device_descriptor(struct usb_device *udev)
{
	struct usb_device_descriptor *desc;
	int ret;

	if (size > sizeof(*desc))
		return -EINVAL;
	desc = kmalloc(sizeof(*desc), GFP_NOIO);
	if (!desc)
		return -ENOMEM;
		return ERR_PTR(-ENOMEM);

	ret = usb_get_descriptor(udev, USB_DT_DEVICE, 0, desc, sizeof(*desc));
	if (ret == sizeof(*desc))
		return desc;

	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
	if (ret >= 0)
		memcpy(&dev->descriptor, desc, size);
		ret = -EMSGSIZE;
	kfree(desc);
	return ret;
	return ERR_PTR(ret);
}

/*
+2 −2
Original line number Diff line number Diff line
@@ -42,8 +42,8 @@ extern bool usb_endpoint_is_ignored(struct usb_device *udev,
		struct usb_endpoint_descriptor *epd);
extern int usb_remove_device(struct usb_device *udev);

extern int usb_get_device_descriptor(struct usb_device *dev,
		unsigned int size);
extern struct usb_device_descriptor *usb_get_device_descriptor(
		struct usb_device *udev);
extern int usb_set_isoch_delay(struct usb_device *dev);
extern int usb_get_bos_descriptor(struct usb_device *dev);
extern void usb_release_bos_descriptor(struct usb_device *dev);