| From d15d662e89fc667b90cd294b0eb45694e33144da Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Mon, 12 Feb 2018 15:20:51 +0100 |
| Subject: ALSA: seq: Fix racy pool initializations |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit d15d662e89fc667b90cd294b0eb45694e33144da upstream. |
| |
| ALSA sequencer core initializes the event pool on demand by invoking |
| snd_seq_pool_init() when the first write happens and the pool is |
| empty. Meanwhile user can reset the pool size manually via ioctl |
| concurrently, and this may lead to UAF or out-of-bound accesses since |
| the function tries to vmalloc / vfree the buffer. |
| |
| A simple fix is to just wrap the snd_seq_pool_init() call with the |
| recently introduced client->ioctl_mutex; as the calls for |
| snd_seq_pool_init() from other side are always protected with this |
| mutex, we can avoid the race. |
| |
| Reported-by: 范龙飞 <long7573@126.com> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/core/seq/seq_clientmgr.c | 8 ++++++-- |
| 1 file changed, 6 insertions(+), 2 deletions(-) |
| |
| --- a/sound/core/seq/seq_clientmgr.c |
| +++ b/sound/core/seq/seq_clientmgr.c |
| @@ -1012,7 +1012,7 @@ static ssize_t snd_seq_write(struct file |
| { |
| struct snd_seq_client *client = file->private_data; |
| int written = 0, len; |
| - int err = -EINVAL; |
| + int err; |
| struct snd_seq_event event; |
| |
| if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT)) |
| @@ -1027,11 +1027,15 @@ static ssize_t snd_seq_write(struct file |
| |
| /* allocate the pool now if the pool is not allocated yet */ |
| if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { |
| - if (snd_seq_pool_init(client->pool) < 0) |
| + mutex_lock(&client->ioctl_mutex); |
| + err = snd_seq_pool_init(client->pool); |
| + mutex_unlock(&client->ioctl_mutex); |
| + if (err < 0) |
| return -ENOMEM; |
| } |
| |
| /* only process whole events */ |
| + err = -EINVAL; |
| while (count >= sizeof(struct snd_seq_event)) { |
| /* Read in the event header from the user */ |
| len = sizeof(event); |