diff options
Diffstat (limited to 'drivers/media/usb/uvc')
| -rw-r--r-- | drivers/media/usb/uvc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/media/usb/uvc/uvc_ctrl.c | 7 | ||||
| -rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 28 | ||||
| -rw-r--r-- | drivers/media/usb/uvc/uvc_entity.c | 2 | ||||
| -rw-r--r-- | drivers/media/usb/uvc/uvc_queue.c | 9 | ||||
| -rw-r--r-- | drivers/media/usb/uvc/uvcvideo.h | 5 | 
6 files changed, 29 insertions, 23 deletions
| diff --git a/drivers/media/usb/uvc/Makefile b/drivers/media/usb/uvc/Makefile index c26d12fdb8f4..a4fe5b5d533f 100644 --- a/drivers/media/usb/uvc/Makefile +++ b/drivers/media/usb/uvc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \  		  uvc_status.o uvc_isight.o uvc_debugfs.o  ifeq ($(CONFIG_MEDIA_CONTROLLER),y) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index c2ee6e39fd0c..20397aba6849 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2002,6 +2002,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,  		goto done;  	} +	/* Validate the user-provided bit-size and offset */ +	if (mapping->size > 32 || +	    mapping->offset + mapping->size > ctrl->info.size * 8) { +		ret = -EINVAL; +		goto done; +	} +  	list_for_each_entry(map, &ctrl->info.mappings, list) {  		if (mapping->id == map->id) {  			uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', " diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 70842c5af05b..6d22b22cb35b 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1802,8 +1802,9 @@ static int uvc_scan_device(struct uvc_device *dev)   * already been canceled by the USB core. There is no need to kill the   * interrupt URB manually.   */ -static void uvc_delete(struct uvc_device *dev) +static void uvc_delete(struct kref *kref)  { +	struct uvc_device *dev = container_of(kref, struct uvc_device, ref);  	struct list_head *p, *n;  	uvc_status_cleanup(dev); @@ -1854,11 +1855,7 @@ static void uvc_release(struct video_device *vdev)  	struct uvc_streaming *stream = video_get_drvdata(vdev);  	struct uvc_device *dev = stream->dev; -	/* Decrement the registered streams count and delete the device when it -	 * reaches zero. -	 */ -	if (atomic_dec_and_test(&dev->nstreams)) -		uvc_delete(dev); +	kref_put(&dev->ref, uvc_delete);  }  /* @@ -1870,10 +1867,10 @@ static void uvc_unregister_video(struct uvc_device *dev)  	/* Unregistering all video devices might result in uvc_delete() being  	 * called from inside the loop if there's no open file handle. To avoid -	 * that, increment the stream count before iterating over the streams -	 * and decrement it when done. +	 * that, increment the refcount before iterating over the streams and +	 * decrement it when done.  	 */ -	atomic_inc(&dev->nstreams); +	kref_get(&dev->ref);  	list_for_each_entry(stream, &dev->streams, list) {  		if (!video_is_registered(&stream->vdev)) @@ -1884,11 +1881,7 @@ static void uvc_unregister_video(struct uvc_device *dev)  		uvc_debugfs_cleanup_stream(stream);  	} -	/* Decrement the stream count and call uvc_delete explicitly if there -	 * are no stream left. -	 */ -	if (atomic_dec_and_test(&dev->nstreams)) -		uvc_delete(dev); +	kref_put(&dev->ref, uvc_delete);  }  static int uvc_register_video(struct uvc_device *dev, @@ -1946,7 +1939,7 @@ static int uvc_register_video(struct uvc_device *dev,  	else  		stream->chain->caps |= V4L2_CAP_VIDEO_OUTPUT; -	atomic_inc(&dev->nstreams); +	kref_get(&dev->ref);  	return 0;  } @@ -2031,7 +2024,7 @@ static int uvc_probe(struct usb_interface *intf,  	INIT_LIST_HEAD(&dev->entities);  	INIT_LIST_HEAD(&dev->chains);  	INIT_LIST_HEAD(&dev->streams); -	atomic_set(&dev->nstreams, 0); +	kref_init(&dev->ref);  	atomic_set(&dev->nmappings, 0);  	mutex_init(&dev->lock); @@ -2096,7 +2089,6 @@ static int uvc_probe(struct usb_interface *intf,  			sizeof(dev->mdev.serial));  	strcpy(dev->mdev.bus_info, udev->devpath);  	dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); -	dev->mdev.driver_version = LINUX_VERSION_CODE;  	media_device_init(&dev->mdev);  	dev->vdev.mdev = &dev->mdev; @@ -2284,7 +2276,7 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");   * VENDOR_SPEC because they don't announce themselves as UVC devices, even   * though they are compliant.   */ -static struct usb_device_id uvc_ids[] = { +static const struct usb_device_id uvc_ids[] = {  	/* LogiLink Wireless Webcam */  	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE  				| USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index ac386bb547e6..554063c07d7a 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -61,7 +61,7 @@ static int uvc_mc_create_links(struct uvc_video_chain *chain,  	return 0;  } -static struct v4l2_subdev_ops uvc_subdev_ops = { +static const struct v4l2_subdev_ops uvc_subdev_ops = {  };  void uvc_mc_cleanup_entity(struct uvc_entity *entity) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index aa2199775cb8..c8d78b2f3de4 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -82,9 +82,14 @@ static int uvc_queue_setup(struct vb2_queue *vq,  	struct uvc_streaming *stream = uvc_queue_to_stream(queue);  	unsigned size = stream->ctrl.dwMaxVideoFrameSize; -	/* Make sure the image size is large enough. */ +	/* +	 * When called with plane sizes, validate them. The driver supports +	 * single planar formats only, and requires buffers to be large enough +	 * to store a complete frame. +	 */  	if (*nplanes) -		return sizes[0] < size ? -EINVAL : 0; +		return *nplanes != 1 || sizes[0] < size ? -EINVAL : 0; +  	*nplanes = 1;  	sizes[0] = size;  	return 0; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 15e415e32c7f..05398784d1c8 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _USB_VIDEO_H_  #define _USB_VIDEO_H_ @@ -166,7 +167,7 @@  /* Maximum status buffer size in bytes of interrupt URB. */  #define UVC_MAX_STATUS_SIZE	16 -#define UVC_CTRL_CONTROL_TIMEOUT	300 +#define UVC_CTRL_CONTROL_TIMEOUT	500  #define UVC_CTRL_STREAMING_TIMEOUT	5000  /* Maximum allowed number of control mappings per device */ @@ -575,7 +576,7 @@ struct uvc_device {  	/* Video Streaming interfaces */  	struct list_head streams; -	atomic_t nstreams; +	struct kref ref;  	/* Status Interrupt Endpoint */  	struct usb_host_endpoint *int_ep; |