]>
Commit | Line | Data |
---|---|---|
7c604272 GKH |
1 | From 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 Mon Sep 17 00:00:00 2001 |
2 | From: Clemens Ladisch <clemens@ladisch.de> | |
3 | Date: Sat, 15 Oct 2011 23:19:25 +0200 | |
4 | Subject: ALSA: ua101: fix crash when unplugging | |
5 | ||
6 | From: Clemens Ladisch <clemens@ladisch.de> | |
7 | ||
8 | commit 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 upstream. | |
9 | ||
10 | If the device is unplugged while running, it is possible for a PCM | |
11 | device to be closed after the disconnect callback has returned. This | |
12 | means that kill_stream_urb() and disable_iso_interface() would try to | |
13 | access already-invalid or freed USB data structures. | |
14 | ||
15 | The function free_usb_related_resources() was intended to prevent this, | |
16 | but forgot to clear the affected variables. | |
17 | ||
18 | Reported-and-tested-by: Olivier Courtay <olivier@courtay.org> | |
19 | Signed-off-by: Clemens Ladisch <clemens@ladisch.de> | |
20 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
21 | Signed-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) |