diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2011-10-15 17:19:25 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-11-06 05:21:42 -0500 |
commit | 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 (patch) | |
tree | c2b1afb1818dd722c7026ebd0047972a32845d20 /sound | |
parent | 6bcbf64ace40d6833622d85701218a8bb7a4f207 (diff) |
ALSA: ua101: fix crash when unplugging
If the device is unplugged while running, it is possible for a PCM
device to be closed after the disconnect callback has returned. This
means that kill_stream_urb() and disable_iso_interface() would try to
access already-invalid or freed USB data structures.
The function free_usb_related_resources() was intended to prevent this,
but forgot to clear the affected variables.
Reported-and-tested-by: Olivier Courtay <olivier@courtay.org>
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Cc: 2.6.33+ <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/misc/ua101.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 67bec7612442..c0609c210303 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c | |||
@@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream) | |||
459 | unsigned int i; | 459 | unsigned int i; |
460 | 460 | ||
461 | for (i = 0; i < stream->queue_length; ++i) | 461 | for (i = 0; i < stream->queue_length; ++i) |
462 | usb_kill_urb(&stream->urbs[i]->urb); | 462 | if (stream->urbs[i]) |
463 | usb_kill_urb(&stream->urbs[i]->urb); | ||
463 | } | 464 | } |
464 | 465 | ||
465 | static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) | 466 | static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) |
@@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) | |||
484 | { | 485 | { |
485 | struct usb_host_interface *alts; | 486 | struct usb_host_interface *alts; |
486 | 487 | ||
488 | if (!ua->intf[intf_index]) | ||
489 | return; | ||
490 | |||
487 | alts = ua->intf[intf_index]->cur_altsetting; | 491 | alts = ua->intf[intf_index]->cur_altsetting; |
488 | if (alts->desc.bAlternateSetting != 0) { | 492 | if (alts->desc.bAlternateSetting != 0) { |
489 | int err = usb_set_interface(ua->dev, | 493 | int err = usb_set_interface(ua->dev, |
@@ -1144,27 +1148,37 @@ static void free_stream_urbs(struct ua101_stream *stream) | |||
1144 | { | 1148 | { |
1145 | unsigned int i; | 1149 | unsigned int i; |
1146 | 1150 | ||
1147 | for (i = 0; i < stream->queue_length; ++i) | 1151 | for (i = 0; i < stream->queue_length; ++i) { |
1148 | kfree(stream->urbs[i]); | 1152 | kfree(stream->urbs[i]); |
1153 | stream->urbs[i] = NULL; | ||
1154 | } | ||
1149 | } | 1155 | } |
1150 | 1156 | ||
1151 | static void free_usb_related_resources(struct ua101 *ua, | 1157 | static void free_usb_related_resources(struct ua101 *ua, |
1152 | struct usb_interface *interface) | 1158 | struct usb_interface *interface) |
1153 | { | 1159 | { |
1154 | unsigned int i; | 1160 | unsigned int i; |
1161 | struct usb_interface *intf; | ||
1155 | 1162 | ||
1163 | mutex_lock(&ua->mutex); | ||
1156 | free_stream_urbs(&ua->capture); | 1164 | free_stream_urbs(&ua->capture); |
1157 | free_stream_urbs(&ua->playback); | 1165 | free_stream_urbs(&ua->playback); |
1166 | mutex_unlock(&ua->mutex); | ||
1158 | free_stream_buffers(ua, &ua->capture); | 1167 | free_stream_buffers(ua, &ua->capture); |
1159 | free_stream_buffers(ua, &ua->playback); | 1168 | free_stream_buffers(ua, &ua->playback); |
1160 | 1169 | ||
1161 | for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) | 1170 | for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) { |
1162 | if (ua->intf[i]) { | 1171 | mutex_lock(&ua->mutex); |
1163 | usb_set_intfdata(ua->intf[i], NULL); | 1172 | intf = ua->intf[i]; |
1164 | if (ua->intf[i] != interface) | 1173 | ua->intf[i] = NULL; |
1174 | mutex_unlock(&ua->mutex); | ||
1175 | if (intf) { | ||
1176 | usb_set_intfdata(intf, NULL); | ||
1177 | if (intf != interface) | ||
1165 | usb_driver_release_interface(&ua101_driver, | 1178 | usb_driver_release_interface(&ua101_driver, |
1166 | ua->intf[i]); | 1179 | intf); |
1167 | } | 1180 | } |
1181 | } | ||
1168 | } | 1182 | } |
1169 | 1183 | ||
1170 | static void ua101_card_free(struct snd_card *card) | 1184 | static void ua101_card_free(struct snd_card *card) |