From: Greg Kroah-Hartman Date: Wed, 11 Apr 2012 21:38:30 +0000 (-0700) Subject: 3.3-stable patches X-Git-Tag: v3.3.2~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=68a6a3a4aac67aacd0c6e21e575b3e80876cbd1b;p=thirdparty%2Fkernel%2Fstable-queue.git 3.3-stable patches added patches: uvcvideo-fix-race-related-crash-in-uvc_video_clock_update.patch --- diff --git a/queue-3.3/series b/queue-3.3/series index 477643ce5a6..9665383ead1 100644 --- a/queue-3.3/series +++ b/queue-3.3/series @@ -70,3 +70,4 @@ sched-x86-fix-overflow-in-cyc2ns_offset.patch mfd-clear-twl6030-irq-status-register-only-once.patch usb-add-motorola-rokr-e6-id-to-the-usbnet-driver-zaurus.patch ioat-fix-size-of-completion-for-xen.patch +uvcvideo-fix-race-related-crash-in-uvc_video_clock_update.patch diff --git a/queue-3.3/uvcvideo-fix-race-related-crash-in-uvc_video_clock_update.patch b/queue-3.3/uvcvideo-fix-race-related-crash-in-uvc_video_clock_update.patch new file mode 100644 index 00000000000..95468b8d2ae --- /dev/null +++ b/queue-3.3/uvcvideo-fix-race-related-crash-in-uvc_video_clock_update.patch @@ -0,0 +1,137 @@ +From ed0ee0ce0a3224dab5caa088a5f8b6df25924276 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 27 Mar 2012 05:51:00 -0300 +Subject: [media] uvcvideo: Fix race-related crash in uvc_video_clock_update() + +From: Laurent Pinchart + +commit ed0ee0ce0a3224dab5caa088a5f8b6df25924276 upstream. + +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 +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/video/uvc/uvc_video.c | 50 +++++++++++++++++++++++------------- + 1 file changed, 32 insertions(+), 18 deletions(-) + +--- a/drivers/media/video/uvc/uvc_video.c ++++ b/drivers/media/video/uvc/uvc_video.c +@@ -468,22 +468,30 @@ uvc_video_clock_decode(struct uvc_stream + spin_unlock_irqrestore(&stream->clock.lock, flags); + } + +-static int uvc_video_clock_init(struct uvc_streaming *stream) ++static void uvc_video_clock_reset(struct uvc_streaming *stream) + { + struct uvc_clock *clock = &stream->clock; + +- spin_lock_init(&clock->lock); + clock->head = 0; + clock->count = 0; +- clock->size = 32; + clock->last_sof = -1; + clock->sof_offset = -1; ++} ++ ++static int uvc_video_clock_init(struct uvc_streaming *stream) ++{ ++ struct uvc_clock *clock = &stream->clock; ++ ++ spin_lock_init(&clock->lock); ++ clock->size = 32; + + clock->samples = kmalloc(clock->size * sizeof(*clock->samples), + GFP_KERNEL); + if (clock->samples == NULL) + return -ENOMEM; + ++ uvc_video_clock_reset(stream); ++ + return 0; + } + +@@ -1424,8 +1432,6 @@ static void uvc_uninit_video(struct uvc_ + + if (free_buffers) + uvc_free_urb_buffers(stream); +- +- uvc_video_clock_cleanup(stream); + } + + /* +@@ -1555,10 +1561,6 @@ static int uvc_init_video(struct uvc_str + + uvc_video_stats_start(stream); + +- ret = uvc_video_clock_init(stream); +- if (ret < 0) +- return ret; +- + if (intf->num_altsetting > 1) { + struct usb_host_endpoint *best_ep = NULL; + unsigned int best_psize = 3 * 1024; +@@ -1683,6 +1685,8 @@ int uvc_video_resume(struct uvc_streamin + + stream->frozen = 0; + ++ uvc_video_clock_reset(stream); ++ + ret = uvc_commit_video(stream, &stream->ctrl); + if (ret < 0) { + uvc_queue_enable(&stream->queue, 0); +@@ -1819,25 +1823,35 @@ int uvc_video_enable(struct uvc_streamin + uvc_uninit_video(stream, 1); + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + uvc_queue_enable(&stream->queue, 0); ++ uvc_video_clock_cleanup(stream); + return 0; + } + +- ret = uvc_queue_enable(&stream->queue, 1); ++ ret = uvc_video_clock_init(stream); + if (ret < 0) + return ret; + ++ ret = uvc_queue_enable(&stream->queue, 1); ++ if (ret < 0) ++ goto error_queue; ++ + /* Commit the streaming parameters. */ + ret = uvc_commit_video(stream, &stream->ctrl); +- if (ret < 0) { +- uvc_queue_enable(&stream->queue, 0); +- return ret; +- } ++ if (ret < 0) ++ goto error_commit; + + ret = uvc_init_video(stream, GFP_KERNEL); +- if (ret < 0) { +- usb_set_interface(stream->dev->udev, stream->intfnum, 0); +- uvc_queue_enable(&stream->queue, 0); +- } ++ if (ret < 0) ++ goto error_video; ++ ++ return 0; ++ ++error_video: ++ usb_set_interface(stream->dev->udev, stream->intfnum, 0); ++error_commit: ++ uvc_queue_enable(&stream->queue, 0); ++error_queue: ++ uvc_video_clock_cleanup(stream); + + return ret; + }