From 0b6221081620b9c5f1ddaeb29dfe6ca1311049cd Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Apr 03 2012 17:49:57 +0000 Subject: Fix crash in uvc_video_clock_update from Laurent Pinchart (rhbz 806433) --- diff --git a/kernel.spec b/kernel.spec index 84440e8..905deda 100644 --- a/kernel.spec +++ b/kernel.spec @@ -54,7 +54,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 2 +%global baserelease 3 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -779,6 +779,9 @@ Patch21351: x86-add-io_apic_ops-to-allow-interception.patch Patch21352: x86-apic_ops-Replace-apic_ops-with-x86_apic_ops.patch Patch21353: xen-x86-Implement-x86_apic_ops.patch +#rhbz 806433 +Patch21360: uvcvideo-Fix-race-induced-crash-in-uvc_video_clock_update.patch + #rhbz 770476 Patch21370: iwlegacy-do-not-nulify-il-vif-on-reset.patch Patch21371: iwlwifi-do-not-nulify-ctx-vif-on-reset.patch @@ -1472,6 +1475,9 @@ ApplyPatch nfs-Fix-length-of-buffer-copied-in-__nfs4_get_acl_uncached.patch #rhbz 808207 CVE-2012-1601 ApplyPatch KVM-Ensure-all-vcpus-are-consistent-with-in-kernel-i.patch +#rhbz 806433 +ApplyPatch uvcvideo-Fix-race-induced-crash-in-uvc_video_clock_update.patch + # END OF PATCH APPLICATIONS %endif @@ -2210,6 +2216,9 @@ fi # and build. %changelog +* Tue Apr 03 2012 Josh Boyer +- Fix crash in uvc_video_clock_update from Laurent Pinchart (rhbz 806433) + * Mon Apr 02 2012 Dave Jones 3.3.1-2 - Disable CONFIG_DEBUG_PAGEALLOC in -debug builds again. diff --git a/uvcvideo-Fix-race-induced-crash-in-uvc_video_clock_update.patch b/uvcvideo-Fix-race-induced-crash-in-uvc_video_clock_update.patch new file mode 100644 index 0000000..5f2a1c0 --- /dev/null +++ b/uvcvideo-Fix-race-induced-crash-in-uvc_video_clock_update.patch @@ -0,0 +1,113 @@ +@@ -, +, @@ + drivers/media/video/uvc/uvc_video.c | 50 ++++++++++++++++++++++------------ + 1 files changed, 32 insertions(+), 18 deletions(-) +--- a/drivers/media/video/uvc/uvc_video.c ++++ a/drivers/media/video/uvc/uvc_video.c +@@ -468,22 +468,30 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, + 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_streaming *stream, int free_buffers) + + if (free_buffers) + uvc_free_urb_buffers(stream); +- +- uvc_video_clock_cleanup(stream); + } + + /* +@@ -1555,10 +1561,6 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) + + 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_streaming *stream, int reset) + + 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_streaming *stream, int enable) + 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; + }