]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.1.1/alsa-ua101-fix-crash-when-unplugging.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.1.1 / alsa-ua101-fix-crash-when-unplugging.patch
CommitLineData
7c604272
GKH
1From 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 Mon Sep 17 00:00:00 2001
2From: Clemens Ladisch <clemens@ladisch.de>
3Date: Sat, 15 Oct 2011 23:19:25 +0200
4Subject: ALSA: ua101: fix crash when unplugging
5
6From: Clemens Ladisch <clemens@ladisch.de>
7
8commit 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 upstream.
9
10If the device is unplugged while running, it is possible for a PCM
11device to be closed after the disconnect callback has returned. This
12means that kill_stream_urb() and disable_iso_interface() would try to
13access already-invalid or freed USB data structures.
14
15The function free_usb_related_resources() was intended to prevent this,
16but forgot to clear the affected variables.
17
18Reported-and-tested-by: Olivier Courtay <olivier@courtay.org>
19Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
20Signed-off-by: Takashi Iwai <tiwai@suse.de>
21Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
22
23---
24 sound/usb/misc/ua101.c | 28 +++++++++++++++++++++-------
25 1 file changed, 21 insertions(+), 7 deletions(-)
26
27--- a/sound/usb/misc/ua101.c
28+++ b/sound/usb/misc/ua101.c
29@@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua10
30 unsigned int i;
31
32 for (i = 0; i < stream->queue_length; ++i)
33- usb_kill_urb(&stream->urbs[i]->urb);
34+ if (stream->urbs[i])
35+ usb_kill_urb(&stream->urbs[i]->urb);
36 }
37
38 static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index)
39@@ -484,6 +485,9 @@ static void disable_iso_interface(struct
40 {
41 struct usb_host_interface *alts;
42
43+ if (!ua->intf[intf_index])
44+ return;
45+
46 alts = ua->intf[intf_index]->cur_altsetting;
47 if (alts->desc.bAlternateSetting != 0) {
48 int err = usb_set_interface(ua->dev,
49@@ -1144,27 +1148,37 @@ static void free_stream_urbs(struct ua10
50 {
51 unsigned int i;
52
53- for (i = 0; i < stream->queue_length; ++i)
54+ for (i = 0; i < stream->queue_length; ++i) {
55 kfree(stream->urbs[i]);
56+ stream->urbs[i] = NULL;
57+ }
58 }
59
60 static void free_usb_related_resources(struct ua101 *ua,
61 struct usb_interface *interface)
62 {
63 unsigned int i;
64+ struct usb_interface *intf;
65
66+ mutex_lock(&ua->mutex);
67 free_stream_urbs(&ua->capture);
68 free_stream_urbs(&ua->playback);
69+ mutex_unlock(&ua->mutex);
70 free_stream_buffers(ua, &ua->capture);
71 free_stream_buffers(ua, &ua->playback);
72
73- for (i = 0; i < ARRAY_SIZE(ua->intf); ++i)
74- if (ua->intf[i]) {
75- usb_set_intfdata(ua->intf[i], NULL);
76- if (ua->intf[i] != interface)
77+ for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) {
78+ mutex_lock(&ua->mutex);
79+ intf = ua->intf[i];
80+ ua->intf[i] = NULL;
81+ mutex_unlock(&ua->mutex);
82+ if (intf) {
83+ usb_set_intfdata(intf, NULL);
84+ if (intf != interface)
85 usb_driver_release_interface(&ua101_driver,
86- ua->intf[i]);
87+ intf);
88 }
89+ }
90 }
91
92 static void ua101_card_free(struct snd_card *card)