Skip to content

Commit

Permalink
ALSA: ua101: fix crash when unplugging
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Clemens Ladisch authored and Takashi Iwai committed Nov 6, 2011
1 parent 6bcbf64 commit 862a624
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions sound/usb/misc/ua101.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream)
unsigned int i;

for (i = 0; i < stream->queue_length; ++i)
usb_kill_urb(&stream->urbs[i]->urb);
if (stream->urbs[i])
usb_kill_urb(&stream->urbs[i]->urb);
}

static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index)
Expand All @@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index)
{
struct usb_host_interface *alts;

if (!ua->intf[intf_index])
return;

alts = ua->intf[intf_index]->cur_altsetting;
if (alts->desc.bAlternateSetting != 0) {
int err = usb_set_interface(ua->dev,
Expand Down Expand Up @@ -1144,27 +1148,37 @@ static void free_stream_urbs(struct ua101_stream *stream)
{
unsigned int i;

for (i = 0; i < stream->queue_length; ++i)
for (i = 0; i < stream->queue_length; ++i) {
kfree(stream->urbs[i]);
stream->urbs[i] = NULL;
}
}

static void free_usb_related_resources(struct ua101 *ua,
struct usb_interface *interface)
{
unsigned int i;
struct usb_interface *intf;

mutex_lock(&ua->mutex);
free_stream_urbs(&ua->capture);
free_stream_urbs(&ua->playback);
mutex_unlock(&ua->mutex);
free_stream_buffers(ua, &ua->capture);
free_stream_buffers(ua, &ua->playback);

for (i = 0; i < ARRAY_SIZE(ua->intf); ++i)
if (ua->intf[i]) {
usb_set_intfdata(ua->intf[i], NULL);
if (ua->intf[i] != interface)
for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) {
mutex_lock(&ua->mutex);
intf = ua->intf[i];
ua->intf[i] = NULL;
mutex_unlock(&ua->mutex);
if (intf) {
usb_set_intfdata(intf, NULL);
if (intf != interface)
usb_driver_release_interface(&ua101_driver,
ua->intf[i]);
intf);
}
}
}

static void ua101_card_free(struct snd_card *card)
Expand Down

0 comments on commit 862a624

Please sign in to comment.