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

Commit 2ddac378 authored by Takashi Iwai's avatar Takashi Iwai Committed by Lee Jones
Browse files

BACKPORT: ALSA: pcm: Fix races among concurrent prealloc proc writes



commit 69534c48ba8ce552ce383b3dfdb271ffe51820c3 upstream.

We have no protection against concurrent PCM buffer preallocation
changes via proc files, and it may potentially lead to UAF or some
weird problem.  This patch applies the PCM open_mutex to the proc
write operation for avoiding the racy proc writes and the PCM stream
open (and further operations).

Bug: 232293337
Cc: <stable@vger.kernel.org>
Reviewed-by: default avatarJaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20220322170720.3529-5-tiwai@suse.de


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
[OP: backport to 5.4: adjusted context]
Signed-off-by: default avatarOvidiu Panait <ovidiu.panait@windriver.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
Change-Id: I52d0347c440b87c700b28e082eee9ab9d3ec4910
parent 6ef42e57
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -133,19 +133,20 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
	size_t size;
	size_t size;
	struct snd_dma_buffer new_dmab;
	struct snd_dma_buffer new_dmab;


	mutex_lock(&substream->pcm->open_mutex);
	if (substream->runtime) {
	if (substream->runtime) {
		buffer->error = -EBUSY;
		buffer->error = -EBUSY;
		return;
		goto unlock;
	}
	}
	if (!snd_info_get_line(buffer, line, sizeof(line))) {
	if (!snd_info_get_line(buffer, line, sizeof(line))) {
		snd_info_get_str(str, line, sizeof(str));
		snd_info_get_str(str, line, sizeof(str));
		size = simple_strtoul(str, NULL, 10) * 1024;
		size = simple_strtoul(str, NULL, 10) * 1024;
		if ((size != 0 && size < 8192) || size > substream->dma_max) {
		if ((size != 0 && size < 8192) || size > substream->dma_max) {
			buffer->error = -EINVAL;
			buffer->error = -EINVAL;
			return;
			goto unlock;
		}
		}
		if (substream->dma_buffer.bytes == size)
		if (substream->dma_buffer.bytes == size)
			return;
			goto unlock;
		memset(&new_dmab, 0, sizeof(new_dmab));
		memset(&new_dmab, 0, sizeof(new_dmab));
		new_dmab.dev = substream->dma_buffer.dev;
		new_dmab.dev = substream->dma_buffer.dev;
		if (size > 0) {
		if (size > 0) {
@@ -153,7 +154,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
						substream->dma_buffer.dev.dev,
						substream->dma_buffer.dev.dev,
						size, &new_dmab) < 0) {
						size, &new_dmab) < 0) {
				buffer->error = -ENOMEM;
				buffer->error = -ENOMEM;
				return;
				goto unlock;
			}
			}
			substream->buffer_bytes_max = size;
			substream->buffer_bytes_max = size;
		} else {
		} else {
@@ -165,6 +166,8 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
	} else {
	} else {
		buffer->error = -EINVAL;
		buffer->error = -EINVAL;
	}
	}
 unlock:
	mutex_unlock(&substream->pcm->open_mutex);
}
}


static inline void preallocate_info_init(struct snd_pcm_substream *substream)
static inline void preallocate_info_init(struct snd_pcm_substream *substream)