Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81104041 authored by Takashi Iwai's avatar Takashi Iwai Committed by Greg Kroah-Hartman
Browse files

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: 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.de


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f74f1728
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -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));
}

/*