Received: by 2002:a05:6a10:8a4d:0:0:0:0 with SMTP id dn13csp959112pxb; Fri, 13 Aug 2021 10:04:28 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzbXwGKDGzlpgJTVA6urSZP6TkxY5TkMtfIc2SqW/H10fngZ0/W9B/7rutYhqxwwBQFFxNc X-Received: by 2002:a05:6602:2193:: with SMTP id b19mr2822746iob.84.1628874268705; Fri, 13 Aug 2021 10:04:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1628874268; cv=none; d=google.com; s=arc-20160816; b=R+C6P085IFoEHZW574gOMFLmQItAM9r7tADiPmhO8ySsNKY/doEBb8fQ4rs2fRwblv GbCBuhacN21tmt+gjncvydOtsRmr5skFv8/nC7yThpYSZVP3u9x8Bsn2Ek7b0Gwvvxxn aSNKsaPnVwybEXU0zuzyi1OIfl7zwIY5n3jne2SETC+oS6cLiR6JD9/62wGvaCMfHPiz yDULv3QPYV0MwN59enZQmCHkIMqKIHHQPU/3QxMXHRMAkpS/lxz4N87rD8CxaZrMyiZo cvfQ/yUXmtaMXMPWufHBe9gG59IwBrYk1otlcF0STvoo0Gv9BXKuIij8ScLmEe0H6l4R uSYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=anrPkz/PtEwe7EZWlWtSZ+QCCcHuUxR89iYMEDoKpJ8=; b=Pv4A5Ns126Mb8daBF+nCNwk2mqx4Nb6o8Aj4uY4h4ndaOOx0+xWCrai7v/dcLBrF+P 93GtULs95ASJzeNXnzWzJyvwVzxqLLfN4gUz5HtyrNLZfwV8A9l7heqMxuYvmgnKnNWR QRdsdwLAfHF7m3yFwZYkdAcJKHPXiOfcwrvZFu2P02M6YUXzmGh8hn8ktoHE+ePdQYo3 mpqZKALunNTGoKPD906+dAhY8CxA6Qd1hXbazmUGx3GgF5c47ztUklzKPwPhcrdJNHuY V3Pq1RLEAZuXNFJmsmbtE3p/B5Fwu/0w0sLpw7rs7vgQfzYl+O30FUphE+VH1cJYXmFr faug== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=bzn8LB4B; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id l3si1848173jaq.39.2021.08.13.10.04.17; Fri, 13 Aug 2021 10:04:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=bzn8LB4B; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241067AbhHMPMN (ORCPT + 99 others); Fri, 13 Aug 2021 11:12:13 -0400 Received: from mail.kernel.org ([198.145.29.99]:54986 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241890AbhHMPLT (ORCPT ); Fri, 13 Aug 2021 11:11:19 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id B37A461102; Fri, 13 Aug 2021 15:10:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1628867452; bh=EFJhGl4j17dSbDx5yR+3T/oEosXLQSue43tuVXBDXrU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bzn8LB4Bpwn9/P6UNPXogj5hLFxIk+F+TD3e7jL3/zaDBl7Cqspuud11IVvAlNnSf EhOSlcVe1VeKObY92musa9oXJfvr3d7B7cAfQDPKKqLTda2HwB06Zt4TL79sX6qXol /47nVuBsHAckOp7mOJ3dfxsW/VFtqsy8G16+dee0= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Takashi Iwai , folkert Subject: [PATCH 4.14 02/42] ALSA: seq: Fix racy deletion of subscriber Date: Fri, 13 Aug 2021 17:06:28 +0200 Message-Id: <20210813150525.180507847@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210813150525.098817398@linuxfoundation.org> References: <20210813150525.098817398@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Takashi Iwai commit 97367c97226aab8b298ada954ce12659ee3ad2a4 upstream. It turned out that the current implementation of the port subscription is racy. The subscription contains two linked lists, and we have to add to or delete from both lists. Since both connection and disconnection procedures perform the same order for those two lists (i.e. src list, then dest list), when a deletion happens during a connection procedure, the src list may be deleted before the dest list addition completes, and this may lead to a use-after-free or an Oops, even though the access to both lists are protected via mutex. The simple workaround for this race is to change the access order for the disconnection, namely, dest list, then src list. This assures that the connection has been established when disconnecting, and also the concurrent deletion can be avoided. Reported-and-tested-by: folkert Cc: Link: https://lore.kernel.org/r/20210801182754.GP890690@belle.intranet.vanheusden.com Link: https://lore.kernel.org/r/20210803114312.2536-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_ports.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -532,10 +532,11 @@ static int check_and_subscribe_port(stru return err; } -static void delete_and_unsubscribe_port(struct snd_seq_client *client, - struct snd_seq_client_port *port, - struct snd_seq_subscribers *subs, - bool is_src, bool ack) +/* called with grp->list_mutex held */ +static void __delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack) { struct snd_seq_port_subs_info *grp; struct list_head *list; @@ -543,7 +544,6 @@ static void delete_and_unsubscribe_port( grp = is_src ? &port->c_src : &port->c_dest; list = is_src ? &subs->src_list : &subs->dest_list; - down_write(&grp->list_mutex); write_lock_irq(&grp->list_lock); empty = list_empty(list); if (!empty) @@ -553,6 +553,18 @@ static void delete_and_unsubscribe_port( if (!empty) unsubscribe_port(client, port, grp, &subs->info, ack); +} + +static void delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack) +{ + struct snd_seq_port_subs_info *grp; + + grp = is_src ? &port->c_src : &port->c_dest; + down_write(&grp->list_mutex); + __delete_and_unsubscribe_port(client, port, subs, is_src, ack); up_write(&grp->list_mutex); } @@ -608,27 +620,30 @@ int snd_seq_port_disconnect(struct snd_s struct snd_seq_client_port *dest_port, struct snd_seq_port_subscribe *info) { - struct snd_seq_port_subs_info *src = &src_port->c_src; + struct snd_seq_port_subs_info *dest = &dest_port->c_dest; struct snd_seq_subscribers *subs; int err = -ENOENT; - down_write(&src->list_mutex); + /* always start from deleting the dest port for avoiding concurrent + * deletions + */ + down_write(&dest->list_mutex); /* look for the connection */ - list_for_each_entry(subs, &src->list_head, src_list) { + list_for_each_entry(subs, &dest->list_head, dest_list) { if (match_subs_info(info, &subs->info)) { - atomic_dec(&subs->ref_count); /* mark as not ready */ + __delete_and_unsubscribe_port(dest_client, dest_port, + subs, false, + connector->number != dest_client->number); err = 0; break; } } - up_write(&src->list_mutex); + up_write(&dest->list_mutex); if (err < 0) return err; delete_and_unsubscribe_port(src_client, src_port, subs, true, connector->number != src_client->number); - delete_and_unsubscribe_port(dest_client, dest_port, subs, false, - connector->number != dest_client->number); kfree(subs); return 0; }