Skip to content

Commit ed0ee0c

Browse files
pinchartlMauro Carvalho Chehab
authored and
Mauro Carvalho Chehab
committedApr 9, 2012
[media] uvcvideo: Fix race-related crash in uvc_video_clock_update()
The driver frees the clock samples buffer before stopping the video buffers queue. If a DQBUF call arrives in-between, uvc_video_clock_update() will be called with a NULL clock samples buffer, leading to a crash. This occurs very frequently when using the webcam with the flash browser plugin. Move clock initialization/cleanup to uvc_video_enable() in order to free the clock samples buffer after the queue is stopped. Make sure the clock is reset at resume time to avoid miscalculating timestamps. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
1 parent d3a92d6 commit ed0ee0c

File tree

1 file changed

+32
-18
lines changed

1 file changed

+32
-18
lines changed
 

‎drivers/media/video/uvc/uvc_video.c

+32-18
Original file line numberDiff line numberDiff line change
@@ -468,22 +468,30 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
468468
spin_unlock_irqrestore(&stream->clock.lock, flags);
469469
}
470470

471-
static int uvc_video_clock_init(struct uvc_streaming *stream)
471+
static void uvc_video_clock_reset(struct uvc_streaming *stream)
472472
{
473473
struct uvc_clock *clock = &stream->clock;
474474

475-
spin_lock_init(&clock->lock);
476475
clock->head = 0;
477476
clock->count = 0;
478-
clock->size = 32;
479477
clock->last_sof = -1;
480478
clock->sof_offset = -1;
479+
}
480+
481+
static int uvc_video_clock_init(struct uvc_streaming *stream)
482+
{
483+
struct uvc_clock *clock = &stream->clock;
484+
485+
spin_lock_init(&clock->lock);
486+
clock->size = 32;
481487

482488
clock->samples = kmalloc(clock->size * sizeof(*clock->samples),
483489
GFP_KERNEL);
484490
if (clock->samples == NULL)
485491
return -ENOMEM;
486492

493+
uvc_video_clock_reset(stream);
494+
487495
return 0;
488496
}
489497

@@ -1424,8 +1432,6 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
14241432

14251433
if (free_buffers)
14261434
uvc_free_urb_buffers(stream);
1427-
1428-
uvc_video_clock_cleanup(stream);
14291435
}
14301436

14311437
/*
@@ -1555,10 +1561,6 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
15551561

15561562
uvc_video_stats_start(stream);
15571563

1558-
ret = uvc_video_clock_init(stream);
1559-
if (ret < 0)
1560-
return ret;
1561-
15621564
if (intf->num_altsetting > 1) {
15631565
struct usb_host_endpoint *best_ep = NULL;
15641566
unsigned int best_psize = 3 * 1024;
@@ -1683,6 +1685,8 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
16831685

16841686
stream->frozen = 0;
16851687

1688+
uvc_video_clock_reset(stream);
1689+
16861690
ret = uvc_commit_video(stream, &stream->ctrl);
16871691
if (ret < 0) {
16881692
uvc_queue_enable(&stream->queue, 0);
@@ -1819,25 +1823,35 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
18191823
uvc_uninit_video(stream, 1);
18201824
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
18211825
uvc_queue_enable(&stream->queue, 0);
1826+
uvc_video_clock_cleanup(stream);
18221827
return 0;
18231828
}
18241829

1825-
ret = uvc_queue_enable(&stream->queue, 1);
1830+
ret = uvc_video_clock_init(stream);
18261831
if (ret < 0)
18271832
return ret;
18281833

1834+
ret = uvc_queue_enable(&stream->queue, 1);
1835+
if (ret < 0)
1836+
goto error_queue;
1837+
18291838
/* Commit the streaming parameters. */
18301839
ret = uvc_commit_video(stream, &stream->ctrl);
1831-
if (ret < 0) {
1832-
uvc_queue_enable(&stream->queue, 0);
1833-
return ret;
1834-
}
1840+
if (ret < 0)
1841+
goto error_commit;
18351842

18361843
ret = uvc_init_video(stream, GFP_KERNEL);
1837-
if (ret < 0) {
1838-
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
1839-
uvc_queue_enable(&stream->queue, 0);
1840-
}
1844+
if (ret < 0)
1845+
goto error_video;
1846+
1847+
return 0;
1848+
1849+
error_video:
1850+
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
1851+
error_commit:
1852+
uvc_queue_enable(&stream->queue, 0);
1853+
error_queue:
1854+
uvc_video_clock_cleanup(stream);
18411855

18421856
return ret;
18431857
}

0 commit comments

Comments
 (0)
Please sign in to comment.