A data race between snd_seq_oss_midi_open and snd_seq_oss_midi_filemode
Hi there,
We found a data race could happen between snd_seq_oss_midi_open() and snd_seq_oss_midi_filemode() over the variable mdev->opened.
When running concurrently, snd_seq_oss_midi_open() makes the return value of snd_seq_oss_midi_filemode() non-deterministic: Thread-1 Thread-2 //snd_seq_oss_midi_filemode() //snd_seq_oss_midi_open() if (mdev->opened & PERM_WRITE) mode |= SNDRV_SEQ_OSS_FILE_WRITE; mdev->opened |= PERM_READ; if (mdev->opened & PERM_READ) mode |= SNDRV_SEQ_OSS_FILE_READ;
It is not clear to us that whether this is a serious problem but we would like to report this just in case.
Thanks, Sishuai
On Mon, 29 May 2023 22:11:24 +0200, Gong, Sishuai wrote:
Hi there,
We found a data race could happen between snd_seq_oss_midi_open() and snd_seq_oss_midi_filemode() over the variable mdev->opened.
When running concurrently, snd_seq_oss_midi_open() makes the return value of snd_seq_oss_midi_filemode() non-deterministic: Thread-1 Thread-2 //snd_seq_oss_midi_filemode() //snd_seq_oss_midi_open() if (mdev->opened & PERM_WRITE) mode |= SNDRV_SEQ_OSS_FILE_WRITE; mdev->opened |= PERM_READ; if (mdev->opened & PERM_READ) mode |= SNDRV_SEQ_OSS_FILE_READ;
It is not clear to us that whether this is a serious problem but we would like to report this just in case.
Thanks for the report. Yes, the value may be overridden with the race, as the code there has no protection. But this shouldn't bring too serious problems like data corruption. At most, it'll lead to some errors by doubly opens or such.
In anyway, below is the attempt to address the issue.
Takashi
-- 8< -- From: Takashi Iwai tiwai@suse.de Subject: [PATCH] ALSA: seq: oss: Fix racy open/close of MIDI devices
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: "Gong, Sishuai" sishuai@purdue.edu Closes: https://lore.kernel.org/r/7DC9AF71-F481-4ABA-955F-76C535661E33@purdue.edu Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/seq/oss/seq_oss_midi.c | 35 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 07efb38f58ac..f2940b29595f 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -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; };
@@ -172,6 +173,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 */ strscpy(mdev->name, pinfo->name, sizeof(mdev->name)); @@ -322,15 +324,17 @@ 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;
mdev = get_mididev(dp, dev); if (!mdev) 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; @@ -340,14 +344,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; @@ -372,13 +376,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; }
/* @@ -393,10 +401,9 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) mdev = get_mididev(dp, dev); if (!mdev) 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) { @@ -415,6 +422,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; }
participants (2)
-
Gong, Sishuai
-
Takashi Iwai