Patch "ALSA: seq: 2nd attempt at fixing race creating a queue" has been added to the 4.12-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
ALSA: seq: 2nd attempt at fixing race creating a queue
to the 4.12-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
alsa-seq-2nd-attempt-at-fixing-race-creating-a-queue.patch
and it can be found in the queue-4.12 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
7e1d90f60a0d501c8503e636942ca704a454d910Mon Sep 17 00:00:00 2001
From: Daniel Mentz <[email protected]>
Date: Mon, 14 Aug 2017 14:46:01 -0700
Subject: ALSA: seq: 2nd attempt at fixing race creating a queue
From: Daniel Mentz <[email protected]>
commit 7e1d90f60a0d501c8503e636942ca704a454d910 upstream.
commit 4842e98f26dd80be3623c4714a244ba52ea096a8 ("ALSA: seq: Fix race at creating a queue") attempted to fix a race reported by syzkaller. That fix has been described as follows:
"
When a sequencer queue is created in snd_seq_queue_alloc(),it adds the new queue element to the public list before referencing it. Thus the queue might be deleted before the call of snd_seq_queue_use(), and it results in the use-after-free error, as spotted by syzkaller.
The fix is to reference the queue object at the right time. "
Even with that fix in place, syzkaller reported a use-after-free error. It specifically pointed to the last instruction "return q->queue" in snd_seq_queue_alloc(). The pointer q is being used after kfree() has been called on it.
It turned out that there is still a small window where a race can happen. The window opens at snd_seq_ioctl_create_queue()->snd_seq_queue_alloc()->queue_list_add() and closes at snd_seq_ioctl_create_queue()->queueptr()->snd_use_lock_use(). Between these two calls, a different thread could delete the queue and possibly re-create a different queue in the same location in queue_list.
This change prevents this situation by calling snd_use_lock_use() from snd_seq_queue_alloc() prior to calling queue_list_add(). It is then the caller's responsibility to call snd_use_lock_free(&q->use_lock).
--- sound/core/seq/seq_clientmgr.c | 13 ++++--------- sound/core/seq/seq_queue.c | 14 +++++++++----- sound/core/seq/seq_queue.h | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-)
sound/core/seq/seq_clientmgr.c +4 -9
@@ -1502,16 +1502,11 @@ static int snd_seq_ioctl_unsubscribe_porstatic int snd_seq_ioctl_create_queue (struct snd_seq_client *client,void *arg) {struct snd_seq_queue_info *info = arg; -int result;struct snd_seq_queue *q; - result =snd_seq_queue_alloc (client->number, info->locked, info->flags); -if (result <0 ) -return result; - - q =queueptr (result); -if (q ==NULL ) -return -EINVAL ; + q =snd_seq_queue_alloc (client->number, info->locked, info->flags); +if (IS_ERR (q)) +return PTR_ERR (q); info->queue = q->queue; info->locked = q->locked;
@@ -1521,7 +1516,7 @@ static int snd_seq_ioctl_create_queue(stif (!info->name[0 ])snprintf (info->name,sizeof (info->name),"Queue-%d" , q->queue);strlcpy (q->name, info->name,sizeof (q->name)); -queuefree (q); +snd_use_lock_free (&q->use_lock);return 0 ; }
sound/core/seq/seq_queue.c +9 -5
@@ -184,22 +184,26 @@ void __exit snd_seq_queues_delete(void)static void queue_use (struct snd_seq_queue *queue,int client,int use);/* allocate a new queue - -* return queue index value or negative value for error +* return pointer to new queue or ERR_PTR(-errno) for error +* The new queue's use_lock is set to 1. It is the caller's responsibility to +* call snd_use_lock_free(&q->use_lock). */ -int snd_seq_queue_alloc (int client,int locked,unsigned int info_flags) +struct snd_seq_queue *snd_seq_queue_alloc (int client,int locked,unsigned int info_flags) {struct snd_seq_queue *q; q =queue_new (client, locked);if (q ==NULL ) -return -ENOMEM ; +return ERR_PTR (-ENOMEM ); q->info_flags = info_flags;queue_use (q, client,1 ); +snd_use_lock_use (&q->use_lock);if (queue_list_add (q) <0 ) { +snd_use_lock_free (&q->use_lock);queue_delete (q); -return -ENOMEM ; +return ERR_PTR (-ENOMEM ); } -return q->queue; +return q; }/* delete a queue - queue must be owned by the client */
sound/core/seq/seq_queue.h +1 -1
@@ -71,7 +71,7 @@ void snd_seq_queues_delete(void);/* create new queue (constructor) */ -int snd_seq_queue_alloc (int client,int locked,unsigned int flags); +struct snd_seq_queue *snd_seq_queue_alloc (int client,int locked,unsigned int flags);/* delete queue (destructor) */ int snd_seq_queue_delete (int client,int queueid);
Patches currently in stable-queue which might be from [email protected] are
queue-4.12/alsa-seq-2nd-attempt-at-fixing-race-creating-a-queue.patch