From patchwork Mon Aug 23 17:14:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Desmond Cheong Zhi Xi X-Patchwork-Id: 12453285 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DE8A5C432BE for ; Mon, 23 Aug 2021 17:15:20 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AAEA761206 for ; Mon, 23 Aug 2021 17:15:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org AAEA761206 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 26DC389F92; Mon, 23 Aug 2021 17:15:18 +0000 (UTC) Received: from mail-pg1-x52f.google.com (mail-pg1-x52f.google.com [IPv6:2607:f8b0:4864:20::52f]) by gabe.freedesktop.org (Postfix) with ESMTPS id EB72389F77; Mon, 23 Aug 2021 17:15:16 +0000 (UTC) Received: by mail-pg1-x52f.google.com with SMTP id e7so17249920pgk.2; Mon, 23 Aug 2021 10:15:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Hm7YjUyiFZ/KTSC9DbXmgQsGRHrND7m8Eh1agHCitnc=; b=Hu/UENdhdrmnyEohbXjETfe98nCnQf8T8kz+WnnhfYxirR40EcXoYicthiSNlyfrcb 1lHg9PI3AXl9NLdgjZ4EU8M4i912WQf3ymjcc7aXDI0XLN1xmGz3rA6QVpw9gs5l2OpW 86Y2Eedl3Q4JoMLcWHVKVgUIqzoizNTypNNak8pnpJrX4u5u/tg8fqh5/44/CYdTkLOA XSlamsA1X2jhY7mwMKM3nc21+0+ezmpLz0kILFICQ0ZQDaAXuEVCYgYkKPDlffhPTZWp BplkzcNDyd3p2Ln14BcgB/bX9pWtjtvpdL6stk05ncLvT8bR9N+WrzlyFE0GiiqN+DKJ zVug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Hm7YjUyiFZ/KTSC9DbXmgQsGRHrND7m8Eh1agHCitnc=; b=iJh+Fp+BW4/CM1beVkteJbkJHjHH+JOl60qWL+qMtMdAb9+oP+HGn1zYElF3mM1knF uE+LoAJvtesrGYhFPZ6z3oka92KzR+z5mjtnBmSFlAfZyKB4v3uLyOuX7oXaHoxiR6iX 2vGq92JihmbgkHIuwGn6tOYbnKyOSACEMVQzdHPkpM7gKK7J4lh0pLyQEWaVXHDjaVQT kCl/cZms8aVZPkpuK+209/JEIAIFhLdYmHHNIv/KwDIo/awindMVUm04f/Cm/J1Gy1tZ GOcyEiGXrDj98LHeJSruQ+uyVYVJV59TW/7uOBVbw1u01vBNsB1gazyjbv0A06fLvsNk EuwA== X-Gm-Message-State: AOAM53198Np1a+57NWQgnlmExuhW7q75oG75mJXBIOCeHPD1E0BiBZBY AUjrdO6RlEEb4vAYJ5gvMvQ= X-Google-Smtp-Source: ABdhPJxBpFsyIM9dqaqeLqzsQR5HT/rpYYPihnEULHz191fxer+tshG8eCUcMaE58dbnOQ/FiYxw9w== X-Received: by 2002:a65:5a8e:: with SMTP id c14mr32646227pgt.125.1629738916506; Mon, 23 Aug 2021 10:15:16 -0700 (PDT) Received: from localhost.localdomain ([118.200.190.93]) by smtp.gmail.com with ESMTPSA id q4sm14290830pjd.52.2021.08.23.10.15.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 10:15:16 -0700 (PDT) From: Desmond Cheong Zhi Xi To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, daniel@ffwll.ch, sumit.semwal@linaro.org, christian.koenig@amd.com Cc: Desmond Cheong Zhi Xi , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org Date: Tue, 24 Aug 2021 01:14:32 +0800 Message-Id: <20210823171437.829404-2-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210823171437.829404-1-desmondcheongzx@gmail.com> References: <20210823171437.829404-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v5 1/6] drm: fix null ptr dereference in drm_master_release X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" drm_master_release can be called on a drm_file without a master, which results in a null ptr dereference of file_priv->master->magic_map. The three cases are: 1. Error path in drm_open_helper drm_open(): drm_open_helper(): drm_master_open(): drm_new_set_master(); <--- returns -ENOMEM, drm_file.master not set drm_file_free(): drm_master_release(); <--- NULL ptr dereference (file_priv->master->magic_map) 2. Error path in mock_drm_getfile mock_drm_getfile(): anon_inode_getfile(); <--- returns error, drm_file.master not set drm_file_free(): drm_master_release(); <--- NULL ptr dereference (file_priv->master->magic_map) 3. In drm_client_close, as drm_client_open doesn't set up a master drm_file.master is set up in drm_open_helper through the call to drm_master_open, so we mirror it with a call to drm_master_release in drm_close_helper, and remove drm_master_release from drm_file_free to avoid the null ptr dereference. Signed-off-by: Desmond Cheong Zhi Xi --- drivers/gpu/drm/drm_file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index ed25168619fc..90b62f360da1 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -282,9 +282,6 @@ void drm_file_free(struct drm_file *file) drm_legacy_ctxbitmap_flush(dev, file); - if (drm_is_primary_client(file)) - drm_master_release(file); - if (dev->driver->postclose) dev->driver->postclose(dev, file); @@ -305,6 +302,9 @@ static void drm_close_helper(struct file *filp) list_del(&file_priv->lhead); mutex_unlock(&dev->filelist_mutex); + if (drm_is_primary_client(file_priv)) + drm_master_release(file_priv); + drm_file_free(file_priv); } From patchwork Mon Aug 23 17:14:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Desmond Cheong Zhi Xi X-Patchwork-Id: 12453287 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC44AC4338F for ; Mon, 23 Aug 2021 17:15:25 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A1BC361206 for ; Mon, 23 Aug 2021 17:15:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org A1BC361206 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0DBF889FBC; Mon, 23 Aug 2021 17:15:25 +0000 (UTC) Received: from mail-pl1-x62f.google.com (mail-pl1-x62f.google.com [IPv6:2607:f8b0:4864:20::62f]) by gabe.freedesktop.org (Postfix) with ESMTPS id 750B889FBC; Mon, 23 Aug 2021 17:15:24 +0000 (UTC) Received: by mail-pl1-x62f.google.com with SMTP id m17so3502931plc.6; Mon, 23 Aug 2021 10:15:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bkFQht7vR3ZjKExLOYXZei3qepyeU4QeAm6JOJ26wAc=; b=oLW9dd1H98Y2NVGVTMwDQ4etDQAadZJhrnNplKdcAgOs6LERr+/LE4HDYk5Dp+gv/C UMp5EUDgniSgz+zNGkYd5mbPjYoUN+qoO2LAwx3P2rnLcc0rbpIXscj3mSbnGdlx9XFJ 7SHkbcOUTA3QrsIbrHn5TCaG7C+XT2E/BQ8Tpua+2o7e2nzqvHLNA960ZgY5YBCEAj+R SsKRlpf0S8EOJz8NZoS2J3xuoztNQwjfGSFO6nVx1+rLRP0J3QR2fFj+B8jdj12CejKP T4rl902fGADq9BdWI105XADSyIKGit3ppX9/e5yZtvpD2qSHt457+Vly4/RM5gXIabw6 8o4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bkFQht7vR3ZjKExLOYXZei3qepyeU4QeAm6JOJ26wAc=; b=I2tLV5a09SNfkcCSIq+bNABa7YvJs0Wr6X5k9Zu7Rba6CMm0Zjpc6Q5u+hLCXU/EQ1 qQ1iOKuIhWyJqVjW29arPFlQ1+E9k+EL4YS4thDUr56uIOyTjERW4qh9q9THt/w/lSq8 CyeLRTDtH0Uqe+KHY3ZCpcCfZIFZFXtqfR/VG05XQWLFSoCv1zJmzlaZdPTJE4rATOMd mXyjGk06/SY9CVzzpwCvooNuRuFEpbBwvNHSqAX9oFMgBDIoaP9wO4idrrBchOoLMwAY AcHkG1nxpNF8CQ6I4jg4s8bUR+Tmcx/11V3Q3lYJgwCzmQCd91iIwE8JZB0vMuyzrJvH A/JA== X-Gm-Message-State: AOAM531m5WGnT8GRBQ5+uGWYiR9UXnM0mwv0wp10R+XE7AcyxWVdsbi4 SzKlvI5NgLSiDUfb5nTEff8= X-Google-Smtp-Source: ABdhPJyjAOPhvXCTyRvIcUm/ZJLoeXWSrhTXJM6aD9iyfhWr61DmcL4Q1JV5V3OLEg85MOHq7AGjrg== X-Received: by 2002:a17:90a:f2d2:: with SMTP id gt18mr19469461pjb.187.1629738924090; Mon, 23 Aug 2021 10:15:24 -0700 (PDT) Received: from localhost.localdomain ([118.200.190.93]) by smtp.gmail.com with ESMTPSA id q4sm14290830pjd.52.2021.08.23.10.15.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 10:15:23 -0700 (PDT) From: Desmond Cheong Zhi Xi To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, daniel@ffwll.ch, sumit.semwal@linaro.org, christian.koenig@amd.com Cc: Desmond Cheong Zhi Xi , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org Date: Tue, 24 Aug 2021 01:14:33 +0800 Message-Id: <20210823171437.829404-3-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210823171437.829404-1-desmondcheongzx@gmail.com> References: <20210823171437.829404-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v5 2/6] drm: convert drm_device.master_mutex into a rwsem X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" drm_device.master_mutex currently protects the following: - drm_device.master - drm_file.master - drm_file.was_master - drm_file.is_master - drm_master.unique - drm_master.unique_len - drm_master.magic_map There is a clear separation between functions that read or change these attributes. Hence, convert master_mutex into a rwsem to enable concurrent readers. Signed-off-by: Desmond Cheong Zhi Xi --- drivers/gpu/drm/drm_auth.c | 35 ++++++++++++++++++----------------- drivers/gpu/drm/drm_debugfs.c | 4 ++-- drivers/gpu/drm/drm_drv.c | 3 +-- drivers/gpu/drm/drm_ioctl.c | 10 +++++----- include/drm/drm_auth.h | 6 +++--- include/drm/drm_device.h | 10 ++++++---- include/drm/drm_file.h | 12 ++++++------ 7 files changed, 41 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 60a6b21474b1..73ade0513ccb 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -64,7 +64,7 @@ static bool drm_is_current_master_locked(struct drm_file *fpriv) { lockdep_assert_once(lockdep_is_held(&fpriv->master_lookup_lock) || - lockdep_is_held(&fpriv->minor->dev->master_mutex)); + lockdep_is_held(&fpriv->minor->dev->master_rwsem)); return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master; } @@ -96,7 +96,7 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) struct drm_auth *auth = data; int ret = 0; - mutex_lock(&dev->master_mutex); + down_write(&dev->master_rwsem); if (!file_priv->magic) { ret = idr_alloc(&file_priv->master->magic_map, file_priv, 1, 0, GFP_KERNEL); @@ -104,7 +104,7 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) file_priv->magic = ret; } auth->magic = file_priv->magic; - mutex_unlock(&dev->master_mutex); + up_write(&dev->master_rwsem); DRM_DEBUG("%u\n", auth->magic); @@ -119,13 +119,13 @@ int drm_authmagic(struct drm_device *dev, void *data, DRM_DEBUG("%u\n", auth->magic); - mutex_lock(&dev->master_mutex); + down_write(&dev->master_rwsem); file = idr_find(&file_priv->master->magic_map, auth->magic); if (file) { file->authenticated = 1; idr_replace(&file_priv->master->magic_map, NULL, auth->magic); } - mutex_unlock(&dev->master_mutex); + up_write(&dev->master_rwsem); return file ? 0 : -EINVAL; } @@ -167,7 +167,7 @@ static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) struct drm_master *old_master; struct drm_master *new_master; - lockdep_assert_held_once(&dev->master_mutex); + lockdep_assert_held_once(&dev->master_rwsem); WARN_ON(fpriv->is_master); old_master = fpriv->master; @@ -249,7 +249,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, { int ret; - mutex_lock(&dev->master_mutex); + down_write(&dev->master_rwsem); ret = drm_master_check_perm(dev, file_priv); if (ret) @@ -281,7 +281,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, drm_set_master(dev, file_priv, false); out_unlock: - mutex_unlock(&dev->master_mutex); + up_write(&dev->master_rwsem); return ret; } @@ -298,7 +298,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, { int ret; - mutex_lock(&dev->master_mutex); + down_write(&dev->master_rwsem); ret = drm_master_check_perm(dev, file_priv); if (ret) @@ -321,8 +321,9 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, } drm_drop_master(dev, file_priv); + out_unlock: - mutex_unlock(&dev->master_mutex); + up_write(&dev->master_rwsem); return ret; } @@ -334,7 +335,7 @@ int drm_master_open(struct drm_file *file_priv) /* if there is no current master make this fd it, but do not create * any master object for render clients */ - mutex_lock(&dev->master_mutex); + down_write(&dev->master_rwsem); if (!dev->master) { ret = drm_new_set_master(dev, file_priv); } else { @@ -342,7 +343,7 @@ int drm_master_open(struct drm_file *file_priv) file_priv->master = drm_master_get(dev->master); spin_unlock(&file_priv->master_lookup_lock); } - mutex_unlock(&dev->master_mutex); + up_write(&dev->master_rwsem); return ret; } @@ -352,7 +353,7 @@ void drm_master_release(struct drm_file *file_priv) struct drm_device *dev = file_priv->minor->dev; struct drm_master *master; - mutex_lock(&dev->master_mutex); + down_write(&dev->master_rwsem); master = file_priv->master; if (file_priv->magic) idr_remove(&file_priv->master->magic_map, file_priv->magic); @@ -375,7 +376,7 @@ void drm_master_release(struct drm_file *file_priv) /* drop the master reference held by the file priv */ if (file_priv->master) drm_master_put(&file_priv->master); - mutex_unlock(&dev->master_mutex); + up_write(&dev->master_rwsem); } /** @@ -450,9 +451,9 @@ EXPORT_SYMBOL(drm_master_put); /* Used by drm_client and drm_fb_helper */ bool drm_master_internal_acquire(struct drm_device *dev) { - mutex_lock(&dev->master_mutex); + down_read(&dev->master_rwsem); if (dev->master) { - mutex_unlock(&dev->master_mutex); + up_read(&dev->master_rwsem); return false; } @@ -463,6 +464,6 @@ EXPORT_SYMBOL(drm_master_internal_acquire); /* Used by drm_client and drm_fb_helper */ void drm_master_internal_release(struct drm_device *dev) { - mutex_unlock(&dev->master_mutex); + up_read(&dev->master_rwsem); } EXPORT_SYMBOL(drm_master_internal_release); diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index b0a826489488..b34c9c263188 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -55,7 +55,7 @@ static int drm_name_info(struct seq_file *m, void *data) struct drm_device *dev = minor->dev; struct drm_master *master; - mutex_lock(&dev->master_mutex); + down_read(&dev->master_rwsem); master = dev->master; seq_printf(m, "%s", dev->driver->name); if (dev->dev) @@ -65,7 +65,7 @@ static int drm_name_info(struct seq_file *m, void *data) if (dev->unique) seq_printf(m, " unique=%s", dev->unique); seq_printf(m, "\n"); - mutex_unlock(&dev->master_mutex); + up_read(&dev->master_rwsem); return 0; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 7a5097467ba5..4556bf42954c 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -570,7 +570,6 @@ static void drm_dev_init_release(struct drm_device *dev, void *res) /* Prevent use-after-free in drm_managed_release when debugging is * enabled. Slightly awkward, but can't really be helped. */ dev->dev = NULL; - mutex_destroy(&dev->master_mutex); mutex_destroy(&dev->clientlist_mutex); mutex_destroy(&dev->filelist_mutex); mutex_destroy(&dev->struct_mutex); @@ -611,7 +610,7 @@ static int drm_dev_init(struct drm_device *dev, mutex_init(&dev->struct_mutex); mutex_init(&dev->filelist_mutex); mutex_init(&dev->clientlist_mutex); - mutex_init(&dev->master_mutex); + init_rwsem(&dev->master_rwsem); ret = drmm_add_action(dev, drm_dev_init_release, NULL); if (ret) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 26f3a9ede8fe..d25713b09b80 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -119,16 +119,16 @@ int drm_getunique(struct drm_device *dev, void *data, struct drm_unique *u = data; struct drm_master *master; - mutex_lock(&dev->master_mutex); + down_read(&dev->master_rwsem); master = file_priv->master; if (u->unique_len >= master->unique_len) { if (copy_to_user(u->unique, master->unique, master->unique_len)) { - mutex_unlock(&dev->master_mutex); + up_read(&dev->master_rwsem); return -EFAULT; } } u->unique_len = master->unique_len; - mutex_unlock(&dev->master_mutex); + up_read(&dev->master_rwsem); return 0; } @@ -385,7 +385,7 @@ static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *f struct drm_set_version *sv = data; int if_version, retcode = 0; - mutex_lock(&dev->master_mutex); + down_write(&dev->master_rwsem); if (sv->drm_di_major != -1) { if (sv->drm_di_major != DRM_IF_MAJOR || sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { @@ -420,7 +420,7 @@ static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *f sv->drm_di_minor = DRM_IF_MINOR; sv->drm_dd_major = dev->driver->major; sv->drm_dd_minor = dev->driver->minor; - mutex_unlock(&dev->master_mutex); + up_write(&dev->master_rwsem); return retcode; } diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h index ba248ca8866f..f0a89e5fcaad 100644 --- a/include/drm/drm_auth.h +++ b/include/drm/drm_auth.h @@ -67,17 +67,17 @@ struct drm_master { struct drm_device *dev; /** * @unique: Unique identifier: e.g. busid. Protected by - * &drm_device.master_mutex. + * &drm_device.master_rwsem. */ char *unique; /** * @unique_len: Length of unique field. Protected by - * &drm_device.master_mutex. + * &drm_device.master_rwsem. */ int unique_len; /** * @magic_map: Map of used authentication tokens. Protected by - * &drm_device.master_mutex. + * &drm_device.master_rwsem. */ struct idr magic_map; void *driver_priv; diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index 604b1d1b2d72..142fb2f6e74d 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -107,7 +107,7 @@ struct drm_device { * @master: * * Currently active master for this device. - * Protected by &master_mutex + * Protected by &master_rwsem */ struct drm_master *master; @@ -146,11 +146,13 @@ struct drm_device { struct mutex struct_mutex; /** - * @master_mutex: + * @master_rwsem: * - * Lock for &drm_minor.master and &drm_file.is_master + * Lock for &drm_device.master, &drm_file.was_master, + * &drm_file.is_master, &drm_file.master, &drm_master.unique, + * &drm_master.unique_len, and &drm_master.magic_map. */ - struct mutex master_mutex; + struct rw_semaphore master_rwsem; /** * @open_count: diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index a3acb7ac3550..d12bb2ba7814 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -205,7 +205,7 @@ struct drm_file { * @was_master: * * This client has or had, master capability. Protected by struct - * &drm_device.master_mutex. + * &drm_device.master_rwsem. * * This is used to ensure that CAP_SYS_ADMIN is not enforced, if the * client is or was master in the past. @@ -216,7 +216,7 @@ struct drm_file { * @is_master: * * This client is the creator of @master. Protected by struct - * &drm_device.master_mutex. + * &drm_device.master_rwsem. * * See also the :ref:`section on primary nodes and authentication * `. @@ -227,19 +227,19 @@ struct drm_file { * @master: * * Master this node is currently associated with. Protected by struct - * &drm_device.master_mutex, and serialized by @master_lookup_lock. + * &drm_device.master_rwsem, and serialized by @master_lookup_lock. * * Only relevant if drm_is_primary_client() returns true. Note that * this only matches &drm_device.master if the master is the currently * active one. * - * To update @master, both &drm_device.master_mutex and + * To update @master, both &drm_device.master_rwsem and * @master_lookup_lock need to be held, therefore holding either of * them is safe and enough for the read side. * * When dereferencing this pointer, either hold struct - * &drm_device.master_mutex for the duration of the pointer's use, or - * use drm_file_get_master() if struct &drm_device.master_mutex is not + * &drm_device.master_rwsem for the duration of the pointer's use, or + * use drm_file_get_master() if struct &drm_device.master_rwsem is not * currently held and there is no other need to hold it. This prevents * @master from being freed during use. * From patchwork Mon Aug 23 17:14:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Desmond Cheong Zhi Xi X-Patchwork-Id: 12453289 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85103C4320A for ; Mon, 23 Aug 2021 17:15:31 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 51C50613BD for ; Mon, 23 Aug 2021 17:15:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 51C50613BD Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id BE5ED6E069; Mon, 23 Aug 2021 17:15:30 +0000 (UTC) Received: from mail-pf1-x429.google.com (mail-pf1-x429.google.com [IPv6:2607:f8b0:4864:20::429]) by gabe.freedesktop.org (Postfix) with ESMTPS id C812A6E069; Mon, 23 Aug 2021 17:15:29 +0000 (UTC) Received: by mail-pf1-x429.google.com with SMTP id 18so15950023pfh.9; Mon, 23 Aug 2021 10:15:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=P/HLeCdm1ln+WDWlHx3gbH2c2TGPxEmJ7R7sNcfLOXw=; b=c0f4kiiXc4IkYgZ7SwV50fvg9X1ZxF8YmeWTnH1aY4zr7f7CxUhhKSV/ZxhYEciPsx R4qVFbmzrhrtFLWu5p5Y0++tTcd6CaIj04UjTLFpXvsk9ker44OElUT1FAhJ1Rt0VW+L kJjfeN5Gn7i6bWpucmWiFYyQ16P3Jy332p1OBTQKhgyhWGok75i5BFP08s/R0+IH7OWo NtrYk744ZrR0r4l/25XjPCpwbOubap2eD0VpfKj1KT4MhXwPEorZId01Rru6W+3wAJk1 h5BxeL35p/7pwLyuFfPvEvQyytrwmRi+vPiLjPoshVtby2FB5ccCGeT+9IpVO3fPjaEI IBsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=P/HLeCdm1ln+WDWlHx3gbH2c2TGPxEmJ7R7sNcfLOXw=; b=jc0fIsYTvcH5jAKBGOHfecn9pt/ac0CV4EtyIRm6XpxTJl65t8YbpL4ZODIhdUj0sv Odm5QlfNfE+ZnaJlqfhhanAEt/GL6duZO/CrbpcK7HxnGnXuy4ftyGsuZT8vCJ/eb3WV b0EvJD4JL/zen+aNAEsdDjeqtipQXT/guBWdLGFvglYpQXIQS2QiUM7ZjHZ12f22q1sD /oLqZPV7+ukgjGB1MIEEk44/ClQb9FbDbRA8huqvAM0pU5rNGqaoKshyyPzshAFKnwSK 7jBhE2AsoU10aTdP2xqV1z+TS9YQWGcC7yexJ5gRvZapD8JJDaUyIrFvlffTDROnFyZD rBtw== X-Gm-Message-State: AOAM531WYesggzYwg3OxmacLIndG+DnF9G3O9AAWPdvKfAi0O8m+VZvz BNr6hk8RMbzUtmGFR949cRM= X-Google-Smtp-Source: ABdhPJxHInaVZCTCItEa4Eu561qYx8GvC70vOUyW+CghTAjRug2jVLVxRcc+W6Xrpc1RMGrYbv9O9A== X-Received: by 2002:aa7:94ac:0:b0:3e0:f21a:e6ff with SMTP id a12-20020aa794ac000000b003e0f21ae6ffmr33941216pfl.76.1629738929457; Mon, 23 Aug 2021 10:15:29 -0700 (PDT) Received: from localhost.localdomain ([118.200.190.93]) by smtp.gmail.com with ESMTPSA id q4sm14290830pjd.52.2021.08.23.10.15.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 10:15:29 -0700 (PDT) From: Desmond Cheong Zhi Xi To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, daniel@ffwll.ch, sumit.semwal@linaro.org, christian.koenig@amd.com Cc: Desmond Cheong Zhi Xi , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org Date: Tue, 24 Aug 2021 01:14:34 +0800 Message-Id: <20210823171437.829404-4-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210823171437.829404-1-desmondcheongzx@gmail.com> References: <20210823171437.829404-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v5 3/6] drm: lock drm_global_mutex earlier in the ioctl handler X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" In a future patch, a read lock on drm_device.master_rwsem is held in the ioctl handler before the check for ioctl permissions. However, this inverts the lock hierarchy of drm_global_mutex --> master_rwsem. To avoid this, we do some prep work to grab the drm_global_mutex before checking for ioctl permissions. Signed-off-by: Desmond Cheong Zhi Xi --- drivers/gpu/drm/drm_ioctl.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index d25713b09b80..158629d88319 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -772,19 +772,19 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, if (drm_dev_is_unplugged(dev)) return -ENODEV; + /* Enforce sane locking for modern driver ioctls. */ + if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY)) && !(flags & DRM_UNLOCKED)) + mutex_lock(&drm_global_mutex); + retcode = drm_ioctl_permit(flags, file_priv); if (unlikely(retcode)) - return retcode; + goto out; - /* Enforce sane locking for modern driver ioctls. */ - if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) || - (flags & DRM_UNLOCKED)) - retcode = func(dev, kdata, file_priv); - else { - mutex_lock(&drm_global_mutex); - retcode = func(dev, kdata, file_priv); + retcode = func(dev, kdata, file_priv); + +out: + if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY)) && !(flags & DRM_UNLOCKED)) mutex_unlock(&drm_global_mutex); - } return retcode; } EXPORT_SYMBOL(drm_ioctl_kernel); From patchwork Mon Aug 23 17:14:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Desmond Cheong Zhi Xi X-Patchwork-Id: 12453291 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 01152C432BE for ; Mon, 23 Aug 2021 17:15:39 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C641461206 for ; Mon, 23 Aug 2021 17:15:38 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org C641461206 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D2BC46E094; Mon, 23 Aug 2021 17:15:37 +0000 (UTC) Received: from mail-pj1-x1035.google.com (mail-pj1-x1035.google.com [IPv6:2607:f8b0:4864:20::1035]) by gabe.freedesktop.org (Postfix) with ESMTPS id 03F956E083; Mon, 23 Aug 2021 17:15:36 +0000 (UTC) Received: by mail-pj1-x1035.google.com with SMTP id j4-20020a17090a734400b0018f6dd1ec97so426815pjs.3; Mon, 23 Aug 2021 10:15:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=rtuBBmsJ+FZGp2Lavog/mblfNKKX32jG6r2O7uMrLj0=; b=e7uGGTmhO+HW1Nizy73RZhNXpoJcMOyUBRatHDEtcSEbl4wH5flpNGeotwgb4sFZ1d uLh0hZ5tWOj48C1zoLlCLjUBSGCxC0fS7N91OOvc4fa1fkOEqECuXy5ZAnOWmIq6Yqj9 TwxQsOiN9kxnU0IEKnl1qG9/dvDdoGonR3D8o4jyPv6SG66Bfe3OviRM3A70aDuwtiqp KEO5ddg5hkcLV0iDjLO7Y+hAU2UhgzsVSTI8WMd1Vka5+HuS61n7TojMfImVSpwkVJtP k8KXyWyaVcLlsT+B7mNKDUfoyOxOadvUD1DDrvpMrMMLvQfbk/XB+AOU+BB0C5G8FAEs ZerQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rtuBBmsJ+FZGp2Lavog/mblfNKKX32jG6r2O7uMrLj0=; b=iYVKt2VRwauKdKhlgD3opM+BaAclYcDHXCitIo54v45GTugiutOcCfmGHFoKAQiie6 QtlkwZZiTnr8ghzcEHanUPlJJ8UJmYN0R0oEumzt9MpawQZNKeqPKy7zmvrIv8ntBWmE wdQH47lN/rSzD75eDKWrLKxbvZe6toh7Iml4OrY5IhLgeusdXFZyRHjGZqUOeP9srYKm Z6Bd6cAaIIJesyLGpKgJqoeus6X+cZnjdzf7qKAZ7U9js6eG3ew3o8Y3ucO+FPwYAZeP c7g8KcMzumIlrkvCqqP/px3C24huPi7U9Ey55n+zTNw4hhU2VEJaObsrBYLOX8xdiOwa 5NgA== X-Gm-Message-State: AOAM530oRnz4MzBbwcegiLHwfZtFFApqncN2TXT4HI09M8VM2CXQ3m9G C8BSAPPhUbT76pXEv4uQwRc= X-Google-Smtp-Source: ABdhPJx+F+vy3/OxAlCs6LGIrtGmdduva4wi4tRr9T6hBpSbW9CIXvc7HHH7d9jGUoAUUdQgrWfViQ== X-Received: by 2002:a17:903:31cd:b0:134:5b6f:2ff8 with SMTP id v13-20020a17090331cd00b001345b6f2ff8mr5521620ple.46.1629738935621; Mon, 23 Aug 2021 10:15:35 -0700 (PDT) Received: from localhost.localdomain ([118.200.190.93]) by smtp.gmail.com with ESMTPSA id q4sm14290830pjd.52.2021.08.23.10.15.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 10:15:35 -0700 (PDT) From: Desmond Cheong Zhi Xi To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, daniel@ffwll.ch, sumit.semwal@linaro.org, christian.koenig@amd.com Cc: Desmond Cheong Zhi Xi , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, Daniel Vetter Date: Tue, 24 Aug 2021 01:14:35 +0800 Message-Id: <20210823171437.829404-5-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210823171437.829404-1-desmondcheongzx@gmail.com> References: <20210823171437.829404-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v5 4/6] drm: avoid races with modesetting rights X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" In drm_client_modeset.c and drm_fb_helper.c, drm_master_internal_{acquire,release} are used to avoid races with DRM userspace. These functions hold onto drm_device.master_rwsem while committing, and bail if there's already a master. However, there are other places where modesetting rights can race. A time-of-check-to-time-of-use error can occur if an ioctl that changes the modeset has its rights revoked after it validates its permissions, but before it completes. There are four places where modesetting permissions can change: - DROP_MASTER ioctl removes rights for a master and its leases - REVOKE_LEASE ioctl revokes rights for a specific lease - SET_MASTER ioctl sets the device master if the master role hasn't been acquired yet - drm_open which can create a new master for a device if one does not currently exist These races can be avoided using drm_device.master_rwsem: users that perform modesetting should hold a read lock on the new drm_device.master_rwsem, and users that change these permissions should hold a write lock. To avoid deadlocks with master_rwsem, for ioctls that need to check for modesetting permissions, but also need to hold a write lock on master_rwsem to protect some other attribute (or recurses to some function that holds a write lock, like drm_mode_create_lease_ioctl which eventually calls drm_master_open), we remove the DRM_MASTER flag and push the master_rwsem lock and permissions check into the ioctl. Reported-by: Daniel Vetter Signed-off-by: Desmond Cheong Zhi Xi --- drivers/gpu/drm/drm_auth.c | 4 ++++ drivers/gpu/drm/drm_ioctl.c | 20 +++++++++++++++----- drivers/gpu/drm/drm_lease.c | 35 ++++++++++++++++++++++++----------- include/drm/drm_device.h | 5 +++++ 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 73ade0513ccb..65065f7e1499 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -120,6 +120,10 @@ int drm_authmagic(struct drm_device *dev, void *data, DRM_DEBUG("%u\n", auth->magic); down_write(&dev->master_rwsem); + if (unlikely(!drm_is_current_master(file_priv))) { + up_write(&dev->master_rwsem); + return -EACCES; + } file = idr_find(&file_priv->master->magic_map, auth->magic); if (file) { file->authenticated = 1; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 158629d88319..8bea39ffc5c0 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -386,6 +386,10 @@ static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *f int if_version, retcode = 0; down_write(&dev->master_rwsem); + if (unlikely(!drm_is_current_master(file_priv))) { + retcode = -EACCES; + goto unlock; + } if (sv->drm_di_major != -1) { if (sv->drm_di_major != DRM_IF_MAJOR || sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { @@ -420,8 +424,9 @@ static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *f sv->drm_di_minor = DRM_IF_MINOR; sv->drm_dd_major = dev->driver->major; sv->drm_dd_minor = dev->driver->minor; - up_write(&dev->master_rwsem); +unlock: + up_write(&dev->master_rwsem); return retcode; } @@ -574,12 +579,12 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), - DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), + DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, 0), DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_MASTER), + DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, 0), DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH), @@ -706,10 +711,10 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_CRTC_QUEUE_SEQUENCE, drm_crtc_queue_sequence_ioctl, 0), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, DRM_MASTER), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_LIST_LESSEES, drm_mode_list_lessees_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GET_LEASE, drm_mode_get_lease_ioctl, DRM_MASTER), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, DRM_MASTER), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, 0), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) @@ -776,6 +781,9 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY)) && !(flags & DRM_UNLOCKED)) mutex_lock(&drm_global_mutex); + if (unlikely(flags & DRM_MASTER)) + down_read(&dev->master_rwsem); + retcode = drm_ioctl_permit(flags, file_priv); if (unlikely(retcode)) goto out; @@ -783,6 +791,8 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, retcode = func(dev, kdata, file_priv); out: + if (unlikely(flags & DRM_MASTER)) + up_read(&dev->master_rwsem); if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY)) && !(flags & DRM_UNLOCKED)) mutex_unlock(&drm_global_mutex); return retcode; diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index dee4f24a1808..bed6f7636cbe 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -500,6 +500,18 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, return -EINVAL; } + /* Clone the lessor file to create a new file for us */ + DRM_DEBUG_LEASE("Allocating lease file\n"); + lessee_file = file_clone_open(lessor_file); + if (IS_ERR(lessee_file)) + return PTR_ERR(lessee_file); + + down_read(&dev->master_rwsem); + if (unlikely(!drm_is_current_master(lessor_priv))) { + ret = -EACCES; + goto out_file; + } + lessor = drm_file_get_master(lessor_priv); /* Do not allow sub-leases */ if (lessor->lessor) { @@ -547,14 +559,6 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, goto out_leases; } - /* Clone the lessor file to create a new file for us */ - DRM_DEBUG_LEASE("Allocating lease file\n"); - lessee_file = file_clone_open(lessor_file); - if (IS_ERR(lessee_file)) { - ret = PTR_ERR(lessee_file); - goto out_lessee; - } - lessee_priv = lessee_file->private_data; /* Change the file to a master one */ drm_master_put(&lessee_priv->master); @@ -571,17 +575,19 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, fd_install(fd, lessee_file); drm_master_put(&lessor); + up_read(&dev->master_rwsem); DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n"); return 0; -out_lessee: - drm_master_put(&lessee); - out_leases: put_unused_fd(fd); out_lessor: drm_master_put(&lessor); + +out_file: + up_read(&dev->master_rwsem); + fput(lessee_file); DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret); return ret; } @@ -705,6 +711,11 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; + down_write(&dev->master_rwsem); + if (unlikely(!drm_is_current_master(lessor_priv))) { + ret = -EACCES; + goto unlock; + } lessor = drm_file_get_master(lessor_priv); mutex_lock(&dev->mode_config.idr_mutex); @@ -728,5 +739,7 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev, mutex_unlock(&dev->mode_config.idr_mutex); drm_master_put(&lessor); +unlock: + up_write(&dev->master_rwsem); return ret; } diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index 142fb2f6e74d..7d32bb69e6db 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -151,6 +151,11 @@ struct drm_device { * Lock for &drm_device.master, &drm_file.was_master, * &drm_file.is_master, &drm_file.master, &drm_master.unique, * &drm_master.unique_len, and &drm_master.magic_map. + * + * Additionally, synchronizes modesetting rights between multiple users. + * Users that can change the modeset or display state must hold a read + * lock on @master_rwsem, and users that change modesetting rights + * should hold a write lock. */ struct rw_semaphore master_rwsem; From patchwork Mon Aug 23 17:14:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Desmond Cheong Zhi Xi X-Patchwork-Id: 12453293 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E0190C4338F for ; Mon, 23 Aug 2021 17:15:43 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B154D61452 for ; Mon, 23 Aug 2021 17:15:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org B154D61452 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 2CFFD6E090; Mon, 23 Aug 2021 17:15:43 +0000 (UTC) Received: from mail-pg1-x530.google.com (mail-pg1-x530.google.com [IPv6:2607:f8b0:4864:20::530]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4E0EA6E090; Mon, 23 Aug 2021 17:15:42 +0000 (UTC) Received: by mail-pg1-x530.google.com with SMTP id n18so17265071pgm.12; Mon, 23 Aug 2021 10:15:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=LBNnbRdOB7gSyGYfTznXsYtZJZQrtVufmncq+RbfE9Q=; b=hG8Mzg+1ySiHuITmyp+yvPuFpdEA3NP/19iTrD/Y0g0PtxF/8NMH2RdPjpY+kbjKoC lgv6NuYvXX+ah1Ke3DNhU9t+K2wY7IXGibMNDyvyWvRGRz8ST+sNlTJrgXezunIw4Y8Z GwOykfo+d5qT42m40aTeOUsNhh+aYQzE7lPgiQ6SDVXJu443TytjA87r6yaN1S+1aABn 4q7ueSkFnhzrZdi95OgKPwaCwFOnpBWcG/utpwxSqpbNwBwCSUFbDw3zRKeeb8QyvQYq tfX37J3sQ7cVKCRDvHwOLFTchIfpZNpfFtppYryIroIl0qB/zmOfRs8guAGNwPt+IbA3 /lOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=LBNnbRdOB7gSyGYfTznXsYtZJZQrtVufmncq+RbfE9Q=; b=CYgMgJcxLZCp8CR/qqsbThZMN4UgYDnYkWmN9AmTocuP3wdhi74brnqqRI140K/2wn f786jMQxFUtIiQBuA6M6vxuz2wey18zGLMIin3D6nkQ+ALnf3sDKCZo8r56UM2Di6wzh OtboHc+UgEsgHxoR0NNdhJwzyhReohHmXh14DXC0ZhRWFvub/FRFPc2SEM6hVgQytRn/ Er8w6DySiG0OAdFh54I7yqiB/M1LzYUa2DhJTdexvHZ+Iv9cWImmVfakat7wnDvBRNK+ G+ob3vj/NsCbBuaQJfcb1OXON8ERiE8+R+PIn8nGuSvvVoSGpvYPjWnVVTBtZSWbWIgA srhw== X-Gm-Message-State: AOAM533uvRr69TljQPad01czdMtvrpCnMOhHvqqEptRzciSRtfKi/3Sw ESgcCbdF1MV+iDX8K0vHltA= X-Google-Smtp-Source: ABdhPJzxaeW8uzTG1uHXrwZSAw+OnE8hM7SpDAvhq7TC2oOZJYxygouMsEegHA38RAs8r14uZK+YzA== X-Received: by 2002:aa7:850c:0:b0:3e2:edf3:3d09 with SMTP id v12-20020aa7850c000000b003e2edf33d09mr28372462pfn.42.1629738941879; Mon, 23 Aug 2021 10:15:41 -0700 (PDT) Received: from localhost.localdomain ([118.200.190.93]) by smtp.gmail.com with ESMTPSA id q4sm14290830pjd.52.2021.08.23.10.15.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 10:15:41 -0700 (PDT) From: Desmond Cheong Zhi Xi To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, daniel@ffwll.ch, sumit.semwal@linaro.org, christian.koenig@amd.com Cc: Desmond Cheong Zhi Xi , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org Date: Tue, 24 Aug 2021 01:14:36 +0800 Message-Id: <20210823171437.829404-6-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210823171437.829404-1-desmondcheongzx@gmail.com> References: <20210823171437.829404-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v5 5/6] drm: avoid circular locks with modeset_mutex and master_rwsem X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" drm_device.master_rwsem is an outer lock that's grabbed in the ioctl handler. However, in a future patch, master_rwsem will replace drm_file.master_lookup_lock in drm_file_get_master, which is sometimes called while holding other locks that depend on master_rwsem. This circular locking should be avoided to prevent deadlocks. _drm_lease_held and drm_lease_held call drm_file_get_master. However, both functions are called while holding on to modeset_mutex, inverting the master_rwsem --> modeset_mutex lock hierarchy. To fix this, we do two things: 1. Wrap __drm_mode_object_find with read locks on master_rwsem before locking modeset mutex so that we can still safely access drm_file.master without drm_file_get_master 2. Call drm_file_get_master before locking modeset_mutex, then check for leases with the new drm_lease_held_master function instead of drm_lease_held Signed-off-by: Desmond Cheong Zhi Xi --- drivers/gpu/drm/drm_atomic_uapi.c | 4 +++- drivers/gpu/drm/drm_auth.c | 3 +++ drivers/gpu/drm/drm_encoder.c | 7 ++++++- drivers/gpu/drm/drm_framebuffer.c | 2 +- drivers/gpu/drm/drm_lease.c | 34 ++++++++----------------------- drivers/gpu/drm/drm_mode_object.c | 16 +++++++++++---- drivers/gpu/drm/drm_plane.c | 17 +++++++++++++--- drivers/gpu/drm/drm_property.c | 6 +++--- include/drm/drm_lease.h | 4 +++- 9 files changed, 53 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 909f31833181..203b0936f7f4 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -1366,6 +1366,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, if (!state) return -ENOMEM; + down_read(&dev->master_rwsem); drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); state->acquire_ctx = &ctx; state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); @@ -1385,7 +1386,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, goto out; } - obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY); + obj = __drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY); if (!obj) { ret = -ENOENT; goto out; @@ -1474,6 +1475,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); + up_read(&dev->master_rwsem); return ret; } diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 65065f7e1499..f2b2f197052a 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -410,6 +410,9 @@ struct drm_master *drm_file_get_master(struct drm_file *file_priv) { struct drm_master *master = NULL; + if (!file_priv) + return NULL; + spin_lock(&file_priv->master_lookup_lock); if (!file_priv->master) goto unlock; diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 72e982323a5e..a4852876f91f 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -22,6 +22,7 @@ #include +#include #include #include #include @@ -281,6 +282,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, struct drm_mode_get_encoder *enc_resp = data; struct drm_encoder *encoder; struct drm_crtc *crtc; + struct drm_master *master = NULL; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; @@ -289,13 +291,16 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, if (!encoder) return -ENOENT; + master = drm_file_get_master(file_priv); drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); crtc = drm_encoder_get_crtc(encoder); - if (crtc && drm_lease_held(file_priv, crtc->base.id)) + if (crtc && drm_lease_held_master(master, crtc->base.id)) enc_resp->crtc_id = crtc->base.id; else enc_resp->crtc_id = 0; drm_modeset_unlock(&dev->mode_config.connection_mutex); + if (master) + drm_master_put(&master); enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_id = encoder->base.id; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 07f5abc875e9..9c1db91b150d 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -887,7 +887,7 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, struct drm_mode_object *obj; struct drm_framebuffer *fb = NULL; - obj = __drm_mode_object_find(dev, file_priv, id, DRM_MODE_OBJECT_FB); + obj = drm_mode_object_find(dev, file_priv, id, DRM_MODE_OBJECT_FB); if (obj) fb = obj_to_fb(obj); return fb; diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index bed6f7636cbe..4d434ee6730d 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -85,7 +85,7 @@ _drm_find_lessee(struct drm_master *master, int lessee_id) return idr_find(&drm_lease_owner(master)->lessee_idr, lessee_id); } -static int _drm_lease_held_master(struct drm_master *master, int id) +bool _drm_lease_held_master(struct drm_master *master, int id) { lockdep_assert_held(&master->dev->mode_config.idr_mutex); if (master->lessor) @@ -105,20 +105,16 @@ static bool _drm_has_leased(struct drm_master *master, int id) return false; } -/* Called with idr_mutex held */ -bool _drm_lease_held(struct drm_file *file_priv, int id) +bool drm_lease_held_master(struct drm_master *master, int id) { bool ret; - struct drm_master *master; - if (!file_priv) + if (!master || !master->lessor) return true; - master = drm_file_get_master(file_priv); - if (!master) - return true; + mutex_lock(&master->dev->mode_config.idr_mutex); ret = _drm_lease_held_master(master, id); - drm_master_put(&master); + mutex_unlock(&master->dev->mode_config.idr_mutex); return ret; } @@ -128,22 +124,11 @@ bool drm_lease_held(struct drm_file *file_priv, int id) struct drm_master *master; bool ret; - if (!file_priv) - return true; - master = drm_file_get_master(file_priv); - if (!master) - return true; - if (!master->lessor) { - ret = true; - goto out; - } - mutex_lock(&master->dev->mode_config.idr_mutex); - ret = _drm_lease_held_master(master, id); - mutex_unlock(&master->dev->mode_config.idr_mutex); + ret = drm_lease_held_master(master, id); + if (master) + drm_master_put(&master); -out: - drm_master_put(&master); return ret; } @@ -159,9 +144,6 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in) int count_in, count_out; uint32_t crtcs_out = 0; - if (!file_priv) - return crtcs_in; - master = drm_file_get_master(file_priv); if (!master) return crtcs_in; diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index 86d9e907c0b2..911f658a8ffc 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -139,6 +139,7 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, { struct drm_mode_object *obj = NULL; + lockdep_assert_held_once(&dev->master_rwsem); mutex_lock(&dev->mode_config.idr_mutex); obj = idr_find(&dev->mode_config.object_idr, id); if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) @@ -146,9 +147,11 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, if (obj && obj->id != id) obj = NULL; - if (obj && drm_mode_object_lease_required(obj->type) && - !_drm_lease_held(file_priv, obj->id)) - obj = NULL; + if (obj && drm_mode_object_lease_required(obj->type)) { + if (file_priv && file_priv->master && + !_drm_lease_held_master(file_priv->master, obj->id)) + obj = NULL; + } if (obj && obj->free_cb) { if (!kref_get_unless_zero(&obj->refcount)) @@ -176,7 +179,9 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, { struct drm_mode_object *obj = NULL; + down_read(&dev->master_rwsem); obj = __drm_mode_object_find(dev, file_priv, id, type); + up_read(&dev->master_rwsem); return obj; } EXPORT_SYMBOL(drm_mode_object_find); @@ -408,9 +413,12 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; + down_read(&dev->master_rwsem); DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); - obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); + obj = __drm_mode_object_find(dev, file_priv, arg->obj_id, + arg->obj_type); + up_read(&dev->master_rwsem); if (!obj) { ret = -ENOENT; goto out; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 82afb854141b..90f056169331 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -687,6 +688,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, struct drm_mode_get_plane *plane_resp = data; struct drm_plane *plane; uint32_t __user *format_ptr; + struct drm_master *master = NULL; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; @@ -695,10 +697,13 @@ int drm_mode_getplane(struct drm_device *dev, void *data, if (!plane) return -ENOENT; + master = drm_file_get_master(file_priv); drm_modeset_lock(&plane->mutex, NULL); - if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id)) + if (plane->state && plane->state->crtc && + drm_lease_held_master(master, plane->state->crtc->base.id)) plane_resp->crtc_id = plane->state->crtc->base.id; - else if (!plane->state && plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id)) + else if (!plane->state && plane->crtc && + drm_lease_held_master(master, plane->crtc->base.id)) plane_resp->crtc_id = plane->crtc->base.id; else plane_resp->crtc_id = 0; @@ -710,6 +715,8 @@ int drm_mode_getplane(struct drm_device *dev, void *data, else plane_resp->fb_id = 0; drm_modeset_unlock(&plane->mutex); + if (master) + drm_master_put(&master); plane_resp->plane_id = plane->base.id; plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv, @@ -1100,6 +1107,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, { struct drm_crtc *crtc; struct drm_modeset_acquire_ctx ctx; + struct drm_master *master = NULL; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -1114,6 +1122,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, return -ENOENT; } + master = drm_file_get_master(file_priv); drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); retry: ret = drm_modeset_lock(&crtc->mutex, &ctx); @@ -1128,7 +1137,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, if (ret) goto out; - if (!drm_lease_held(file_priv, crtc->cursor->base.id)) { + if (!drm_lease_held_master(master, crtc->cursor->base.id)) { ret = -EACCES; goto out; } @@ -1168,6 +1177,8 @@ static int drm_mode_cursor_common(struct drm_device *dev, drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); + if (master) + drm_master_put(&master); return ret; diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index 6c353c9dc772..9f04dcb81d07 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -656,7 +656,7 @@ struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, struct drm_mode_object *obj; struct drm_property_blob *blob = NULL; - obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB); + obj = drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB); if (obj) blob = obj_to_blob(obj); return blob; @@ -919,8 +919,8 @@ bool drm_property_change_valid_get(struct drm_property *property, if (value == 0) return true; - *ref = __drm_mode_object_find(property->dev, NULL, value, - property->values[0]); + *ref = drm_mode_object_find(property->dev, NULL, value, + property->values[0]); return *ref != NULL; } diff --git a/include/drm/drm_lease.h b/include/drm/drm_lease.h index 5c9ef6a2aeae..62d9de6ecada 100644 --- a/include/drm/drm_lease.h +++ b/include/drm/drm_lease.h @@ -16,7 +16,9 @@ void drm_lease_destroy(struct drm_master *lessee); bool drm_lease_held(struct drm_file *file_priv, int id); -bool _drm_lease_held(struct drm_file *file_priv, int id); +bool _drm_lease_held_master(struct drm_master *master, int id); + +bool drm_lease_held_master(struct drm_master *master, int id); void drm_lease_revoke(struct drm_master *master); From patchwork Mon Aug 23 17:14:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Desmond Cheong Zhi Xi X-Patchwork-Id: 12453295 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B290C4320E for ; Mon, 23 Aug 2021 17:15:50 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5C68861439 for ; Mon, 23 Aug 2021 17:15:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 5C68861439 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 933EB6E09A; Mon, 23 Aug 2021 17:15:49 +0000 (UTC) Received: from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com [IPv6:2607:f8b0:4864:20::1032]) by gabe.freedesktop.org (Postfix) with ESMTPS id 12EE66E098; Mon, 23 Aug 2021 17:15:48 +0000 (UTC) Received: by mail-pj1-x1032.google.com with SMTP id 28-20020a17090a031cb0290178dcd8a4d1so354217pje.0; Mon, 23 Aug 2021 10:15:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CdghZpU/IFDZvN5I3/y7/a/xtgVOyRJ35c5/RV+v4JY=; b=mVsjlqYdzeDLyBD0PWUsN65UBIYuGXzoWgzPNxLnqRaNuX7LFuk+RxHds6S+4sIvhx s997V11GbCqL8laqi+0vmBZI0k7LGuFqm1W3iCm/O3A79IGVPAK6Zh2KARvT6TlPbpUi n2q9EGeBEtuVU5GxCk4j8tyBLnJ9Ah20qbcoxOEbMRLd7AuFIl4obOuu15h92q4hi7mj RFYnD4ys5li8ph0idHRldYJI63a6r1bM+UD2t978QdH/7bDr3bp79QGt381o2cysUOO5 vQ6upvLZZDBIYGd2kDbsbJZSCSI7s4q83j49Cqra0l+BtltlWg+gTP2x/zvNEsK589jI 1eFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CdghZpU/IFDZvN5I3/y7/a/xtgVOyRJ35c5/RV+v4JY=; b=WbLvqlu3qH0ZrDKSvY0sBkt5Ga1QsIAfjkbAR3jCLFrOMoQsR7exw/HFQxERkQ8sHm Wy4xdolYAyRH3qQFTm+7N6Xbv2gbBurAcBMv98MOyKGlxMGRQBhYWACJX4k9IJFnDkoU BohykL7vTDEgZDPq60//EjmSymB7AMqoCJrIgXVcptRoqvc8ZP3NCXF/E++zikFSpLIS rJkmmdwPqG5yxxH0mPk5WjERP0ztvW2U6WOha18cIzDpos9d6I1LwApZqBSU8ntF9ONM DZArZLe6Em3WsCugX8naQ3ru8wic3CsVPXHxX2BYthckgS+MHq94ND0sBAbHfj9ffDlQ rWvw== X-Gm-Message-State: AOAM530TJoqmXNvLuobg7Y7OeZgnliptUS44nyNeEptFbBrVXQLOxoQ1 XyiHmJf/rqTcvuK4vVNxreY= X-Google-Smtp-Source: ABdhPJym8/kr10k6SS6CXqcSfaEbWEMxvZA2Ay+uj8o8TFJ/2iQggZFVs+WYnnWXOldqaYwU9M6sTg== X-Received: by 2002:a17:902:8c81:b029:12c:ee37:3f58 with SMTP id t1-20020a1709028c81b029012cee373f58mr29374647plo.45.1629738947651; Mon, 23 Aug 2021 10:15:47 -0700 (PDT) Received: from localhost.localdomain ([118.200.190.93]) by smtp.gmail.com with ESMTPSA id q4sm14290830pjd.52.2021.08.23.10.15.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 10:15:47 -0700 (PDT) From: Desmond Cheong Zhi Xi To: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, daniel@ffwll.ch, sumit.semwal@linaro.org, christian.koenig@amd.com Cc: Desmond Cheong Zhi Xi , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org Date: Tue, 24 Aug 2021 01:14:37 +0800 Message-Id: <20210823171437.829404-7-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210823171437.829404-1-desmondcheongzx@gmail.com> References: <20210823171437.829404-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v5 6/6] drm: remove drm_file.master_lookup_lock X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Previously, master_lookup_lock was introduced in commit 0b0860a3cf5e ("drm: serialize drm_file.master with a new spinlock") to serialize accesses to drm_file.master. This then allowed us to write drm_file_get_master in commit 56f0729a510f ("drm: protect drm_master pointers in drm_lease.c"). The rationale behind introducing a new spinlock at the time was that the other lock that could have been used (drm_device.master_mutex) was the outermost lock, so embedding calls to drm_file_get_master and drm_is_current_master in various functions easily caused us to invert the lock hierarchy. Following the conversion of master_mutex into a rwsem, and its use to plug races with modesetting rights, we've untangled some lock hierarchies and removed the need for using drm_file_get_master and the unlocked version of drm_is_current_master in multiple places. Additionally, a previous patch fixed other remaining inversions involving master_rwsem and modeset_mutex. Hence, we can take this opportunity to clean up the locking design by replacing master_lookup_lock with drm_device.master_rwsem. Signed-off-by: Desmond Cheong Zhi Xi --- drivers/gpu/drm/drm_auth.c | 19 +++++++------------ drivers/gpu/drm/drm_file.c | 1 - drivers/gpu/drm/drm_internal.h | 1 + drivers/gpu/drm/drm_ioctl.c | 4 ++-- drivers/gpu/drm/drm_lease.c | 18 ++++++++---------- include/drm/drm_file.h | 9 +-------- 6 files changed, 19 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index f2b2f197052a..232416119407 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -61,10 +61,9 @@ * trusted clients. */ -static bool drm_is_current_master_locked(struct drm_file *fpriv) +bool drm_is_current_master_locked(struct drm_file *fpriv) { - lockdep_assert_once(lockdep_is_held(&fpriv->master_lookup_lock) || - lockdep_is_held(&fpriv->minor->dev->master_rwsem)); + lockdep_assert_held_once(&fpriv->minor->dev->master_rwsem); return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master; } @@ -83,9 +82,9 @@ bool drm_is_current_master(struct drm_file *fpriv) { bool ret; - spin_lock(&fpriv->master_lookup_lock); + down_read(&fpriv->minor->dev->master_rwsem); ret = drm_is_current_master_locked(fpriv); - spin_unlock(&fpriv->master_lookup_lock); + up_read(&fpriv->minor->dev->master_rwsem); return ret; } @@ -120,7 +119,7 @@ int drm_authmagic(struct drm_device *dev, void *data, DRM_DEBUG("%u\n", auth->magic); down_write(&dev->master_rwsem); - if (unlikely(!drm_is_current_master(file_priv))) { + if (unlikely(!drm_is_current_master_locked(file_priv))) { up_write(&dev->master_rwsem); return -EACCES; } @@ -178,9 +177,7 @@ static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) new_master = drm_master_create(dev); if (!new_master) return -ENOMEM; - spin_lock(&fpriv->master_lookup_lock); fpriv->master = new_master; - spin_unlock(&fpriv->master_lookup_lock); fpriv->is_master = 1; fpriv->authenticated = 1; @@ -343,9 +340,7 @@ int drm_master_open(struct drm_file *file_priv) if (!dev->master) { ret = drm_new_set_master(dev, file_priv); } else { - spin_lock(&file_priv->master_lookup_lock); file_priv->master = drm_master_get(dev->master); - spin_unlock(&file_priv->master_lookup_lock); } up_write(&dev->master_rwsem); @@ -413,13 +408,13 @@ struct drm_master *drm_file_get_master(struct drm_file *file_priv) if (!file_priv) return NULL; - spin_lock(&file_priv->master_lookup_lock); + down_read(&file_priv->minor->dev->master_rwsem); if (!file_priv->master) goto unlock; master = drm_master_get(file_priv->master); unlock: - spin_unlock(&file_priv->master_lookup_lock); + up_read(&file_priv->minor->dev->master_rwsem); return master; } EXPORT_SYMBOL(drm_file_get_master); diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 90b62f360da1..8c846e0179d7 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -176,7 +176,6 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor) init_waitqueue_head(&file->event_wait); file->event_space = 4096; /* set aside 4k for event buffer */ - spin_lock_init(&file->master_lookup_lock); mutex_init(&file->event_read_lock); if (drm_core_check_feature(dev, DRIVER_GEM)) diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 17f3548c8ed2..5d421f749a17 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -132,6 +132,7 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); /* drm_auth.c */ +bool drm_is_current_master_locked(struct drm_file *fpriv); int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_authmagic(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 8bea39ffc5c0..c728437466c3 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -386,7 +386,7 @@ static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *f int if_version, retcode = 0; down_write(&dev->master_rwsem); - if (unlikely(!drm_is_current_master(file_priv))) { + if (unlikely(!drm_is_current_master_locked(file_priv))) { retcode = -EACCES; goto unlock; } @@ -540,7 +540,7 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) /* MASTER is only for master or control clients */ if (unlikely((flags & DRM_MASTER) && - !drm_is_current_master(file_priv))) + !drm_is_current_master_locked(file_priv))) return -EACCES; /* Render clients must be explicitly allowed */ diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index 4d434ee6730d..fe6286072d30 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -489,12 +489,12 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, return PTR_ERR(lessee_file); down_read(&dev->master_rwsem); - if (unlikely(!drm_is_current_master(lessor_priv))) { + if (unlikely(!drm_is_current_master_locked(lessor_priv))) { ret = -EACCES; goto out_file; } - lessor = drm_file_get_master(lessor_priv); + lessor = lessor_priv->master; /* Do not allow sub-leases */ if (lessor->lessor) { DRM_DEBUG_LEASE("recursive leasing not allowed\n"); @@ -556,7 +556,6 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, /* Hook up the fd */ fd_install(fd, lessee_file); - drm_master_put(&lessor); up_read(&dev->master_rwsem); DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n"); return 0; @@ -591,7 +590,8 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; - lessor = drm_file_get_master(lessor_priv); + lockdep_assert_held_once(&dev->master_rwsem); + lessor = lessor_priv->master; DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id); mutex_lock(&dev->mode_config.idr_mutex); @@ -615,7 +615,6 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev, arg->count_lessees = count; mutex_unlock(&dev->mode_config.idr_mutex); - drm_master_put(&lessor); return ret; } @@ -641,7 +640,8 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; - lessee = drm_file_get_master(lessee_priv); + lockdep_assert_held_once(&dev->master_rwsem); + lessee = lessee_priv->master; DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id); mutex_lock(&dev->mode_config.idr_mutex); @@ -669,7 +669,6 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev, arg->count_objects = count; mutex_unlock(&dev->mode_config.idr_mutex); - drm_master_put(&lessee); return ret; } @@ -694,11 +693,11 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev, return -EOPNOTSUPP; down_write(&dev->master_rwsem); - if (unlikely(!drm_is_current_master(lessor_priv))) { + if (unlikely(!drm_is_current_master_locked(lessor_priv))) { ret = -EACCES; goto unlock; } - lessor = drm_file_get_master(lessor_priv); + lessor = lessor_priv->master; mutex_lock(&dev->mode_config.idr_mutex); lessee = _drm_find_lessee(lessor, arg->lessee_id); @@ -719,7 +718,6 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev, fail: mutex_unlock(&dev->mode_config.idr_mutex); - drm_master_put(&lessor); unlock: up_write(&dev->master_rwsem); diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index d12bb2ba7814..e2d49fe3e32d 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -227,16 +227,12 @@ struct drm_file { * @master: * * Master this node is currently associated with. Protected by struct - * &drm_device.master_rwsem, and serialized by @master_lookup_lock. + * &drm_device.master_rwsem. * * Only relevant if drm_is_primary_client() returns true. Note that * this only matches &drm_device.master if the master is the currently * active one. * - * To update @master, both &drm_device.master_rwsem and - * @master_lookup_lock need to be held, therefore holding either of - * them is safe and enough for the read side. - * * When dereferencing this pointer, either hold struct * &drm_device.master_rwsem for the duration of the pointer's use, or * use drm_file_get_master() if struct &drm_device.master_rwsem is not @@ -248,9 +244,6 @@ struct drm_file { */ struct drm_master *master; - /** @master_lock: Serializes @master. */ - spinlock_t master_lookup_lock; - /** @pid: Process that opened this file. */ struct pid *pid;