Commit 1f8763c5 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: seq: Fix a potential UAF by wrong private_free call order

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: 7c37ae5c ("ALSA: seq: Rewrite sequencer device binding with standard bus")
Reported-and-tested-by: default avatarJohn Keeping <john@metanate.com>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210930114114.8645-1-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent eb676622
...@@ -156,6 +156,8 @@ static int snd_seq_device_dev_free(struct snd_device *device) ...@@ -156,6 +156,8 @@ static int snd_seq_device_dev_free(struct snd_device *device)
struct snd_seq_device *dev = device->device_data; struct snd_seq_device *dev = device->device_data;
cancel_autoload_drivers(); cancel_autoload_drivers();
if (dev->private_free)
dev->private_free(dev);
put_device(&dev->dev); put_device(&dev->dev);
return 0; return 0;
} }
...@@ -183,11 +185,7 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) ...@@ -183,11 +185,7 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
static void snd_seq_dev_release(struct device *dev) static void snd_seq_dev_release(struct device *dev)
{ {
struct snd_seq_device *sdev = to_seq_dev(dev); kfree(to_seq_dev(dev));
if (sdev->private_free)
sdev->private_free(sdev);
kfree(sdev);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment