Received: by 2002:a05:6358:a55:b0:ec:fcf4:3ecf with SMTP id 21csp3387585rwb; Mon, 16 Jan 2023 07:23:43 -0800 (PST) X-Google-Smtp-Source: AMrXdXsTv8ZtSH1/qfS65d5fOmEPBq+vKEz+UoM0gq/r9F8oJFahJE5QUE7nRTBmp/yL1Fs1UXV7 X-Received: by 2002:a05:6a20:2921:b0:b8:afd9:9844 with SMTP id t33-20020a056a20292100b000b8afd99844mr666051pzf.54.1673882622811; Mon, 16 Jan 2023 07:23:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1673882622; cv=none; d=google.com; s=arc-20160816; b=nvZYJ48raoX5GDu4A0QbvBIY97mQn+87IIrVx1yF4plfDCLd83DZcGj9+tAegzZPn1 sbJbqjGytMbZFvh8DlN3Cf/6gizXlnmorTPAiVcSlFUAXCzHc0Ac7GXNeTG/ZaxlRKrI p8iobYAvSrSK1ukw7drsH374Rj0EZGYZgD/7rgJ1jvcSYbq+t+uloxDh7WEzTJicByZ0 1tDv4ugfbJiBaBOeWAJ2qEVAb9EdUPTpFDlhvaJwR77zzcdT7cGNm2V4Sh776MCRpJJj EMtpnX44wY9qyo4WjRJM2Hhu8mysr2bjHNdmVcfm243WgEbcxml1+KEDasbege6P9FBH IV2g== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=t53ySpQ6DY69Kqss5eJMRFlo1WBpyJM6UlFexLFGo/4=; b=lOliIUCbhcf8yI/2rfNDKDKZpb1R9XsQHmCNEoesyPbv+geZgWG/F4P1hUKDliyvb0 FtOF/CgSGSl7MryakcVs+W0NonSm8pY0AHtl9oGy3D5Ru4Pntuk9/4GwIUqURNffMLnv PMiPVWFrSgHjnFH2NuUOfnJQoVKqADwEc7Wpk4Djqd7coGq+vTzs99W/Ev99CxERSb8O qHb18wkqAsksL2IyR70z8TzYIbdJkx74AI99QbmzwDKKmhoVwRKAwyn3VoYOz7wIYCUV vaRlS307IIDGAE0qvTwMSyILxWgvb8vfryc0ZhkMeusfbdbxx5n79xmu9Za1Q8nRjPPK Ei1g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=nh5QuIy+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id g2-20020a056a0023c200b005815532f745si31940228pfc.44.2023.01.16.07.23.36; Mon, 16 Jan 2023 07:23:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=nh5QuIy+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232419AbjAPOPh (ORCPT + 50 others); Mon, 16 Jan 2023 09:15:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38862 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232429AbjAPONc (ORCPT ); Mon, 16 Jan 2023 09:13:32 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E229B2385B; Mon, 16 Jan 2023 06:05:10 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id A737060FD7; Mon, 16 Jan 2023 14:05:10 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 61736C433AE; Mon, 16 Jan 2023 14:05:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1673877910; bh=c2m5x0jaEMRpel0F1pPEctB1T2lKgMQs6HSAEprYGbk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nh5QuIy+pD8Wh4LSYH+zstFDZDd6okNkWFrKBnRjaBmcK6sf31fCqUqE2Qg4FE0YR uBfp/xAtLpv0XX6RjD1EMvUwgUxFmBSZseXz1OdNOWRA63DDiRRulFyXHYtb7lb8kv 5jGLQrmh/24zVjPi8F1Eua6/IM7WcAZ673Yv3uWjMl7561zDXD3AQryu92gY0Hc4gZ mwzDSqeUptKSJ1jjh6sAZlf36qkcssB2q3MnlmM0yA8Tu5UeHkpsIzmEAHNug7IAh/ gexpnd7MsUMO3WY98qwNcUBDvfbOZ50aFPxFfIUbX5S6SPFhLKmqH3Ne7evSLKN57L AwCGEQQnMZrFw== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Bartosz Golaszewski , Mark Brown , Sasha Levin , linux-spi@vger.kernel.org Subject: [PATCH AUTOSEL 5.10 11/17] spi: spidev: fix a race condition when accessing spidev->spi Date: Mon, 16 Jan 2023 09:04:42 -0500 Message-Id: <20230116140448.116034-11-sashal@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20230116140448.116034-1-sashal@kernel.org> References: <20230116140448.116034-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Bartosz Golaszewski [ Upstream commit a720416d94634068951773cb9e9d6f1b73769e5b ] There's a spinlock in place that is taken in file_operations callbacks whenever we check if spidev->spi is still alive (not null). It's also taken when spidev->spi is set to NULL in remove(). This however doesn't protect the code against driver unbind event while one of the syscalls is still in progress. To that end we need a lock taken continuously as long as we may still access spidev->spi. As both the file ops and the remove callback are never called from interrupt context, we can replace the spinlock with a mutex. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230106100719.196243-1-brgl@bgdev.pl Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spidev.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 9c5ec99431d2..87c4d641cbd5 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -67,7 +67,7 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS); struct spidev_data { dev_t devt; - spinlock_t spi_lock; + struct mutex spi_lock; struct spi_device *spi; struct list_head device_entry; @@ -94,9 +94,8 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message) int status; struct spi_device *spi; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spidev->spi; - spin_unlock_irq(&spidev->spi_lock); if (spi == NULL) status = -ESHUTDOWN; @@ -106,6 +105,7 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message) if (status == 0) status = message->actual_length; + mutex_unlock(&spidev->spi_lock); return status; } @@ -358,12 +358,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * we issue this ioctl. */ spidev = filp->private_data; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spi_dev_get(spidev->spi); - spin_unlock_irq(&spidev->spi_lock); - - if (spi == NULL) + if (spi == NULL) { + mutex_unlock(&spidev->spi_lock); return -ESHUTDOWN; + } /* use the buffer lock here for triple duty: * - prevent I/O (from us) so calling spi_setup() is safe; @@ -500,6 +500,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) mutex_unlock(&spidev->buf_lock); spi_dev_put(spi); + mutex_unlock(&spidev->spi_lock); return retval; } @@ -521,12 +522,12 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, * we issue this ioctl. */ spidev = filp->private_data; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spi_dev_get(spidev->spi); - spin_unlock_irq(&spidev->spi_lock); - - if (spi == NULL) + if (spi == NULL) { + mutex_unlock(&spidev->spi_lock); return -ESHUTDOWN; + } /* SPI_IOC_MESSAGE needs the buffer locked "normally" */ mutex_lock(&spidev->buf_lock); @@ -553,6 +554,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, done: mutex_unlock(&spidev->buf_lock); spi_dev_put(spi); + mutex_unlock(&spidev->spi_lock); return retval; } @@ -631,10 +633,10 @@ static int spidev_release(struct inode *inode, struct file *filp) spidev = filp->private_data; filp->private_data = NULL; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); /* ... after we unbound from the underlying device? */ dofree = (spidev->spi == NULL); - spin_unlock_irq(&spidev->spi_lock); + mutex_unlock(&spidev->spi_lock); /* last close? */ spidev->users--; @@ -761,7 +763,7 @@ static int spidev_probe(struct spi_device *spi) /* Initialize the driver data */ spidev->spi = spi; - spin_lock_init(&spidev->spi_lock); + mutex_init(&spidev->spi_lock); mutex_init(&spidev->buf_lock); INIT_LIST_HEAD(&spidev->device_entry); @@ -806,9 +808,9 @@ static int spidev_remove(struct spi_device *spi) /* prevent new opens */ mutex_lock(&device_list_lock); /* make sure ops on existing fds can abort cleanly */ - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spidev->spi = NULL; - spin_unlock_irq(&spidev->spi_lock); + mutex_unlock(&spidev->spi_lock); list_del(&spidev->device_entry); device_destroy(spidev_class, spidev->devt); -- 2.35.1