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

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

ALSA: seq: oss: Fix racy open/close of MIDI devices



[ Upstream commit 297224fc0922e7385573a30c29ffdabb67f27b7d ]

Although snd_seq_oss_midi_open() and snd_seq_oss_midi_close() can be
called concurrently from different code paths, we have no proper data
protection against races.  Introduce open_mutex to each seq_oss_midi
object for avoiding the races.

Reported-by: default avatar"Gong, Sishuai" <sishuai@purdue.edu>
Closes: https://lore.kernel.org/r/7DC9AF71-F481-4ABA-955F-76C535661E33@purdue.edu
Link: https://lore.kernel.org/r/20230612125533.27461-1-tiwai@suse.de


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 601dc776
Loading
Loading
Loading
Loading
+22 −13
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ struct seq_oss_midi {
	struct snd_midi_event *coder;	/* MIDI event coder */
	struct seq_oss_devinfo *devinfo;	/* assigned OSSseq device */
	snd_use_lock_t use_lock;
	struct mutex open_mutex;
};


@@ -171,6 +172,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
	mdev->flags = pinfo->capability;
	mdev->opened = 0;
	snd_use_lock_init(&mdev->use_lock);
	mutex_init(&mdev->open_mutex);

	/* copy and truncate the name of synth device */
	strlcpy(mdev->name, pinfo->name, sizeof(mdev->name));
@@ -319,14 +321,16 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
	int perm;
	struct seq_oss_midi *mdev;
	struct snd_seq_port_subscribe subs;
	int err;

	if ((mdev = get_mididev(dp, dev)) == NULL)
		return -ENODEV;

	mutex_lock(&mdev->open_mutex);
	/* already used? */
	if (mdev->opened && mdev->devinfo != dp) {
		snd_use_lock_free(&mdev->use_lock);
		return -EBUSY;
		err = -EBUSY;
		goto unlock;
	}

	perm = 0;
@@ -336,14 +340,14 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
		perm |= PERM_READ;
	perm &= mdev->flags;
	if (perm == 0) {
		snd_use_lock_free(&mdev->use_lock);
		return -ENXIO;
		err = -ENXIO;
		goto unlock;
	}

	/* already opened? */
	if ((mdev->opened & perm) == perm) {
		snd_use_lock_free(&mdev->use_lock);
		return 0;
		err = 0;
		goto unlock;
	}

	perm &= ~mdev->opened;
@@ -368,13 +372,17 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
	}

	if (! mdev->opened) {
		snd_use_lock_free(&mdev->use_lock);
		return -ENXIO;
		err = -ENXIO;
		goto unlock;
	}

	mdev->devinfo = dp;
	err = 0;

 unlock:
	mutex_unlock(&mdev->open_mutex);
	snd_use_lock_free(&mdev->use_lock);
	return 0;
	return err;
}

/*
@@ -388,10 +396,9 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)

	if ((mdev = get_mididev(dp, dev)) == NULL)
		return -ENODEV;
	if (! mdev->opened || mdev->devinfo != dp) {
		snd_use_lock_free(&mdev->use_lock);
		return 0;
	}
	mutex_lock(&mdev->open_mutex);
	if (!mdev->opened || mdev->devinfo != dp)
		goto unlock;

	memset(&subs, 0, sizeof(subs));
	if (mdev->opened & PERM_WRITE) {
@@ -410,6 +417,8 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
	mdev->opened = 0;
	mdev->devinfo = NULL;

 unlock:
	mutex_unlock(&mdev->open_mutex);
	snd_use_lock_free(&mdev->use_lock);
	return 0;
}