Received: by 2002:a05:6a10:c604:0:0:0:0 with SMTP id y4csp3844834pxt; Tue, 10 Aug 2021 12:42:33 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx8ve+Usl0vNcYBL/cug5WgXIxvV2f41yyR+sIWtIbBVmfy1423Sd7GA2JHCOOGgV28bCol X-Received: by 2002:a17:906:ecb3:: with SMTP id qh19mr119735ejb.413.1628624553024; Tue, 10 Aug 2021 12:42:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1628624553; cv=none; d=google.com; s=arc-20160816; b=BHlAN7bBKBm7mKFiM82gjsDCa9NDSWCKA5dlC7o/pHzDNvi1A4AtOzWx3KcyuKbc+Z I7YSej3K6Gb/V756xcUmLS2fG8kObtFlPRVvsGmnwIpXfR71o9bNWWpCMB4Gynxs3M3s kYf4ZiOEglgPPEH38Xo0HvtZBhuLmErXy99xdrkkKTA5ZTWTbS1LqWCGr8plQX1oobHv sLa4E5P7sv1JxPerFnMzAq/7OGfp4ayAGSib1bVlaI2U7TxkTqala62KrylK6gignX5R 2qoMRr3KTDN5N5yfg3Oi3VmgTB4eKz5fcr3nXnYTDSwbor/CjyNJxeH2I87FrqP9CCNl X9BA== 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=uKPUHviu66XbCPi4mwZ3dNrGGaSceTLkiVRPcUY6AHY=; b=jFgvfvPe1IPxtShyqSRegjVcnZswBmDiTbYObKZR1IEhB/84WonQk/vef2KJtd9E1Y VnTCwnuGMDmTYGeV7boEyvgW8QF7U1FI5UqFE8y68GPU4ElA1leonIuJ5Y7WfKghTOeL sbsQH96+YtmZ6BRGG/cajQVeCFjUqRF/NhdZbZ6cgeZwzblhRdvzgXdlzajUVJMcu4Od IsCTKW6WzxmCsWSAyohwkjgMKZd13qy9M33ALvB1yz+ba+eX7dVIk5hMREFw6gFh+xBf PZxWj3uLgHrO9umV2yMZmZcPSDGmq2o/f33ijh8p4j53rA+dZMoDdXUP4Kh1npRuDURD SV1A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=u+Tpf2Qk; 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 cx28si9118098edb.322.2021.08.10.12.42.05; Tue, 10 Aug 2021 12:42:33 -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=u+Tpf2Qk; 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 S236555AbhHJRyE (ORCPT + 99 others); Tue, 10 Aug 2021 13:54:04 -0400 Received: from mail.kernel.org ([198.145.29.99]:55284 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234040AbhHJRuP (ORCPT ); Tue, 10 Aug 2021 13:50:15 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 8E74A61266; Tue, 10 Aug 2021 17:42:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1628617349; bh=FfXHP7cUmnlDTXqLMrTXsprmJ00OVsWAgbgMHCiyXAQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=u+Tpf2QkvjulQrkLHf40MMLU6sdWG2WUiXIEm0soWFKOl2rqnthKvF0MwcyucaxEA muIFncHsEEQZSXnBvOU54m+BJfT3/1Po+8uAjue6eC482fR8kG3N0A6VpMrLKxf3MD +tIaxybwlWIZ6IUsPsNmgvxz1KMCv3iZSGWwXSlY= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Takashi Iwai , folkert Subject: [PATCH 5.13 002/175] ALSA: seq: Fix racy deletion of subscriber Date: Tue, 10 Aug 2021 19:28:30 +0200 Message-Id: <20210810173001.013554195@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210810173000.928681411@linuxfoundation.org> References: <20210810173000.928681411@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 @@ -514,10 +514,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; @@ -525,7 +526,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) @@ -535,6 +535,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); } @@ -590,27 +602,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; }