ALSA: ua101: fix crash when unplugging

commit 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 upstream.

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>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index fb5d68f..96c381e 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -459,7 +459,8 @@
 	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)
@@ -484,6 +485,9 @@
 {
 	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,
@@ -1144,27 +1148,37 @@
 {
 	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)