]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ALSA: seq: Fix a potential UAF by wrong private_free call order
authorTakashi Iwai <tiwai@suse.de>
Thu, 30 Sep 2021 11:41:14 +0000 (13:41 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Oct 2021 09:40:12 +0000 (11:40 +0200)
commit 1f8763c59c4ec6254d629fe77c0a52220bd907aa upstream.

John Keeping reported and posted a patch for a potential UAF in
rawmidi sequencer destruction: the snd_rawmidi_dev_seq_free() may be
called after the associated rawmidi object got already freed.
After a deeper look, it turned out that the bug is rather the
incorrect private_free call order for a snd_seq_device.  The
snd_seq_device private_free gets called at the release callback of the
sequencer device object, while this was rather expected to be executed
at the snd_device call chains that runs at the beginning of the whole
card-free procedure.  It's been broken since the rewrite of
sequencer-device binding (although it hasn't surfaced because the
sequencer device release happens usually right along with the card
device release).

This patch corrects the private_free call to be done in the right
place, at snd_seq_device_dev_free().

Fixes: 343f01de38f4 ("ALSA: seq: Rewrite sequencer device binding with standard bus")
Reported-and-tested-by: John Keeping <john@metanate.com>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210930114114.8645-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
sound/core/seq_device.c

index e9dbad93f9d09da4acf542a77169dee0e8b0560f..c9223049551c4d505ac11162ed527e644fa0b6ad 100644 (file)
@@ -147,6 +147,8 @@ static int snd_seq_device_dev_free(struct snd_device *device)
        struct snd_seq_device *dev = device->device_data;
 
        cancel_autoload_drivers();
+       if (dev->private_free)
+               dev->private_free(dev);
        put_device(&dev->dev);
        return 0;
 }
@@ -174,11 +176,7 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
 
 static void snd_seq_dev_release(struct device *dev)
 {
-       struct snd_seq_device *sdev = to_seq_dev(dev);
-
-       if (sdev->private_free)
-               sdev->private_free(sdev);
-       kfree(sdev);
+       kfree(to_seq_dev(dev));
 }
 
 /*