ALSA: rawmidi: Take open_mutex around parameter changes
authorTakashi Iwai <tiwai@suse.de>
Fri, 17 Jun 2022 14:40:49 +0000 (16:40 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 20 Jun 2022 07:36:02 +0000 (09:36 +0200)
The input/output parameter changes are pretty intrusive, possibly
involving with the buffer resizing operation.  Hence those should be
performed exclusively; otherwise some ugly race could happen.

This patch puts the existing open_mutex for snd_rawmidi_input_params()
and *_output_params() for protecting the concurrent calls.  Since
those are exported, it's also meant for hardening from the external
calls, too.

Link: https://lore.kernel.org/r/20220617144051.18985-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/rawmidi.c

index 0a00f37..7fd6b36 100644 (file)
@@ -712,11 +712,19 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
 int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
                              struct snd_rawmidi_params *params)
 {
-       if (substream->append && substream->use_count > 1)
-               return -EBUSY;
+       int err;
+
        snd_rawmidi_drain_output(substream);
-       substream->active_sensing = !params->no_active_sensing;
-       return resize_runtime_buffer(substream, params, false);
+       mutex_lock(&substream->rmidi->open_mutex);
+       if (substream->append && substream->use_count > 1)
+               err = -EBUSY;
+       else
+               err = resize_runtime_buffer(substream, params, false);
+
+       if (!err)
+               substream->active_sensing = !params->no_active_sensing;
+       mutex_unlock(&substream->rmidi->open_mutex);
+       return err;
 }
 EXPORT_SYMBOL(snd_rawmidi_output_params);
 
@@ -727,19 +735,22 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
        unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK;
        int err;
 
+       snd_rawmidi_drain_input(substream);
+       mutex_lock(&substream->rmidi->open_mutex);
        if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
-               return -EINVAL;
+               err = -EINVAL;
        else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
-               return -EINVAL;
-       if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
-               return -EINVAL;
-       snd_rawmidi_drain_input(substream);
-       err = resize_runtime_buffer(substream, params, true);
-       if (err < 0)
-               return err;
+               err = -EINVAL;
+       else if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
+               err = -EINVAL;
+       else
+               err = resize_runtime_buffer(substream, params, true);
 
-       substream->framing = framing;
-       substream->clock_type = clock_type;
+       if (!err) {
+               substream->framing = framing;
+               substream->clock_type = clock_type;
+       }
+       mutex_unlock(&substream->rmidi->open_mutex);
        return 0;
 }
 EXPORT_SYMBOL(snd_rawmidi_input_params);