From patchwork Tue Aug 31 07:24:58 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: 12466645 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=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 76E26C4320A for ; Tue, 31 Aug 2021 07:25:40 +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 3F61E6101B for ; Tue, 31 Aug 2021 07:25:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 3F61E6101B 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 2CFAF89BFD; Tue, 31 Aug 2021 07:25:39 +0000 (UTC) Received: from mail-pj1-x1033.google.com (mail-pj1-x1033.google.com [IPv6:2607:f8b0:4864:20::1033]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7761489BFC; Tue, 31 Aug 2021 07:25:37 +0000 (UTC) Received: by mail-pj1-x1033.google.com with SMTP id mw10-20020a17090b4d0a00b0017b59213831so1345012pjb.0; Tue, 31 Aug 2021 00:25:37 -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=tHn1bKbgKWkWnpZZfeyzrlp2g8PdlS3oPFK4wibr8zM=; b=pMjwOP/19qT52lkjXq8sDWHfx7YGZ8eUQGoIKFiBmpYZXRbATElia9k4erKkY4o+gx bPv9Q+ALqfj6l0g/7NXoYBsBaUHHT+6gpUJC0TZZA35oV6yJRINlv14SbH4wmA+hWnld A5j6PaQ1FR2HPB1VVcngEVYOmhQ+NpLjrks7l/GQz3GiD/Ij6t9cbltGAt9Ghki/8W2G 8wonwnJqSZ31sN7su4nbQ9ehq6UPI2UCarkMqTB4TAcyt0O3UBFAOrpejOLa2u2DFQOG seyxkNmsGWqWrmFUoPEtoV5VSb1OXPvizXaVppaQ4FJhDNDk0jkvQTAQjwiWAZ/5FHb6 r8Gw== 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=tHn1bKbgKWkWnpZZfeyzrlp2g8PdlS3oPFK4wibr8zM=; b=GRmxi9Bcr6bc0YgZkFk6GcdMwC5hbWmcsYV5N+/KwE7yunDGzrqN1WfcErlk9sMoUf f5En0CHg49OqvfCjAbn3z3bArd29JoKts3G8QKeKcDWE7yMXWbP6dSAcW8q04a82gnn5 xP1zFkH/9N5/W5F5Y3Edaeoqowlo09oe2jE2b1dah+W7Rimrg42YIH+3gBVkKsSHryNs ojR4/8bUER0dzvDzcFJ9qCusLY0HAbGDzIcHsS4cozbB0EBlPEW35FtverG41Rpj0FPC uB4BuwMU/xGI5xOeXFZrhMMUCjFaBxGZcGaAmoHrMIxet5GMwXalvniZRo/9/QoD6ZrM zfjQ== X-Gm-Message-State: AOAM531d4NyFn9X+CtlLKuej8rSNmksKN2KSPt40iTU0CgLtGqBPkOlr MgPZzEmJTsYF2X/qMkc5w84= X-Google-Smtp-Source: ABdhPJzpV2t1yFkjJNCWkF5oIEd1fc2kRhKJQqIj82vlMWjQvXBEEUimnllxLVlQqW5CEZE3+9QHpA== X-Received: by 2002:a17:90a:2e88:: with SMTP id r8mr3698988pjd.169.1630394737112; Tue, 31 Aug 2021 00:25:37 -0700 (PDT) Received: from sanitydock.wifi-cloud.jp ([210.160.217.69]) by smtp.gmail.com with ESMTPSA id m11sm1720724pjn.2.2021.08.31.00.25.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Aug 2021 00:25:36 -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, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, stable@vger.kernel.org, Daniel Vetter Subject: [PATCH v10 1/4] drm: fix null ptr dereference in drm_master_release Date: Tue, 31 Aug 2021 15:24:58 +0800 Message-Id: <20210831072501.184211-2-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210831072501.184211-1-desmondcheongzx@gmail.com> References: <20210831072501.184211-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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. Fixes: 7eeaeb90a6a5 ("drm/file: Don't set master on in-kernel clients") Signed-off-by: Desmond Cheong Zhi Xi Cc: stable@vger.kernel.org Reviewed-by: Daniel Vetter --- 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 Tue Aug 31 07:24:59 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: 12466647 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=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 E0979C432BE for ; Tue, 31 Aug 2021 07:25:46 +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 B06DE60FE8 for ; Tue, 31 Aug 2021 07:25:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org B06DE60FE8 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 1239889C18; Tue, 31 Aug 2021 07:25:46 +0000 (UTC) Received: from mail-pl1-x634.google.com (mail-pl1-x634.google.com [IPv6:2607:f8b0:4864:20::634]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4A56589C1A; Tue, 31 Aug 2021 07:25:43 +0000 (UTC) Received: by mail-pl1-x634.google.com with SMTP id m17so10076391plc.6; Tue, 31 Aug 2021 00:25:43 -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=Krc6ajDEx+zL1Z6rjoMP/o/AE40lzjEKULCugIhiSwo=; b=G84e9NB1rWS2lnZVB3yaRsE8QkV/DJycoiFaXSErgoDP2voybT1ZflcmSy4h/PBU2r XdwERPGVnK8O6039ZRLIZicz0N4Nc/QyeQ309pWjmLn/c6zUtHILFA84hy0ohotHC5U1 tkLfp99AcwBCw9wde0iUE3nfwUxJK5cFwk0kxlIwEjuBQ5MntAtkGhjHXyElLj1RN4Lk /namUGxY1HvI4V2Hc84CEhJYeDba7YV121Y3Je02zbmK4r55aiGIMq9/Tevnj/++H+NW rUBFD0WCWptaoiJpfewh+IalpTne8V1W7uBT+QLSZJbuKhXNV9B/TXBukgTwYirMRbpL Ve+w== 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=Krc6ajDEx+zL1Z6rjoMP/o/AE40lzjEKULCugIhiSwo=; b=GIgIriddP4PJ85jOE4HMgyfDWiA7BTz5ikDb6Lc+P5Q17+qZHPRLLde8ZTfpTW/cZ7 6VN6Ywcn+l38MX5/Xg5aHJHpS9nNG3RVzkZFXtmpgQvi5bEonOw1n7eqKitTacFDV7KJ g9MWWMVSn3p4W2OEpqks/kL4vUKMb5veeKQqRXpZlyCm1+AA6t1utZa7gloAbvUY8il/ jnC8b8jVvUsolQ4ZrJeanBO8+5mgvnGXq6oGNqWzpAvqmhcHrnMbCQCypx/PcS99H1ut 6QFo9mdbemCaY/uCwscHpPwsuG+Nk1FvLwmTFq8NebyREkg6WR+b5WbuoYCN5dgtZG9D C4wA== X-Gm-Message-State: AOAM530ByHc5FEtExnVzugxqpx8eoRQKglvaXuOVFga9/YlL9JttIJKw f6NdVp2OrsLxJqYljQDUWuQ= X-Google-Smtp-Source: ABdhPJyIFuth0aOQwowwTQAHD+R6qKvDOqUblbQnivpFk4ozL9dCCWLKez7ilYZpWkTSFsvmDrfMug== X-Received: by 2002:a17:90a:ab8f:: with SMTP id n15mr3799895pjq.154.1630394742810; Tue, 31 Aug 2021 00:25:42 -0700 (PDT) Received: from sanitydock.wifi-cloud.jp ([210.160.217.69]) by smtp.gmail.com with ESMTPSA id m11sm1720724pjn.2.2021.08.31.00.25.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Aug 2021 00:25:42 -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, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, Daniel Vetter Subject: [PATCH v10 2/4] drm: convert drm_device.master_mutex into a rwsem Date: Tue, 31 Aug 2021 15:24:59 +0800 Message-Id: <20210831072501.184211-3-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210831072501.184211-1-desmondcheongzx@gmail.com> References: <20210831072501.184211-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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 Reviewed-by: Daniel Vetter --- 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 8b8744dcf691..9fc00e36c5d6 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 Tue Aug 31 07:25:00 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: 12466649 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=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 928D8C43216 for ; Tue, 31 Aug 2021 07:25:51 +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 54AFE6023E for ; Tue, 31 Aug 2021 07:25:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 54AFE6023E 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 848B689DDD; Tue, 31 Aug 2021 07:25:50 +0000 (UTC) Received: from mail-pj1-x1030.google.com (mail-pj1-x1030.google.com [IPv6:2607:f8b0:4864:20::1030]) by gabe.freedesktop.org (Postfix) with ESMTPS id B848889DDD; Tue, 31 Aug 2021 07:25:48 +0000 (UTC) Received: by mail-pj1-x1030.google.com with SMTP id j1so11178771pjv.3; Tue, 31 Aug 2021 00:25: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=FzExCBQE7rwMYVKetJ9aGi6+oVAsZBZjfgGFXxeHd5E=; b=LXe0f4nPVCe1oh3x5+e3cE7j/bEYgV/8zc80PbZ6LXQLG2n57Lx1fHt9akzFhqF06M vTvHuTvzUYHRxqmg69BlMsboB6VGAAGly8qOMokYCtmYecsc/TOUv+8JqRokhbx5GxOf 7AygM2bgBVxhQiCJ+s58MVLwLzRG/hbTFKHxlKIBKZrVwYd8An/rad3jdSNesX1cumJH kim90j9snnZU2/XgbD1BGQHgdYI+34sJTM6Na8n8uyhqGf+YOlaw6x6qj5shKYDbrYDE /gEJcfnkwnbfBUfokZXQMndj6Ux36lZJFc0ABmo8rh6Fp59spcjw6h7Gh/LyKq5bjNxX cypw== 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=FzExCBQE7rwMYVKetJ9aGi6+oVAsZBZjfgGFXxeHd5E=; b=cjA1kRf19UTQXv/sRgJhKaGfe55YWdH0ahu9kjR/yGN3kElQRSPWeXrakKwpSR+7Iy X8N9Z3xxP6Vq1cV0DKQxAq3PCvnQx102k5s1HiWjYM1YVflGWRwBQZcGj7QK8Xxz++Iq h+j6oiQ7CMdCVLP10iYbRYla+EoQKiQO+rnMd/ie/FpZlkKnVqRStOuQc/l2yKzUHPii 3OkpES8W4//F0Woi0gaDj19P8RuPqVbicYPVLVtrZKqcwvYwQEzBPnLDIZGgd2TjOxgL 17sYj8/9GRuJiUk02FKF8QfUxaH3lcNS1Z6Y8G2dTYsoMAqy9rKD4qL0p5Ynw6IlRkHA I7Ng== X-Gm-Message-State: AOAM533xMoASfPBLjVEo3VHQBDA/OxMGnGniqay+YxetWdkTgIR6NVbe 2LaBnQCpq4h0/Uwh3j2li3k= X-Google-Smtp-Source: ABdhPJysGpkZ0cAY6VQlN8tnvez7JJZxx3OJmr6/KKxgL/wi48F5mbtV0mBFI6qvB9e1Z3DLUIq34w== X-Received: by 2002:a17:90a:e64a:: with SMTP id ep10mr3657825pjb.167.1630394748361; Tue, 31 Aug 2021 00:25:48 -0700 (PDT) Received: from sanitydock.wifi-cloud.jp ([210.160.217.69]) by smtp.gmail.com with ESMTPSA id m11sm1720724pjn.2.2021.08.31.00.25.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Aug 2021 00:25: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, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, Daniel Vetter Subject: [PATCH v10 3/4] drm: lock drm_global_mutex earlier in the ioctl handler Date: Tue, 31 Aug 2021 15:25:00 +0800 Message-Id: <20210831072501.184211-4-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210831072501.184211-1-desmondcheongzx@gmail.com> References: <20210831072501.184211-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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 Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_ioctl.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 9fc00e36c5d6..fe9c4c0264a9 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -767,24 +767,27 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, { struct drm_file *file_priv = file->private_data; struct drm_device *dev = file_priv->minor->dev; + bool locked_ioctl; int retcode; if (drm_dev_is_unplugged(dev)) return -ENODEV; + /* Enforce sane locking for modern driver ioctls. */ + locked_ioctl = (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY)) && + !(flags & DRM_UNLOCKED)); + if (locked_ioctl) + 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 (locked_ioctl) mutex_unlock(&drm_global_mutex); - } return retcode; } EXPORT_SYMBOL(drm_ioctl_kernel); From patchwork Tue Aug 31 07:25:01 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: 12466651 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=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 DBA24C4320E for ; Tue, 31 Aug 2021 07:25:58 +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 ACF6760200 for ; Tue, 31 Aug 2021 07:25:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org ACF6760200 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 8857A89E5F; Tue, 31 Aug 2021 07:25:57 +0000 (UTC) Received: from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com [IPv6:2607:f8b0:4864:20::102a]) by gabe.freedesktop.org (Postfix) with ESMTPS id 59E7089E5F; Tue, 31 Aug 2021 07:25:56 +0000 (UTC) Received: by mail-pj1-x102a.google.com with SMTP id g13-20020a17090a3c8d00b00196286963b9so1305157pjc.3; Tue, 31 Aug 2021 00:25:56 -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=SrrV3clumIwMrnsDunPCSljyK6+I7diizgnIMV5VDGM=; b=D4Uczj5ScpNKrJc2Y6vF1YPgkC+QRmy1Lv0ltH1JckfUAHsuIJWIxJpkh2L8SsiJ64 hjMuPVqUafy/ebyVLdcsvRAp5Qnreo8eWUBy5IDRrnG1/3+UTrVMheVSoWbi+roIQVj8 yq2JpQPV/EEiCfdoyR5o3Oqe/ylclUPgep/W1bl2+fm9F3dkmfgRhmyUtmFTkhFFg+OC r+OWKESZFBqJPMGKZMAIb5N0Z5mpiZgZpv9r2vPUzT6r6dxeh11uDgksd8CtFLfjsBPA Egn31ZHbxhSnWGwI9JsDGWFMO2glYjsHi/m5JcIuTd6GdhRoUADTbsHv5QZaTrVXWZf7 TeNg== 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=SrrV3clumIwMrnsDunPCSljyK6+I7diizgnIMV5VDGM=; b=GBgPsn6ukdcH6/LNITWExt7j9z8pto/vWdI2hKPKmFyHoQvOFUsr/ZK19Xf6p/6aJb kZ7ohGPQiQnLPIzHWHOdk1nDDe6lKDcQQ/zvfaQ3YcelJgy1MuR3ifDOzCpWzbDC4AGJ qXh3nkFA44guZdY4vZYzT2gwiMxJv66nu8WQFmmy4G3773PkJNYphLz7OseE60eeQ4Jv xo3LMP6MFh2XisFNc/68Y7EHZG2agy3z+h704y0yrw4t8qm7o7egirx0J1JII/MSYf2O NS0DwnK3qf5msMYukVrdREvkOSR4nyap4MqozbtT9au4HSmBwLQZ4sAfHTd5Uu/OYg/Q gpQA== X-Gm-Message-State: AOAM530tLFxH2HlwKi8aTCuj2daV714MkeoocnUEFQgfqcyBDKpw3EN7 OvTZ86SpO+AMsaP2eJNHcmo= X-Google-Smtp-Source: ABdhPJx6BRnSMBYnfZwO2vU0ugdP71fbA/c8IXcsv4fhMgZvTRVKDTzBrOOTXreNdkilLdMY8+POLw== X-Received: by 2002:a17:90a:cf81:: with SMTP id i1mr3731701pju.76.1630394755924; Tue, 31 Aug 2021 00:25:55 -0700 (PDT) Received: from sanitydock.wifi-cloud.jp ([210.160.217.69]) by smtp.gmail.com with ESMTPSA id m11sm1720724pjn.2.2021.08.31.00.25.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Aug 2021 00:25:55 -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, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, Daniel Vetter Subject: [PATCH v10 4/4] drm: avoid races with modesetting rights Date: Tue, 31 Aug 2021 15:25:01 +0800 Message-Id: <20210831072501.184211-5-desmondcheongzx@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210831072501.184211-1-desmondcheongzx@gmail.com> References: <20210831072501.184211-1-desmondcheongzx@gmail.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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 Reviewed-by: Daniel Vetter --- 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 | 6 ++++++ 4 files changed, 49 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 fe9c4c0264a9..f6a8aa6c53b3 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) @@ -779,6 +784,9 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, if (locked_ioctl) 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; @@ -786,6 +794,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 (locked_ioctl) 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..5504f9192408 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -151,6 +151,12 @@ 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 access rights to exclusive resources like + * modesetting access between multiple users. For example, 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;