diff options
author | Takashi Iwai <tiwai@suse.de> | 2021-09-30 13:41:14 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-10-27 09:32:37 +0200 |
commit | d050562c8adae0fbdfe62e66c8306ad1efd46046 (patch) | |
tree | ca7fcde66d066389b645784a959258356e9fddf6 | |
parent | c67099a5bc53d1a24058ba5afe873f16cd290e16 (diff) |
ALSA: seq: Fix a potential UAF by wrong private_free call order
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: 7c37ae5c625a ("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>
-rw-r--r-- | sound/core/seq/seq_device.c | 8 |
1 files changed, 3 insertions, 5 deletions
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index e40a2cba5002..5d16b2079119 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -162,6 +162,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; } @@ -189,11 +191,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)); } /* |