Code: static int cp2112_gpio_direction_output(struct gpio_chip *chip,
					unsigned offset, int value)
{
 	struct cp2112_device *dev = gpiochip_get_data(chip);
 	struct hid_device *hdev = dev->hdev;
 	u8 *buf = dev->in_out_buffer;
	unsigned long flags;
 	int ret;
 
	spin_lock_irqsave(&dev->lock, flags);
 
 	ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
 				 CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
				 HID_REQ_GET_REPORT);
	if (ret != CP2112_GPIO_CONFIG_LENGTH) {
		hid_err(hdev, "error requesting GPIO config: %d\n", ret);
		goto fail;
	}

	buf[1] |= 1 << offset;
	buf[2] = gpio_push_pull;

	ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
				 CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
				 HID_REQ_SET_REPORT);
	if (ret < 0) {
		hid_err(hdev, "error setting GPIO config: %d\n", ret);
 		goto fail;
 	}
 
	spin_unlock_irqrestore(&dev->lock, flags);
 
 	/*
 	 * Set gpio value when output direction is already set,
	 * as specified in AN495, Rev. 0.2, cpt. 4.4
	 */
	cp2112_gpio_set(chip, offset, value);

 	return 0;
 
 fail:
	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret < 0 ? ret : -EIO;
 }

Vulnerability Type: DoS 
CWE ID: CWE-404
Summary: drivers/hid/hid-cp2112.c in the Linux kernel 4.9.x before 4.9.9 uses a spinlock without considering that sleeping is possible in a USB HID request callback, which allows local users to cause a denial of service (deadlock) via unspecified vectors.
Commit Message: HID: cp2112: fix sleep-while-atomic

A recent commit fixing DMA-buffers on stack added a shared transfer
buffer protected by a spinlock. This is broken as the USB HID request
callbacks can sleep. Fix this up by replacing the spinlock with a mutex.

Fixes: 1ffb3c40ffb5 ("HID: cp2112: make transfer buffers DMA capable")
Cc: stable <stable@vger.kernel.org>	# 4.9
Signed-off-by: Johan Hovold <johan@kernel.org>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>