mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
ALSA: seq: Fix double port list deletion
The commit [7f0973e973cd: ALSA: seq: Fix lockdep warnings due to
double mutex locks] split the management of two linked lists (source
and destination) into two individual calls for avoiding the AB/BA
deadlock. However, this may leave the possible double deletion of one
of two lists when the counterpart is being deleted concurrently.
It ends up with a list corruption, as revealed by syzkaller fuzzer.
This patch fixes it by checking the list emptiness and skipping the
deletion and the following process.
BugLink: http://lkml.kernel.org/r/CACT4Y+bay9qsrz6dQu31EcGaH9XwfW7o3oBzSQUG9fMszoh=Sg@mail.gmail.com
Fixes: 7f0973e973 ('ALSA: seq: Fix lockdep warnings due to 'double mutex locks)
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Tested-by: Dmitry Vyukov <dvyukov@google.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
0b8c82190c
commit
13d5e5d472
|
|
@ -535,19 +535,22 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
|
||||||
bool is_src, bool ack)
|
bool is_src, bool ack)
|
||||||
{
|
{
|
||||||
struct snd_seq_port_subs_info *grp;
|
struct snd_seq_port_subs_info *grp;
|
||||||
|
struct list_head *list;
|
||||||
|
bool empty;
|
||||||
|
|
||||||
grp = is_src ? &port->c_src : &port->c_dest;
|
grp = is_src ? &port->c_src : &port->c_dest;
|
||||||
|
list = is_src ? &subs->src_list : &subs->dest_list;
|
||||||
down_write(&grp->list_mutex);
|
down_write(&grp->list_mutex);
|
||||||
write_lock_irq(&grp->list_lock);
|
write_lock_irq(&grp->list_lock);
|
||||||
if (is_src)
|
empty = list_empty(list);
|
||||||
list_del(&subs->src_list);
|
if (!empty)
|
||||||
else
|
list_del_init(list);
|
||||||
list_del(&subs->dest_list);
|
|
||||||
grp->exclusive = 0;
|
grp->exclusive = 0;
|
||||||
write_unlock_irq(&grp->list_lock);
|
write_unlock_irq(&grp->list_lock);
|
||||||
up_write(&grp->list_mutex);
|
up_write(&grp->list_mutex);
|
||||||
|
|
||||||
unsubscribe_port(client, port, grp, &subs->info, ack);
|
if (!empty)
|
||||||
|
unsubscribe_port(client, port, grp, &subs->info, ack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* connect two ports */
|
/* connect two ports */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user