CVE-2017-16528: Use After Free (CWE-416)
value: sound/core/seq_device.c in the Linux kernel before 4.13.4 allows local users to cause a denial of service (snd_rawmidi_dev_seq_free use-after-free and system crash) or possibly have unspecified other impact via a crafted USB device.
CWE description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
CVSS v3 base score: 6.6
Published: 2017-11-04T01:29Z
Repository: https://github.com/torvalds/linux
Language: C
Files changed: sound/core/seq_device.c
Commit date: 2017-09-12 12:41:20 +0200
Commit message: ALSA: seq: Cancel pending autoload work at unbinding device

ALSA sequencer core has a mechanism to load the enumerated devices
automatically, and it's performed in an off-load work.  This seems
causing some race when a sequencer is removed while the pending
autoload work is running.  As syzkaller spotted, it may lead to some
use-after-free:
  BUG: KASAN: use-after-free in snd_rawmidi_dev_seq_free+0x69/0x70
  sound/core/rawmidi.c:1617
  Write of size 8 at addr ffff88006c611d90 by task kworker/2:1/567

  CPU: 2 PID: 567 Comm: kworker/2:1 Not tainted 4.13.0+ #29
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
  Workqueue: events autoload_drivers
  Call Trace:
   __dump_stack lib/dump_stack.c:16 [inline]
   dump_stack+0x192/0x22c lib/dump_stack.c:52
   print_address_description+0x78/0x280 mm/kasan/report.c:252
   kasan_report_error mm/kasan/report.c:351 [inline]
   kasan_report+0x230/0x340 mm/kasan/report.c:409
   __asan_report_store8_noabort+0x1c/0x20 mm/kasan/report.c:435
   snd_rawmidi_dev_seq_free+0x69/0x70 sound/core/rawmidi.c:1617
   snd_seq_dev_release+0x4f/0x70 sound/core/seq_device.c:192
   device_release+0x13f/0x210 drivers/base/core.c:814
   kobject_cleanup lib/kobject.c:648 [inline]
   kobject_release lib/kobject.c:677 [inline]
   kref_put include/linux/kref.h:70 [inline]
   kobject_put+0x145/0x240 lib/kobject.c:694
   put_device+0x25/0x30 drivers/base/core.c:1799
   klist_devices_put+0x36/0x40 drivers/base/bus.c:827
   klist_next+0x264/0x4a0 lib/klist.c:403
   next_device drivers/base/bus.c:270 [inline]
   bus_for_each_dev+0x17e/0x210 drivers/base/bus.c:312
   autoload_drivers+0x3b/0x50 sound/core/seq_device.c:117
   process_one_work+0x9fb/0x1570 kernel/workqueue.c:2097
   worker_thread+0x1e4/0x1350 kernel/workqueue.c:2231
   kthread+0x324/0x3f0 kernel/kthread.c:231
   ret_from_fork+0x25/0x30 arch/x86/entry/entry_64.S:425

The fix is simply to assure canceling the autoload work at removing
the device.

Reported-by: Andrey Konovalov <andreyknvl@google.com>
Tested-by: Andrey Konovalov <andreyknvl@google.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Diff: diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c
index c4acf17e9f5e50..e40a2cba5002a8 100644
--- a/sound/core/seq_device.c
+++ b/sound/core/seq_device.c
@@ -146,21 +146,24 @@ void snd_seq_device_load_drivers(void)
 {
 	queue_autoload_drivers();
 	flush_work(&autoload_work);
 }
 EXPORT_SYMBOL(snd_seq_device_load_drivers);
+#define cancel_autoload_drivers()	cancel_work_sync(&autoload_work)
 #else
 #define queue_autoload_drivers() /* NOP */
+#define cancel_autoload_drivers() /* NOP */
 #endif
 
 /*
  * device management
  */
 static int snd_seq_device_dev_free(struct snd_device *device)
 {
 	struct snd_seq_device *dev = device->device_data;
 
+	cancel_autoload_drivers();
 	put_device(&dev->dev);
 	return 0;
 }
 
 static int snd_seq_device_dev_register(struct snd_device *device)

Fixed code: #define cancel_autoload_drivers()	cancel_work_sync(&autoload_work)
#define cancel_autoload_drivers() /* NOP */
	cancel_autoload_drivers();