Skip to content

Commit f51d42a

Browse files
committed
media: uvcvideo: Remove dangling pointers
jira VULN-53462 jira VULN-53461 cve CVE-2024-58002 commit-author Ricardo Ribalda <ribalda@chromium.org> commit 221cd51 upstream-diff used kernel-lt 5.15 commit 117f7a2 This is due to missing both: - e8c0708 - Kbuild: move to -std=gnu11 - 54da6a0 - locking: Introduce __cleanup() based infrastructure When an async control is written, we copy a pointer to the file handle that started the operation. That pointer will be used when the device is done. Which could be anytime in the future. If the user closes that file descriptor, its structure will be freed, and there will be one dangling pointer per pending async control, that the driver will try to use. Clean all the dangling pointers during release(). To avoid adding a performance penalty in the most common case (no async operation), a counter has been introduced with some logic to make sure that it is properly handled. Cc: stable@vger.kernel.org Fixes: e5225c8 ("media: uvcvideo: Send a control event when a Control Change interrupt arrives") Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Link: https://lore.kernel.org/r/20241203-uvc-fix-async-v6-3-26c867231118@chromium.org Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit 117f7a2) Signed-off-by: Jonathan Maple <jmaple@ciq.com>
1 parent 204f212 commit f51d42a

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

drivers/media/usb/uvc/uvc_ctrl.c

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,6 +1532,40 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
15321532
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
15331533
}
15341534

1535+
static void uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl,
1536+
struct uvc_fh *new_handle)
1537+
{
1538+
lockdep_assert_held(&handle->chain->ctrl_mutex);
1539+
1540+
if (new_handle) {
1541+
if (ctrl->handle)
1542+
dev_warn_ratelimited(&handle->stream->dev->udev->dev,
1543+
"UVC non compliance: Setting an async control with a pending operation.");
1544+
1545+
if (new_handle == ctrl->handle)
1546+
return;
1547+
1548+
if (ctrl->handle) {
1549+
WARN_ON(!ctrl->handle->pending_async_ctrls);
1550+
if (ctrl->handle->pending_async_ctrls)
1551+
ctrl->handle->pending_async_ctrls--;
1552+
}
1553+
1554+
ctrl->handle = new_handle;
1555+
handle->pending_async_ctrls++;
1556+
return;
1557+
}
1558+
1559+
/* Cannot clear the handle for a control not owned by us.*/
1560+
if (WARN_ON(ctrl->handle != handle))
1561+
return;
1562+
1563+
ctrl->handle = NULL;
1564+
if (WARN_ON(!handle->pending_async_ctrls))
1565+
return;
1566+
handle->pending_async_ctrls--;
1567+
}
1568+
15351569
void uvc_ctrl_status_event(struct uvc_video_chain *chain,
15361570
struct uvc_control *ctrl, const u8 *data)
15371571
{
@@ -1542,7 +1576,8 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
15421576
mutex_lock(&chain->ctrl_mutex);
15431577

15441578
handle = ctrl->handle;
1545-
ctrl->handle = NULL;
1579+
if (handle)
1580+
uvc_ctrl_set_handle(handle, ctrl, NULL);
15461581

15471582
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
15481583
s32 value = __uvc_ctrl_get_value(mapping, data);
@@ -1818,7 +1853,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
18181853

18191854
if (!rollback && handle &&
18201855
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
1821-
ctrl->handle = handle;
1856+
uvc_ctrl_set_handle(handle, ctrl, handle);
18221857
}
18231858

18241859
return 0;
@@ -2749,6 +2784,30 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
27492784
return 0;
27502785
}
27512786

2787+
void uvc_ctrl_cleanup_fh(struct uvc_fh *handle)
2788+
{
2789+
struct uvc_entity *entity;
2790+
2791+
mutex_lock(&handle->chain->ctrl_mutex);
2792+
2793+
if (!handle->pending_async_ctrls) {
2794+
mutex_unlock(&handle->chain->ctrl_mutex);
2795+
return;
2796+
}
2797+
2798+
list_for_each_entry(entity, &handle->chain->dev->entities, list) {
2799+
unsigned int i;
2800+
for (i = 0; i < entity->ncontrols; ++i) {
2801+
if (entity->controls[i].handle != handle)
2802+
continue;
2803+
uvc_ctrl_set_handle(handle, &entity->controls[i], NULL);
2804+
}
2805+
}
2806+
2807+
WARN_ON(handle->pending_async_ctrls);
2808+
mutex_unlock(&handle->chain->ctrl_mutex);
2809+
}
2810+
27522811
/*
27532812
* Cleanup device controls.
27542813
*/

drivers/media/usb/uvc/uvc_v4l2.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,8 @@ static int uvc_v4l2_release(struct file *file)
658658

659659
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
660660

661+
uvc_ctrl_cleanup_fh(handle);
662+
661663
/* Only free resources if this is a privileged handle. */
662664
if (uvc_has_privileges(handle))
663665
uvc_queue_release(&stream->queue);

drivers/media/usb/uvc/uvcvideo.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,11 @@ struct uvc_video_chain {
329329
struct uvc_entity *processing; /* Processing unit */
330330
struct uvc_entity *selector; /* Selector unit */
331331

332-
struct mutex ctrl_mutex; /* Protects ctrl.info */
332+
struct mutex ctrl_mutex; /*
333+
* Protects ctrl.info,
334+
* ctrl.handle and
335+
* uvc_fh.pending_async_ctrls
336+
*/
333337

334338
struct v4l2_prio_state prio; /* V4L2 priority state */
335339
u32 caps; /* V4L2 chain-wide caps */
@@ -604,6 +608,7 @@ struct uvc_fh {
604608
struct uvc_video_chain *chain;
605609
struct uvc_streaming *stream;
606610
enum uvc_handle_state state;
611+
unsigned int pending_async_ctrls;
607612
};
608613

609614
struct uvc_driver {
@@ -788,6 +793,8 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
788793
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
789794
struct uvc_xu_control_query *xqry);
790795

796+
void uvc_ctrl_cleanup_fh(struct uvc_fh *handle);
797+
791798
/* Utility functions */
792799
struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
793800
u8 epaddr);

0 commit comments

Comments
 (0)