linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] drm, drm/vmwgfx: fixes and updates related to drm_master
@ 2021-07-22  9:29 Desmond Cheong Zhi Xi
  2021-07-22  9:29 ` [PATCH 1/3] drm: use the lookup lock in drm_is_current_master Desmond Cheong Zhi Xi
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Desmond Cheong Zhi Xi @ 2021-07-22  9:29 UTC (permalink / raw)
  To: linux-graphics-maintainer, zackr, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann
  Cc: Desmond Cheong Zhi Xi, dri-devel, linux-kernel, intel-gfx, skhan,
	gregkh, linux-kernel-mentees

Hi,

This series contains some improvements that Daniel Vetter proposed following a discussion on a recent series:
https://lore.kernel.org/lkml/20210712043508.11584-1-desmondcheongzx@gmail.com/

While preparing these patches, I also noticed some unprotected uses of drm_master in the vmwgfx driver that can be addressed by new functions from the previous series.

This series is thus broken up into three patches:

1. Switch from the outer drm_device.master_mutex to the inner drm_file.master_lookup_lock in drm_is_current_master.

2. Update the kerneldoc for lease fields in drm_master to clarify lifetime/locking rules.

3. Prevent potential use-after-free bugs by replacing calls to drm_master_get with drm_file_get_master in vmwgfx_surface.c.

Best wishes,
Desmond

Desmond Cheong Zhi Xi (3):
  drm: use the lookup lock in drm_is_current_master
  drm: clarify lifetime/locking for drm_master's lease fields
  drm/vmwgfx: fix potential UAF in vmwgfx_surface.c

 drivers/gpu/drm/drm_auth.c              |  9 ++--
 drivers/gpu/drm/vmwgfx/vmwgfx_surface.c |  4 +-
 include/drm/drm_auth.h                  | 62 ++++++++++++++++++++-----
 3 files changed, 58 insertions(+), 17 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-22  9:29 [PATCH 0/3] drm, drm/vmwgfx: fixes and updates related to drm_master Desmond Cheong Zhi Xi
@ 2021-07-22  9:29 ` Desmond Cheong Zhi Xi
  2021-07-22 10:38   ` Daniel Vetter
  2021-07-22  9:29 ` [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields Desmond Cheong Zhi Xi
  2021-07-22  9:29 ` [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c Desmond Cheong Zhi Xi
  2 siblings, 1 reply; 18+ messages in thread
From: Desmond Cheong Zhi Xi @ 2021-07-22  9:29 UTC (permalink / raw)
  To: linux-graphics-maintainer, zackr, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann
  Cc: Desmond Cheong Zhi Xi, dri-devel, linux-kernel, intel-gfx, skhan,
	gregkh, linux-kernel-mentees, Daniel Vetter

Inside drm_is_current_master, using the outer drm_device.master_mutex
to protect reads of drm_file.master makes the function prone to creating
lock hierarchy inversions. Instead, we can use the
drm_file.master_lookup_lock that sits at the bottom of the lock
hierarchy.

Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
---
 drivers/gpu/drm/drm_auth.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index f00354bec3fb..9c24b8cc8e36 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -63,8 +63,9 @@
 
 static bool drm_is_current_master_locked(struct drm_file *fpriv)
 {
-	lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
-
+	/* Either drm_device.master_mutex or drm_file.master_lookup_lock
+	 * should be held here.
+	 */
 	return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
 }
 
@@ -82,9 +83,9 @@ bool drm_is_current_master(struct drm_file *fpriv)
 {
 	bool ret;
 
-	mutex_lock(&fpriv->minor->dev->master_mutex);
+	spin_lock(&fpriv->master_lookup_lock);
 	ret = drm_is_current_master_locked(fpriv);
-	mutex_unlock(&fpriv->minor->dev->master_mutex);
+	spin_unlock(&fpriv->master_lookup_lock);
 
 	return ret;
 }
-- 
2.25.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields
  2021-07-22  9:29 [PATCH 0/3] drm, drm/vmwgfx: fixes and updates related to drm_master Desmond Cheong Zhi Xi
  2021-07-22  9:29 ` [PATCH 1/3] drm: use the lookup lock in drm_is_current_master Desmond Cheong Zhi Xi
@ 2021-07-22  9:29 ` Desmond Cheong Zhi Xi
  2021-07-22 10:35   ` Daniel Vetter
  2021-07-22  9:29 ` [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c Desmond Cheong Zhi Xi
  2 siblings, 1 reply; 18+ messages in thread
From: Desmond Cheong Zhi Xi @ 2021-07-22  9:29 UTC (permalink / raw)
  To: linux-graphics-maintainer, zackr, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann
  Cc: Desmond Cheong Zhi Xi, dri-devel, linux-kernel, intel-gfx, skhan,
	gregkh, linux-kernel-mentees

In particular, we make it clear that &drm_device.mode_config.idr_mutex
protects the lease idr and list structures for drm_master. The lessor
field itself doesn't need to be protected as it doesn't change after
it's set in drm_lease_create.

Additionally, we add descriptions for the lifetime of lessors and
leases to make it easier to reason about them.

Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
---
 include/drm/drm_auth.h | 62 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 11 deletions(-)

diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h
index f99d3417f304..c978c85464fa 100644
--- a/include/drm/drm_auth.h
+++ b/include/drm/drm_auth.h
@@ -58,12 +58,6 @@ struct drm_lock_data {
  * @refcount: Refcount for this master object.
  * @dev: Link back to the DRM device
  * @driver_priv: Pointer to driver-private information.
- * @lessor: Lease holder
- * @lessee_id: id for lessees. Owners always have id 0
- * @lessee_list: other lessees of the same master
- * @lessees: drm_masters leasing from this one
- * @leases: Objects leased to this drm_master.
- * @lessee_idr: All lessees under this owner (only used where lessor == NULL)
  *
  * Note that master structures are only relevant for the legacy/primary device
  * nodes, hence there can only be one per device, not one per drm_minor.
@@ -88,17 +82,63 @@ struct drm_master {
 	struct idr magic_map;
 	void *driver_priv;
 
-	/* Tree of display resource leases, each of which is a drm_master struct
-	 * All of these get activated simultaneously, so drm_device master points
-	 * at the top of the tree (for which lessor is NULL). Protected by
-	 * &drm_device.mode_config.idr_mutex.
+	/**
+	 * @lessor:
+	 *
+	 * Lease holder. The lessor does not change once it's set in
+	 * drm_lease_create(). Each lessee holds a reference to its lessor that
+	 * it releases upon being destroyed in drm_lease_destroy().
+	 *
+	 * Display resource leases form a tree of &struct drm_master. All of
+	 * these get activated simultaneously, so &drm_device.master
+	 * points at the top of the tree (for which lessor is NULL).
 	 */
-
 	struct drm_master *lessor;
+
+	/**
+	 * @lessee_id:
+	 *
+	 * ID for lessees. Owners always have ID 0. Protected by
+	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
+	 */
 	int	lessee_id;
+
+	/**
+	 * @lessee_list:
+	 *
+	 * List of lessees of the same master. Protected by
+	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
+	 */
 	struct list_head lessee_list;
+
+	/**
+	 * @lessees:
+	 *
+	 * List of drm_masters leasing from this one. Protected by
+	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
+	 *
+	 * This master cannot be destroyed unless this list is empty as lessors
+	 * are referenced by all their lessees.
+	 */
 	struct list_head lessees;
+
+	/**
+	 * @leases:
+	 *
+	 * Objects leased to this drm_master. Protected by
+	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
+	 *
+	 * Objects are leased all together in drm_lease_create(), and are
+	 * removed all together when the lease is revoked.
+	 */
 	struct idr leases;
+
+	/**
+	 * @lessee_idr:
+	 *
+	 * All lessees under this owner (only used where lessor is NULL).
+	 * Protected by &drm_device.mode_config's &drm_mode_config.idr_mutex.
+	 */
 	struct idr lessee_idr;
 	/* private: */
 #if IS_ENABLED(CONFIG_DRM_LEGACY)
-- 
2.25.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c
  2021-07-22  9:29 [PATCH 0/3] drm, drm/vmwgfx: fixes and updates related to drm_master Desmond Cheong Zhi Xi
  2021-07-22  9:29 ` [PATCH 1/3] drm: use the lookup lock in drm_is_current_master Desmond Cheong Zhi Xi
  2021-07-22  9:29 ` [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields Desmond Cheong Zhi Xi
@ 2021-07-22  9:29 ` Desmond Cheong Zhi Xi
  2021-07-22 10:39   ` Daniel Vetter
  2021-07-22 19:17   ` Zack Rusin
  2 siblings, 2 replies; 18+ messages in thread
From: Desmond Cheong Zhi Xi @ 2021-07-22  9:29 UTC (permalink / raw)
  To: linux-graphics-maintainer, zackr, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann
  Cc: Desmond Cheong Zhi Xi, dri-devel, linux-kernel, intel-gfx, skhan,
	gregkh, linux-kernel-mentees

drm_file.master should be protected by either drm_device.master_mutex
or drm_file.master_lookup_lock when being dereferenced. However,
drm_master_get is called on unprotected file_priv->master pointers in
vmw_surface_define_ioctl and vmw_gb_surface_define_internal.

This is fixed by replacing drm_master_get with drm_file_get_master.

Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 0eba47762bed..5d53a5f9d123 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -865,7 +865,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
 	user_srf->prime.base.shareable = false;
 	user_srf->prime.base.tfile = NULL;
 	if (drm_is_primary_client(file_priv))
-		user_srf->master = drm_master_get(file_priv->master);
+		user_srf->master = drm_file_get_master(file_priv);
 
 	/**
 	 * From this point, the generic resource management functions
@@ -1534,7 +1534,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
 
 	user_srf = container_of(srf, struct vmw_user_surface, srf);
 	if (drm_is_primary_client(file_priv))
-		user_srf->master = drm_master_get(file_priv->master);
+		user_srf->master = drm_file_get_master(file_priv);
 
 	res = &user_srf->srf.res;
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields
  2021-07-22  9:29 ` [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields Desmond Cheong Zhi Xi
@ 2021-07-22 10:35   ` Daniel Vetter
  2021-07-22 13:02     ` Desmond Cheong Zhi Xi
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Vetter @ 2021-07-22 10:35 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi
  Cc: linux-graphics-maintainer, zackr, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann, dri-devel, linux-kernel,
	intel-gfx, skhan, gregkh, linux-kernel-mentees

On Thu, Jul 22, 2021 at 05:29:28PM +0800, Desmond Cheong Zhi Xi wrote:
> In particular, we make it clear that &drm_device.mode_config.idr_mutex
> protects the lease idr and list structures for drm_master. The lessor
> field itself doesn't need to be protected as it doesn't change after
> it's set in drm_lease_create.
> 
> Additionally, we add descriptions for the lifetime of lessors and
> leases to make it easier to reason about them.
> 
> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> ---
>  include/drm/drm_auth.h | 62 ++++++++++++++++++++++++++++++++++--------
>  1 file changed, 51 insertions(+), 11 deletions(-)
> 
> diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h
> index f99d3417f304..c978c85464fa 100644
> --- a/include/drm/drm_auth.h
> +++ b/include/drm/drm_auth.h
> @@ -58,12 +58,6 @@ struct drm_lock_data {
>   * @refcount: Refcount for this master object.
>   * @dev: Link back to the DRM device
>   * @driver_priv: Pointer to driver-private information.
> - * @lessor: Lease holder
> - * @lessee_id: id for lessees. Owners always have id 0
> - * @lessee_list: other lessees of the same master
> - * @lessees: drm_masters leasing from this one
> - * @leases: Objects leased to this drm_master.
> - * @lessee_idr: All lessees under this owner (only used where lessor == NULL)
>   *
>   * Note that master structures are only relevant for the legacy/primary device
>   * nodes, hence there can only be one per device, not one per drm_minor.
> @@ -88,17 +82,63 @@ struct drm_master {
>  	struct idr magic_map;
>  	void *driver_priv;
>  
> -	/* Tree of display resource leases, each of which is a drm_master struct
> -	 * All of these get activated simultaneously, so drm_device master points
> -	 * at the top of the tree (for which lessor is NULL). Protected by
> -	 * &drm_device.mode_config.idr_mutex.
> +	/**
> +	 * @lessor:
> +	 *
> +	 * Lease holder. The lessor does not change once it's set in

Lessor is the lease grantor, lessee is the one receiving the lease. Maybe
clarify this with

"Lease grantor, only set if this struct drm_master represents a lessee
holding a lease of objects from @lessor. Full owners of the device have
this set to NULL."

> +	 * drm_lease_create(). Each lessee holds a reference to its lessor that

I also figured it'd be a good idea to link to the drm_lease docs here to
explain the concepts, but alas we don't have those :-( Hence at least
define what we mean with lessor, lessee, lease and owner.

> +	 * it releases upon being destroyed in drm_lease_destroy().
> +	 *
> +	 * Display resource leases form a tree of &struct drm_master. All of

For now we've limited the tree to a depth of 1, you can't create another
lease if yourself are a lease. I guess another reason to update the
drm_lease.c docs.

So maybe add "Currently the lease tree depth is limited to 1."

> +	 * these get activated simultaneously, so &drm_device.master
> +	 * points at the top of the tree (for which lessor is NULL).
>  	 */
> -
>  	struct drm_master *lessor;
> +
> +	/**
> +	 * @lessee_id:
> +	 *
> +	 * ID for lessees. Owners always have ID 0. Protected by

Maybe clarify to "Owners (i.e. @lessor is NULL) ..."

> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> +	 */
>  	int	lessee_id;
> +
> +	/**
> +	 * @lessee_list:
> +	 *
> +	 * List of lessees of the same master. Protected by

We try to distinguis between list entries and the list, even though it's
the same struct. So maybe

"List entry of lessees of @lessor, where they are linked to @lessee. Not
use for owners."

> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.

> +	 */
>  	struct list_head lessee_list;
> +
> +	/**
> +	 * @lessees:
> +	 *
> +	 * List of drm_masters leasing from this one. Protected by
> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> +	 *
> +	 * This master cannot be destroyed unless this list is empty as lessors
> +	 * are referenced by all their lessees.

Maybe add "this list is empty of no leases have been granted."

> +	 */
>  	struct list_head lessees;
> +
> +	/**
> +	 * @leases:
> +	 *
> +	 * Objects leased to this drm_master. Protected by
> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> +	 *
> +	 * Objects are leased all together in drm_lease_create(), and are
> +	 * removed all together when the lease is revoked.
> +	 */
>  	struct idr leases;
> +
> +	/**
> +	 * @lessee_idr:
> +	 *
> +	 * All lessees under this owner (only used where lessor is NULL).

@lessor so it's highlighted correctly

> +	 * Protected by &drm_device.mode_config's &drm_mode_config.idr_mutex.
> +	 */
>  	struct idr lessee_idr;
>  	/* private: */

With the nits addressed:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Thanks for updating the docs!
-Daniel

>  #if IS_ENABLED(CONFIG_DRM_LEGACY)
> -- 
> 2.25.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-22  9:29 ` [PATCH 1/3] drm: use the lookup lock in drm_is_current_master Desmond Cheong Zhi Xi
@ 2021-07-22 10:38   ` Daniel Vetter
  2021-07-22 15:04     ` Boqun Feng
  2021-07-27 14:37     ` Peter Zijlstra
  0 siblings, 2 replies; 18+ messages in thread
From: Daniel Vetter @ 2021-07-22 10:38 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi, Boqun Feng, LKML, Peter Zijlstra
  Cc: linux-graphics-maintainer, zackr, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann, dri-devel, linux-kernel,
	intel-gfx, skhan, gregkh, linux-kernel-mentees, Daniel Vetter

On Thu, Jul 22, 2021 at 05:29:27PM +0800, Desmond Cheong Zhi Xi wrote:
> Inside drm_is_current_master, using the outer drm_device.master_mutex
> to protect reads of drm_file.master makes the function prone to creating
> lock hierarchy inversions. Instead, we can use the
> drm_file.master_lookup_lock that sits at the bottom of the lock
> hierarchy.
> 
> Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> ---
>  drivers/gpu/drm/drm_auth.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> index f00354bec3fb..9c24b8cc8e36 100644
> --- a/drivers/gpu/drm/drm_auth.c
> +++ b/drivers/gpu/drm/drm_auth.c
> @@ -63,8 +63,9 @@
>  
>  static bool drm_is_current_master_locked(struct drm_file *fpriv)
>  {
> -	lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
> -
> +	/* Either drm_device.master_mutex or drm_file.master_lookup_lock
> +	 * should be held here.
> +	 */

Disappointing that lockdep can't check or conditions for us, a
lockdep_assert_held_either would be really neat in some cases.

Adding lockdep folks, maybe they have ideas.

On the patch:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

>  	return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
>  }
>  
> @@ -82,9 +83,9 @@ bool drm_is_current_master(struct drm_file *fpriv)
>  {
>  	bool ret;
>  
> -	mutex_lock(&fpriv->minor->dev->master_mutex);
> +	spin_lock(&fpriv->master_lookup_lock);
>  	ret = drm_is_current_master_locked(fpriv);
> -	mutex_unlock(&fpriv->minor->dev->master_mutex);
> +	spin_unlock(&fpriv->master_lookup_lock);
>  
>  	return ret;
>  }
> -- 
> 2.25.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c
  2021-07-22  9:29 ` [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c Desmond Cheong Zhi Xi
@ 2021-07-22 10:39   ` Daniel Vetter
  2021-07-22 19:17   ` Zack Rusin
  1 sibling, 0 replies; 18+ messages in thread
From: Daniel Vetter @ 2021-07-22 10:39 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi
  Cc: linux-graphics-maintainer, zackr, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann, dri-devel, linux-kernel,
	intel-gfx, skhan, gregkh, linux-kernel-mentees

On Thu, Jul 22, 2021 at 05:29:29PM +0800, Desmond Cheong Zhi Xi wrote:
> drm_file.master should be protected by either drm_device.master_mutex
> or drm_file.master_lookup_lock when being dereferenced. However,
> drm_master_get is called on unprotected file_priv->master pointers in
> vmw_surface_define_ioctl and vmw_gb_surface_define_internal.
> 
> This is fixed by replacing drm_master_get with drm_file_get_master.
> 
> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

I'll let Zack take a look at this and expect him to push this patch to
drm-misc.git.
-Daniel

> ---
>  drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
> index 0eba47762bed..5d53a5f9d123 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
> @@ -865,7 +865,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
>  	user_srf->prime.base.shareable = false;
>  	user_srf->prime.base.tfile = NULL;
>  	if (drm_is_primary_client(file_priv))
> -		user_srf->master = drm_master_get(file_priv->master);
> +		user_srf->master = drm_file_get_master(file_priv);
>  
>  	/**
>  	 * From this point, the generic resource management functions
> @@ -1534,7 +1534,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
>  
>  	user_srf = container_of(srf, struct vmw_user_surface, srf);
>  	if (drm_is_primary_client(file_priv))
> -		user_srf->master = drm_master_get(file_priv->master);
> +		user_srf->master = drm_file_get_master(file_priv);
>  
>  	res = &user_srf->srf.res;
>  
> -- 
> 2.25.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields
  2021-07-22 10:35   ` Daniel Vetter
@ 2021-07-22 13:02     ` Desmond Cheong Zhi Xi
  2021-07-22 14:17       ` Daniel Vetter
  0 siblings, 1 reply; 18+ messages in thread
From: Desmond Cheong Zhi Xi @ 2021-07-22 13:02 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: linux-graphics-maintainer, zackr, airlied, maarten.lankhorst,
	mripard, tzimmermann, dri-devel, linux-kernel, intel-gfx, skhan,
	gregkh, linux-kernel-mentees

On 22/7/21 6:35 pm, Daniel Vetter wrote:
> On Thu, Jul 22, 2021 at 05:29:28PM +0800, Desmond Cheong Zhi Xi wrote:
>> In particular, we make it clear that &drm_device.mode_config.idr_mutex
>> protects the lease idr and list structures for drm_master. The lessor
>> field itself doesn't need to be protected as it doesn't change after
>> it's set in drm_lease_create.
>>
>> Additionally, we add descriptions for the lifetime of lessors and
>> leases to make it easier to reason about them.
>>
>> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
>> ---
>>   include/drm/drm_auth.h | 62 ++++++++++++++++++++++++++++++++++--------
>>   1 file changed, 51 insertions(+), 11 deletions(-)
>>
>> diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h
>> index f99d3417f304..c978c85464fa 100644
>> --- a/include/drm/drm_auth.h
>> +++ b/include/drm/drm_auth.h
>> @@ -58,12 +58,6 @@ struct drm_lock_data {
>>    * @refcount: Refcount for this master object.
>>    * @dev: Link back to the DRM device
>>    * @driver_priv: Pointer to driver-private information.
>> - * @lessor: Lease holder
>> - * @lessee_id: id for lessees. Owners always have id 0
>> - * @lessee_list: other lessees of the same master
>> - * @lessees: drm_masters leasing from this one
>> - * @leases: Objects leased to this drm_master.
>> - * @lessee_idr: All lessees under this owner (only used where lessor == NULL)
>>    *
>>    * Note that master structures are only relevant for the legacy/primary device
>>    * nodes, hence there can only be one per device, not one per drm_minor.
>> @@ -88,17 +82,63 @@ struct drm_master {
>>   	struct idr magic_map;
>>   	void *driver_priv;
>>   
>> -	/* Tree of display resource leases, each of which is a drm_master struct
>> -	 * All of these get activated simultaneously, so drm_device master points
>> -	 * at the top of the tree (for which lessor is NULL). Protected by
>> -	 * &drm_device.mode_config.idr_mutex.
>> +	/**
>> +	 * @lessor:
>> +	 *
>> +	 * Lease holder. The lessor does not change once it's set in
> 
> Lessor is the lease grantor, lessee is the one receiving the lease. Maybe
> clarify this with
> 
> "Lease grantor, only set if this struct drm_master represents a lessee
> holding a lease of objects from @lessor. Full owners of the device have
> this set to NULL."
> 
>> +	 * drm_lease_create(). Each lessee holds a reference to its lessor that
> 
> I also figured it'd be a good idea to link to the drm_lease docs here to
> explain the concepts, but alas we don't have those :-( Hence at least
> define what we mean with lessor, lessee, lease and owner.
> 

Thanks for the suggestions, Daniel. I'll incorporate them in a v2.

Regarding the missing drm_lease docs... any reason we can't just add it 
in? Seems like most of the comments in drm_lease.c are almost correctly 
formatted too. I could clean them up, define the terms in a preamble, 
then add it to the v2 patch.

>> +	 * it releases upon being destroyed in drm_lease_destroy().
>> +	 *
>> +	 * Display resource leases form a tree of &struct drm_master. All of
> 
> For now we've limited the tree to a depth of 1, you can't create another
> lease if yourself are a lease. I guess another reason to update the
> drm_lease.c docs.
> 
> So maybe add "Currently the lease tree depth is limited to 1."
> 
>> +	 * these get activated simultaneously, so &drm_device.master
>> +	 * points at the top of the tree (for which lessor is NULL).
>>   	 */
>> -
>>   	struct drm_master *lessor;
>> +
>> +	/**
>> +	 * @lessee_id:
>> +	 *
>> +	 * ID for lessees. Owners always have ID 0. Protected by
> 
> Maybe clarify to "Owners (i.e. @lessor is NULL) ..."
> 
>> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
>> +	 */
>>   	int	lessee_id;
>> +
>> +	/**
>> +	 * @lessee_list:
>> +	 *
>> +	 * List of lessees of the same master. Protected by
> 
> We try to distinguis between list entries and the list, even though it's
> the same struct. So maybe
> 
> "List entry of lessees of @lessor, where they are linked to @lessee. Not
> use for owners."
> 
>> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> 
>> +	 */
>>   	struct list_head lessee_list;
>> +
>> +	/**
>> +	 * @lessees:
>> +	 *
>> +	 * List of drm_masters leasing from this one. Protected by
>> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
>> +	 *
>> +	 * This master cannot be destroyed unless this list is empty as lessors
>> +	 * are referenced by all their lessees.
> 
> Maybe add "this list is empty of no leases have been granted."
> 
>> +	 */
>>   	struct list_head lessees;
>> +
>> +	/**
>> +	 * @leases:
>> +	 *
>> +	 * Objects leased to this drm_master. Protected by
>> +	 * &drm_device.mode_config's &drm_mode_config.idr_mutex.
>> +	 *
>> +	 * Objects are leased all together in drm_lease_create(), and are
>> +	 * removed all together when the lease is revoked.
>> +	 */
>>   	struct idr leases;
>> +
>> +	/**
>> +	 * @lessee_idr:
>> +	 *
>> +	 * All lessees under this owner (only used where lessor is NULL).
> 
> @lessor so it's highlighted correctly
> 
>> +	 * Protected by &drm_device.mode_config's &drm_mode_config.idr_mutex.
>> +	 */
>>   	struct idr lessee_idr;
>>   	/* private: */
> 
> With the nits addressed:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Thanks for updating the docs!
> -Daniel
> 
>>   #if IS_ENABLED(CONFIG_DRM_LEGACY)
>> -- 
>> 2.25.1
>>
> 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields
  2021-07-22 13:02     ` Desmond Cheong Zhi Xi
@ 2021-07-22 14:17       ` Daniel Vetter
  0 siblings, 0 replies; 18+ messages in thread
From: Daniel Vetter @ 2021-07-22 14:17 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi
  Cc: VMware Graphics, Zack Rusin, Dave Airlie, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, dri-devel,
	Linux Kernel Mailing List, intel-gfx, Shuah Khan, Greg KH,
	linux-kernel-mentees

On Thu, Jul 22, 2021 at 3:03 PM Desmond Cheong Zhi Xi
<desmondcheongzx@gmail.com> wrote:
>
> On 22/7/21 6:35 pm, Daniel Vetter wrote:
> > On Thu, Jul 22, 2021 at 05:29:28PM +0800, Desmond Cheong Zhi Xi wrote:
> >> In particular, we make it clear that &drm_device.mode_config.idr_mutex
> >> protects the lease idr and list structures for drm_master. The lessor
> >> field itself doesn't need to be protected as it doesn't change after
> >> it's set in drm_lease_create.
> >>
> >> Additionally, we add descriptions for the lifetime of lessors and
> >> leases to make it easier to reason about them.
> >>
> >> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> >> ---
> >>   include/drm/drm_auth.h | 62 ++++++++++++++++++++++++++++++++++--------
> >>   1 file changed, 51 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h
> >> index f99d3417f304..c978c85464fa 100644
> >> --- a/include/drm/drm_auth.h
> >> +++ b/include/drm/drm_auth.h
> >> @@ -58,12 +58,6 @@ struct drm_lock_data {
> >>    * @refcount: Refcount for this master object.
> >>    * @dev: Link back to the DRM device
> >>    * @driver_priv: Pointer to driver-private information.
> >> - * @lessor: Lease holder
> >> - * @lessee_id: id for lessees. Owners always have id 0
> >> - * @lessee_list: other lessees of the same master
> >> - * @lessees: drm_masters leasing from this one
> >> - * @leases: Objects leased to this drm_master.
> >> - * @lessee_idr: All lessees under this owner (only used where lessor == NULL)
> >>    *
> >>    * Note that master structures are only relevant for the legacy/primary device
> >>    * nodes, hence there can only be one per device, not one per drm_minor.
> >> @@ -88,17 +82,63 @@ struct drm_master {
> >>      struct idr magic_map;
> >>      void *driver_priv;
> >>
> >> -    /* Tree of display resource leases, each of which is a drm_master struct
> >> -     * All of these get activated simultaneously, so drm_device master points
> >> -     * at the top of the tree (for which lessor is NULL). Protected by
> >> -     * &drm_device.mode_config.idr_mutex.
> >> +    /**
> >> +     * @lessor:
> >> +     *
> >> +     * Lease holder. The lessor does not change once it's set in
> >
> > Lessor is the lease grantor, lessee is the one receiving the lease. Maybe
> > clarify this with
> >
> > "Lease grantor, only set if this struct drm_master represents a lessee
> > holding a lease of objects from @lessor. Full owners of the device have
> > this set to NULL."
> >
> >> +     * drm_lease_create(). Each lessee holds a reference to its lessor that
> >
> > I also figured it'd be a good idea to link to the drm_lease docs here to
> > explain the concepts, but alas we don't have those :-( Hence at least
> > define what we mean with lessor, lessee, lease and owner.
> >
>
> Thanks for the suggestions, Daniel. I'll incorporate them in a v2.
>
> Regarding the missing drm_lease docs... any reason we can't just add it
> in? Seems like most of the comments in drm_lease.c are almost correctly
> formatted too. I could clean them up, define the terms in a preamble,
> then add it to the v2 patch.

Sure if you want to do that, that would be great. Usual style tips:
- We only document driver interfaces, so structs/inline functions in
headers and exported symbols in .c files.
- Anything else interesting just leave as normal C comments
- An overview DOC: section that explains a bit how leases work and why
(git blame on the commit that added it should help, otherwise I can
type that up) would also be really great.

I think the right place for this is in the drm-uapi.rst section after
the section about primary nodes:

https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#modeset-base-object-abstraction

Cheers, Daniel


>
> >> +     * it releases upon being destroyed in drm_lease_destroy().
> >> +     *
> >> +     * Display resource leases form a tree of &struct drm_master. All of
> >
> > For now we've limited the tree to a depth of 1, you can't create another
> > lease if yourself are a lease. I guess another reason to update the
> > drm_lease.c docs.
> >
> > So maybe add "Currently the lease tree depth is limited to 1."
> >
> >> +     * these get activated simultaneously, so &drm_device.master
> >> +     * points at the top of the tree (for which lessor is NULL).
> >>       */
> >> -
> >>      struct drm_master *lessor;
> >> +
> >> +    /**
> >> +     * @lessee_id:
> >> +     *
> >> +     * ID for lessees. Owners always have ID 0. Protected by
> >
> > Maybe clarify to "Owners (i.e. @lessor is NULL) ..."
> >
> >> +     * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> >> +     */
> >>      int     lessee_id;
> >> +
> >> +    /**
> >> +     * @lessee_list:
> >> +     *
> >> +     * List of lessees of the same master. Protected by
> >
> > We try to distinguis between list entries and the list, even though it's
> > the same struct. So maybe
> >
> > "List entry of lessees of @lessor, where they are linked to @lessee. Not
> > use for owners."
> >
> >> +     * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> >
> >> +     */
> >>      struct list_head lessee_list;
> >> +
> >> +    /**
> >> +     * @lessees:
> >> +     *
> >> +     * List of drm_masters leasing from this one. Protected by
> >> +     * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> >> +     *
> >> +     * This master cannot be destroyed unless this list is empty as lessors
> >> +     * are referenced by all their lessees.
> >
> > Maybe add "this list is empty of no leases have been granted."
> >
> >> +     */
> >>      struct list_head lessees;
> >> +
> >> +    /**
> >> +     * @leases:
> >> +     *
> >> +     * Objects leased to this drm_master. Protected by
> >> +     * &drm_device.mode_config's &drm_mode_config.idr_mutex.
> >> +     *
> >> +     * Objects are leased all together in drm_lease_create(), and are
> >> +     * removed all together when the lease is revoked.
> >> +     */
> >>      struct idr leases;
> >> +
> >> +    /**
> >> +     * @lessee_idr:
> >> +     *
> >> +     * All lessees under this owner (only used where lessor is NULL).
> >
> > @lessor so it's highlighted correctly
> >
> >> +     * Protected by &drm_device.mode_config's &drm_mode_config.idr_mutex.
> >> +     */
> >>      struct idr lessee_idr;
> >>      /* private: */
> >
> > With the nits addressed:
> >
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >
> > Thanks for updating the docs!
> > -Daniel
> >
> >>   #if IS_ENABLED(CONFIG_DRM_LEGACY)
> >> --
> >> 2.25.1
> >>
> >
>


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-22 10:38   ` Daniel Vetter
@ 2021-07-22 15:04     ` Boqun Feng
  2021-07-22 19:02       ` Daniel Vetter
  2021-07-27 14:37     ` Peter Zijlstra
  1 sibling, 1 reply; 18+ messages in thread
From: Boqun Feng @ 2021-07-22 15:04 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi, LKML, Peter Zijlstra,
	linux-graphics-maintainer, zackr, airlied, maarten.lankhorst,
	mripard, tzimmermann, dri-devel, intel-gfx, skhan, gregkh,
	linux-kernel-mentees

On Thu, Jul 22, 2021 at 12:38:10PM +0200, Daniel Vetter wrote:
> On Thu, Jul 22, 2021 at 05:29:27PM +0800, Desmond Cheong Zhi Xi wrote:
> > Inside drm_is_current_master, using the outer drm_device.master_mutex
> > to protect reads of drm_file.master makes the function prone to creating
> > lock hierarchy inversions. Instead, we can use the
> > drm_file.master_lookup_lock that sits at the bottom of the lock
> > hierarchy.
> > 
> > Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> > ---
> >  drivers/gpu/drm/drm_auth.c | 9 +++++----
> >  1 file changed, 5 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> > index f00354bec3fb..9c24b8cc8e36 100644
> > --- a/drivers/gpu/drm/drm_auth.c
> > +++ b/drivers/gpu/drm/drm_auth.c
> > @@ -63,8 +63,9 @@
> >  
> >  static bool drm_is_current_master_locked(struct drm_file *fpriv)
> >  {
> > -	lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
> > -
> > +	/* Either drm_device.master_mutex or drm_file.master_lookup_lock
> > +	 * should be held here.
> > +	 */
> 
> Disappointing that lockdep can't check or conditions for us, a
> lockdep_assert_held_either would be really neat in some cases.
> 

The implementation is not hard but I don't understand the usage, for
example, if we have a global variable x, and two locks L1 and L2, and
the function

	void do_something_to_x(void)
	{
		lockdep_assert_held_either(L1, L2);
		x++;
	}

and two call sites:

	void f(void)
	{
		lock(L1);
		do_something_to_x();
		unlock(L1);
	}

	void g(void)
	{
		lock(L2);
		do_something_to_x();
		unlock(L2);
	}

, wouldn't it be racy if f() and g() called by two threads at the same
time? Usually I would expect there exists a third synchronazition
mechanism (say M), which synchronizes the calls to f() and g(), and we
put M in the lockdep_assert_held() check inside do_something_to_x()
like:

	void do_something_to_x(void)
	{
		lockdep_assert_held_once(M);
		x++;
	}

But of course, M may not be a lock, so we cannot put the assert there.

My cscope failed to find ->master_lookup_lock in -rc2 and seems it's not
introduced in the patchset either, could you point me the branch this
patchset is based on, so that I could understand this better, and maybe
come up with a solution? Thanks ;-)

Regards,
Boqun

> Adding lockdep folks, maybe they have ideas.
> 
> On the patch:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> >  	return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
> >  }
> >  
> > @@ -82,9 +83,9 @@ bool drm_is_current_master(struct drm_file *fpriv)
> >  {
> >  	bool ret;
> >  
> > -	mutex_lock(&fpriv->minor->dev->master_mutex);
> > +	spin_lock(&fpriv->master_lookup_lock);
> >  	ret = drm_is_current_master_locked(fpriv);
> > -	mutex_unlock(&fpriv->minor->dev->master_mutex);
> > +	spin_unlock(&fpriv->master_lookup_lock);
> >  
> >  	return ret;
> >  }
> > -- 
> > 2.25.1
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-22 15:04     ` Boqun Feng
@ 2021-07-22 19:02       ` Daniel Vetter
  2021-07-23  7:16         ` Boqun Feng
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Vetter @ 2021-07-22 19:02 UTC (permalink / raw)
  To: Boqun Feng
  Cc: Desmond Cheong Zhi Xi, LKML, Peter Zijlstra, VMware Graphics,
	Zack Rusin, Dave Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, dri-devel, intel-gfx, Shuah Khan, Greg KH,
	linux-kernel-mentees

On Thu, Jul 22, 2021 at 6:00 PM Boqun Feng <boqun.feng@gmail.com> wrote:
>
> On Thu, Jul 22, 2021 at 12:38:10PM +0200, Daniel Vetter wrote:
> > On Thu, Jul 22, 2021 at 05:29:27PM +0800, Desmond Cheong Zhi Xi wrote:
> > > Inside drm_is_current_master, using the outer drm_device.master_mutex
> > > to protect reads of drm_file.master makes the function prone to creating
> > > lock hierarchy inversions. Instead, we can use the
> > > drm_file.master_lookup_lock that sits at the bottom of the lock
> > > hierarchy.
> > >
> > > Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> > > ---
> > >  drivers/gpu/drm/drm_auth.c | 9 +++++----
> > >  1 file changed, 5 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> > > index f00354bec3fb..9c24b8cc8e36 100644
> > > --- a/drivers/gpu/drm/drm_auth.c
> > > +++ b/drivers/gpu/drm/drm_auth.c
> > > @@ -63,8 +63,9 @@
> > >
> > >  static bool drm_is_current_master_locked(struct drm_file *fpriv)
> > >  {
> > > -   lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
> > > -
> > > +   /* Either drm_device.master_mutex or drm_file.master_lookup_lock
> > > +    * should be held here.
> > > +    */
> >
> > Disappointing that lockdep can't check or conditions for us, a
> > lockdep_assert_held_either would be really neat in some cases.
> >
>
> The implementation is not hard but I don't understand the usage, for
> example, if we have a global variable x, and two locks L1 and L2, and
> the function
>
>         void do_something_to_x(void)
>         {
>                 lockdep_assert_held_either(L1, L2);
>                 x++;
>         }
>
> and two call sites:
>
>         void f(void)
>         {
>                 lock(L1);
>                 do_something_to_x();
>                 unlock(L1);
>         }
>
>         void g(void)
>         {
>                 lock(L2);
>                 do_something_to_x();
>                 unlock(L2);
>         }
>
> , wouldn't it be racy if f() and g() called by two threads at the same
> time? Usually I would expect there exists a third synchronazition
> mechanism (say M), which synchronizes the calls to f() and g(), and we
> put M in the lockdep_assert_held() check inside do_something_to_x()
> like:
>
>         void do_something_to_x(void)
>         {
>                 lockdep_assert_held_once(M);
>                 x++;
>         }
>
> But of course, M may not be a lock, so we cannot put the assert there.
>
> My cscope failed to find ->master_lookup_lock in -rc2 and seems it's not
> introduced in the patchset either, could you point me the branch this
> patchset is based on, so that I could understand this better, and maybe
> come up with a solution? Thanks ;-)

The use case is essentially 2 nesting locks, and only the innermost is
used to update a field. So when you only read this field, it's safe if
either of these two locks are held. Essentially this is a read/write lock
type of thing, except for various reasons the two locks might not be of
the same type (like here where the write lock is a mutex, but the read
lock is a spinlock).

It's a bit like the rcu_derefence macro where it's ok to either be in a
rcu_read_lock() section, or holding the relevant lock that's used to
update the value. We do _not_ have two different locks that allow writing
to the same X.

Does that make it clearer what's the use-case here?

In an example:

void * interesting_pointer.

do_update_interesting_pointer()
{
	mutex_lock(A);
	/* do more stuff to prepare things */
	spin_lock(B);
	interesting_pointer = new_value;
	spin_unlock(B);
	mutex_unlock(A);
}

read_interesting_thing_locked()
{
	lockdep_assert_held_either(A, B);

	return interesting_pointer->thing;
}

read_interesting_thing()
{
	int thing;
	spin_lock(B);
	thing = interesting_pointer->thing;
	spin_unlock(B);

	return B;
}

spinlock might also be irqsafe here if this can be called from irq
context.

Cheers, Daniel

> Regards,
> Boqun
>
> > Adding lockdep folks, maybe they have ideas.
> >
> > On the patch:
> >
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >
> > >     return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
> > >  }
> > >
> > > @@ -82,9 +83,9 @@ bool drm_is_current_master(struct drm_file *fpriv)
> > >  {
> > >     bool ret;
> > >
> > > -   mutex_lock(&fpriv->minor->dev->master_mutex);
> > > +   spin_lock(&fpriv->master_lookup_lock);
> > >     ret = drm_is_current_master_locked(fpriv);
> > > -   mutex_unlock(&fpriv->minor->dev->master_mutex);
> > > +   spin_unlock(&fpriv->master_lookup_lock);
> > >
> > >     return ret;
> > >  }
> > > --
> > > 2.25.1
> > >
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c
  2021-07-22  9:29 ` [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c Desmond Cheong Zhi Xi
  2021-07-22 10:39   ` Daniel Vetter
@ 2021-07-22 19:17   ` Zack Rusin
  2021-07-23  6:44     ` Desmond Cheong Zhi Xi
  1 sibling, 1 reply; 18+ messages in thread
From: Zack Rusin @ 2021-07-22 19:17 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi, linux-graphics-maintainer, airlied,
	daniel, maarten.lankhorst, mripard, tzimmermann
  Cc: dri-devel, linux-kernel, intel-gfx, skhan, gregkh, linux-kernel-mentees

On 7/22/21 5:29 AM, Desmond Cheong Zhi Xi wrote:
> drm_file.master should be protected by either drm_device.master_mutex
> or drm_file.master_lookup_lock when being dereferenced. However,
> drm_master_get is called on unprotected file_priv->master pointers in
> vmw_surface_define_ioctl and vmw_gb_surface_define_internal.
> 
> This is fixed by replacing drm_master_get with drm_file_get_master.
> 
> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>

Reviewed-by: Zack Rusin <zackr@vmware.com>

Thanks for taking the time to fix this. Apart from the clear logic error, do you happen to know under what circumstances would this be hit? We have someone looking at writing some vmwgfx specific igt tests and I was wondering if I could add this to the list.

z

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c
  2021-07-22 19:17   ` Zack Rusin
@ 2021-07-23  6:44     ` Desmond Cheong Zhi Xi
  0 siblings, 0 replies; 18+ messages in thread
From: Desmond Cheong Zhi Xi @ 2021-07-23  6:44 UTC (permalink / raw)
  To: Zack Rusin, linux-graphics-maintainer, airlied, daniel,
	maarten.lankhorst, mripard, tzimmermann
  Cc: dri-devel, linux-kernel, intel-gfx, skhan, gregkh, linux-kernel-mentees

On 23/7/21 3:17 am, Zack Rusin wrote:
> On 7/22/21 5:29 AM, Desmond Cheong Zhi Xi wrote:
>> drm_file.master should be protected by either drm_device.master_mutex
>> or drm_file.master_lookup_lock when being dereferenced. However,
>> drm_master_get is called on unprotected file_priv->master pointers in
>> vmw_surface_define_ioctl and vmw_gb_surface_define_internal.
>>
>> This is fixed by replacing drm_master_get with drm_file_get_master.
>>
>> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> 
> Reviewed-by: Zack Rusin <zackr@vmware.com>
> 
> Thanks for taking the time to fix this. Apart from the clear logic 
> error, do you happen to know under what circumstances would this be hit? 
> We have someone looking at writing some vmwgfx specific igt tests and I 
> was wondering if I could add this to the list.
> 
> z

Hi Zack,

Thanks for the review.

For some context, the use-after-free happens when there's a race between 
accessing the value of drm_file.master, and a call to 
drm_setmaster_ioctl. If drm_file is not the creator of master, then the 
ioctl allocates a new master for drm_file and puts the old master.

Thus for example, the old value of drm_file.master could be freed in 
between getting the value of file_priv->master, and the call to 
drm_master_get.

I'm not entirely sure whether this scenario is a good candidate for a test?

For further reference, the issue was originally caught by Syzbot here:
https://syzkaller.appspot.com/bug?id=148d2f1dfac64af52ffd27b661981a540724f803

And from the logs it seems that the reproducer set up a race between 
DRM_IOCTL_GET_UNIQUE and DRM_IOCTL_SET_MASTER. So possibly a race 
between VMW_CREATE_SURFACE and DRM_IOCTL_SET_MASTER could trigger the 
same bug.

Best wishes,
Desmond


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-22 19:02       ` Daniel Vetter
@ 2021-07-23  7:16         ` Boqun Feng
  0 siblings, 0 replies; 18+ messages in thread
From: Boqun Feng @ 2021-07-23  7:16 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi, LKML, Peter Zijlstra, VMware Graphics,
	Zack Rusin, Dave Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, dri-devel, intel-gfx, Shuah Khan, Greg KH,
	linux-kernel-mentees

On Thu, Jul 22, 2021 at 09:02:41PM +0200, Daniel Vetter wrote:
> On Thu, Jul 22, 2021 at 6:00 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> >
> > On Thu, Jul 22, 2021 at 12:38:10PM +0200, Daniel Vetter wrote:
> > > On Thu, Jul 22, 2021 at 05:29:27PM +0800, Desmond Cheong Zhi Xi wrote:
> > > > Inside drm_is_current_master, using the outer drm_device.master_mutex
> > > > to protect reads of drm_file.master makes the function prone to creating
> > > > lock hierarchy inversions. Instead, we can use the
> > > > drm_file.master_lookup_lock that sits at the bottom of the lock
> > > > hierarchy.
> > > >
> > > > Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> > > > ---
> > > >  drivers/gpu/drm/drm_auth.c | 9 +++++----
> > > >  1 file changed, 5 insertions(+), 4 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> > > > index f00354bec3fb..9c24b8cc8e36 100644
> > > > --- a/drivers/gpu/drm/drm_auth.c
> > > > +++ b/drivers/gpu/drm/drm_auth.c
> > > > @@ -63,8 +63,9 @@
> > > >
> > > >  static bool drm_is_current_master_locked(struct drm_file *fpriv)
> > > >  {
> > > > -   lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
> > > > -
> > > > +   /* Either drm_device.master_mutex or drm_file.master_lookup_lock
> > > > +    * should be held here.
> > > > +    */
> > >
> > > Disappointing that lockdep can't check or conditions for us, a
> > > lockdep_assert_held_either would be really neat in some cases.
> > >
> >
> > The implementation is not hard but I don't understand the usage, for
> > example, if we have a global variable x, and two locks L1 and L2, and
> > the function
> >
> >         void do_something_to_x(void)
> >         {
> >                 lockdep_assert_held_either(L1, L2);
> >                 x++;
> >         }
> >
> > and two call sites:
> >
> >         void f(void)
> >         {
> >                 lock(L1);
> >                 do_something_to_x();
> >                 unlock(L1);
> >         }
> >
> >         void g(void)
> >         {
> >                 lock(L2);
> >                 do_something_to_x();
> >                 unlock(L2);
> >         }
> >
> > , wouldn't it be racy if f() and g() called by two threads at the same
> > time? Usually I would expect there exists a third synchronazition
> > mechanism (say M), which synchronizes the calls to f() and g(), and we
> > put M in the lockdep_assert_held() check inside do_something_to_x()
> > like:
> >
> >         void do_something_to_x(void)
> >         {
> >                 lockdep_assert_held_once(M);
> >                 x++;
> >         }
> >
> > But of course, M may not be a lock, so we cannot put the assert there.
> >
> > My cscope failed to find ->master_lookup_lock in -rc2 and seems it's not
> > introduced in the patchset either, could you point me the branch this
> > patchset is based on, so that I could understand this better, and maybe
> > come up with a solution? Thanks ;-)
> 
> The use case is essentially 2 nesting locks, and only the innermost is
> used to update a field. So when you only read this field, it's safe if
> either of these two locks are held. Essentially this is a read/write lock
> type of thing, except for various reasons the two locks might not be of
> the same type (like here where the write lock is a mutex, but the read
> lock is a spinlock).
> 
> It's a bit like the rcu_derefence macro where it's ok to either be in a
> rcu_read_lock() section, or holding the relevant lock that's used to
> update the value. We do _not_ have two different locks that allow writing
> to the same X.
> 
> Does that make it clearer what's the use-case here?
> 
> In an example:
> 
> void * interesting_pointer.
> 
> do_update_interesting_pointer()
> {
> 	mutex_lock(A);
> 	/* do more stuff to prepare things */
> 	spin_lock(B);
> 	interesting_pointer = new_value;
> 	spin_unlock(B);
> 	mutex_unlock(A);
> }
> 
> read_interesting_thing_locked()
> {
> 	lockdep_assert_held_either(A, B);
> 
> 	return interesting_pointer->thing;
> }
> 
> read_interesting_thing()
> {
> 	int thing;
> 	spin_lock(B);
> 	thing = interesting_pointer->thing;
> 	spin_unlock(B);
> 
> 	return B;
> }
> 
> spinlock might also be irqsafe here if this can be called from irq
> context.
> 

Make sense, so we'd better also provide lockdep_assert_held_both(), I
think, to use it at the update side, something as below:


	/*
	 * lockdep_assert_held_{both,either}().
	 * 
	 * Sometimes users can use a combination of two locks to
	 * implement a rwlock-like lock, for example, say we have
	 * locks L1 and L2, and we only allow updates when two locks
	 * both held like:
	 * 
	 * update()
	 * {
	 *	lockdep_assert_held_both(L1, L2);
	 *	x++; // update x
	 * }
	 *
	 * while for read-only accesses, either lock suffices (since
	 * holding either lock means others cannot hold both, so readers
	 * serialized with the updaters):
	 *
	 * read()
	 * {
	 * 	lockdep_assert_held_either(L1, L2);
	 *	r = x; // read x
	 * }
	 */

	#define lockdep_assert_held_both(l1, l2)	do {			\
			WARN_ON_ONCE(debug_locks &&				\
					(!lockdep_is_held(l1) ||		\
					 !lockdep_is_held(l2)));		\
	} while (0)

	#define lockdep_assert_held_either(l1, l2)	do {			\
			WARN_ON_ONCE(debug_locks &&				\
					(!lockdep_is_held(l1) &&		\
					 !lockdep_is_held(l2)));		\
	} while (0)

Still need sometime to think through this (e.g. on whether this it the
best implementation).

Regards,
Boqun

> Cheers, Daniel
> 
> > Regards,
> > Boqun
> >
> > > Adding lockdep folks, maybe they have ideas.
> > >
> > > On the patch:
> > >
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > >
> > > >     return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
> > > >  }
> > > >
> > > > @@ -82,9 +83,9 @@ bool drm_is_current_master(struct drm_file *fpriv)
> > > >  {
> > > >     bool ret;
> > > >
> > > > -   mutex_lock(&fpriv->minor->dev->master_mutex);
> > > > +   spin_lock(&fpriv->master_lookup_lock);
> > > >     ret = drm_is_current_master_locked(fpriv);
> > > > -   mutex_unlock(&fpriv->minor->dev->master_mutex);
> > > > +   spin_unlock(&fpriv->master_lookup_lock);
> > > >
> > > >     return ret;
> > > >  }
> > > > --
> > > > 2.25.1
> > > >
> > >
> > > --
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > http://blog.ffwll.ch
> 
> 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-22 10:38   ` Daniel Vetter
  2021-07-22 15:04     ` Boqun Feng
@ 2021-07-27 14:37     ` Peter Zijlstra
  2021-07-29  7:00       ` Daniel Vetter
  1 sibling, 1 reply; 18+ messages in thread
From: Peter Zijlstra @ 2021-07-27 14:37 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi, Boqun Feng, LKML,
	linux-graphics-maintainer, zackr, airlied, maarten.lankhorst,
	mripard, tzimmermann, dri-devel, intel-gfx, skhan, gregkh,
	linux-kernel-mentees

On Thu, Jul 22, 2021 at 12:38:10PM +0200, Daniel Vetter wrote:
> On Thu, Jul 22, 2021 at 05:29:27PM +0800, Desmond Cheong Zhi Xi wrote:
> > Inside drm_is_current_master, using the outer drm_device.master_mutex
> > to protect reads of drm_file.master makes the function prone to creating
> > lock hierarchy inversions. Instead, we can use the
> > drm_file.master_lookup_lock that sits at the bottom of the lock
> > hierarchy.
> > 
> > Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> > ---
> >  drivers/gpu/drm/drm_auth.c | 9 +++++----
> >  1 file changed, 5 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> > index f00354bec3fb..9c24b8cc8e36 100644
> > --- a/drivers/gpu/drm/drm_auth.c
> > +++ b/drivers/gpu/drm/drm_auth.c
> > @@ -63,8 +63,9 @@
> >  
> >  static bool drm_is_current_master_locked(struct drm_file *fpriv)
> >  {
> > -	lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
> > -
> > +	/* Either drm_device.master_mutex or drm_file.master_lookup_lock
> > +	 * should be held here.
> > +	 */
> 
> Disappointing that lockdep can't check or conditions for us, a
> lockdep_assert_held_either would be really neat in some cases.
> 
> Adding lockdep folks, maybe they have ideas.

#ifdef CONFIG_LOCKDEP
	WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&drm_device.master_mutex) ||
				      lockdep_is_held(&drm_file.master_lookup_lock)));
#endif

doesn't exactly roll off the tongue, but should do as you want I
suppose.

Would something like:

#define lockdep_assert(cond)	WARN_ON_ONCE(debug_locks && !(cond))

Such that we can write:

	lockdep_assert(lockdep_is_held(&drm_device.master_mutex) ||
		       lockdep_is_held(&drm_file.master_lookup_lock));

make it better ?

---
Subject: locking/lockdep: Provide lockdep_assert{,_once}() helpers

Extract lockdep_assert{,_once}() helpers to more easily write composite
assertions like, for example:

	lockdep_assert(lockdep_is_held(&drm_device.master_mutex) ||
		       lockdep_is_held(&drm_file.master_lookup_lock));

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 5cf387813754..0da67341c1fb 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -306,31 +306,29 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
 
 #define lockdep_depth(tsk)	(debug_locks ? (tsk)->lockdep_depth : 0)
 
-#define lockdep_assert_held(l)	do {					\
-		WARN_ON(debug_locks &&					\
-			lockdep_is_held(l) == LOCK_STATE_NOT_HELD);	\
-	} while (0)
+#define lockdep_assert(cond)		\
+	do { WARN_ON(debug_locks && !(cond)); } while (0)
 
-#define lockdep_assert_not_held(l)	do {				\
-		WARN_ON(debug_locks &&					\
-			lockdep_is_held(l) == LOCK_STATE_HELD);		\
-	} while (0)
+#define lockdep_assert_once(cond)	\
+	do { WARN_ON_ONCE(debug_locks && !(cond)); } while (0)
 
-#define lockdep_assert_held_write(l)	do {			\
-		WARN_ON(debug_locks && !lockdep_is_held_type(l, 0));	\
-	} while (0)
+#define lockdep_assert_held(l)		\
+	lockdep_assert(lockdep_is_held(l) != LOCK_STAT_NOT_HELD)
 
-#define lockdep_assert_held_read(l)	do {				\
-		WARN_ON(debug_locks && !lockdep_is_held_type(l, 1));	\
-	} while (0)
+#define lockdep_assert_not_held(l)	\
+	lockdep_assert(lockdep_is_held(l) != LOCK_STATE_HELD)
 
-#define lockdep_assert_held_once(l)	do {				\
-		WARN_ON_ONCE(debug_locks && !lockdep_is_held(l));	\
-	} while (0)
+#define lockdep_assert_held_write(l)	\
+	lockdep_assert(lockdep_is_held_type(l, 0))
 
-#define lockdep_assert_none_held_once()	do {				\
-		WARN_ON_ONCE(debug_locks && current->lockdep_depth);	\
-	} while (0)
+#define lockdep_assert_held_read(l)	\
+	lockdep_assert(lockdep_is_held_type(l, 1))
+
+#define lockdep_assert_held_once(l)		\
+	lockdep_assert_once(lockdep_is_held(l) != LOCK_STAT_NOT_HELD)
+
+#define lockdep_assert_none_held_once()		\
+	lockdep_assert_once(!current->lockdep_depth)
 
 #define lockdep_recursing(tsk)	((tsk)->lockdep_recursion)
 
@@ -407,6 +405,9 @@ extern int lock_is_held(const void *);
 extern int lockdep_is_held(const void *);
 #define lockdep_is_held_type(l, r)		(1)
 
+#define lockdep_assert(c)			do { } while (0)
+#define lockdep_assert_once(c)			do { } while (0)
+
 #define lockdep_assert_held(l)			do { (void)(l); } while (0)
 #define lockdep_assert_not_held(l)		do { (void)(l); } while (0)
 #define lockdep_assert_held_write(l)		do { (void)(l); } while (0)


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-27 14:37     ` Peter Zijlstra
@ 2021-07-29  7:00       ` Daniel Vetter
  2021-07-29 14:32         ` Desmond Cheong Zhi Xi
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Vetter @ 2021-07-29  7:00 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Desmond Cheong Zhi Xi, Boqun Feng, LKML,
	linux-graphics-maintainer, zackr, airlied, maarten.lankhorst,
	mripard, tzimmermann, dri-devel, intel-gfx, skhan, gregkh,
	linux-kernel-mentees

On Tue, Jul 27, 2021 at 04:37:22PM +0200, Peter Zijlstra wrote:
> On Thu, Jul 22, 2021 at 12:38:10PM +0200, Daniel Vetter wrote:
> > On Thu, Jul 22, 2021 at 05:29:27PM +0800, Desmond Cheong Zhi Xi wrote:
> > > Inside drm_is_current_master, using the outer drm_device.master_mutex
> > > to protect reads of drm_file.master makes the function prone to creating
> > > lock hierarchy inversions. Instead, we can use the
> > > drm_file.master_lookup_lock that sits at the bottom of the lock
> > > hierarchy.
> > > 
> > > Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
> > > ---
> > >  drivers/gpu/drm/drm_auth.c | 9 +++++----
> > >  1 file changed, 5 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> > > index f00354bec3fb..9c24b8cc8e36 100644
> > > --- a/drivers/gpu/drm/drm_auth.c
> > > +++ b/drivers/gpu/drm/drm_auth.c
> > > @@ -63,8 +63,9 @@
> > >  
> > >  static bool drm_is_current_master_locked(struct drm_file *fpriv)
> > >  {
> > > -	lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
> > > -
> > > +	/* Either drm_device.master_mutex or drm_file.master_lookup_lock
> > > +	 * should be held here.
> > > +	 */
> > 
> > Disappointing that lockdep can't check or conditions for us, a
> > lockdep_assert_held_either would be really neat in some cases.
> > 
> > Adding lockdep folks, maybe they have ideas.
> 
> #ifdef CONFIG_LOCKDEP
> 	WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&drm_device.master_mutex) ||
> 				      lockdep_is_held(&drm_file.master_lookup_lock)));
> #endif
> 
> doesn't exactly roll off the tongue, but should do as you want I
> suppose.
> 
> Would something like:
> 
> #define lockdep_assert(cond)	WARN_ON_ONCE(debug_locks && !(cond))
> 
> Such that we can write:
> 
> 	lockdep_assert(lockdep_is_held(&drm_device.master_mutex) ||
> 		       lockdep_is_held(&drm_file.master_lookup_lock));
> 
> make it better ?

Yeah I think that's pretty tidy and flexible.

Desmond, can you pls give this a shot with Peter's patch below?
-Daniel
> 
> ---
> Subject: locking/lockdep: Provide lockdep_assert{,_once}() helpers
> 
> Extract lockdep_assert{,_once}() helpers to more easily write composite
> assertions like, for example:
> 
> 	lockdep_assert(lockdep_is_held(&drm_device.master_mutex) ||
> 		       lockdep_is_held(&drm_file.master_lookup_lock));
> 
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> ---
> diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
> index 5cf387813754..0da67341c1fb 100644
> --- a/include/linux/lockdep.h
> +++ b/include/linux/lockdep.h
> @@ -306,31 +306,29 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
>  
>  #define lockdep_depth(tsk)	(debug_locks ? (tsk)->lockdep_depth : 0)
>  
> -#define lockdep_assert_held(l)	do {					\
> -		WARN_ON(debug_locks &&					\
> -			lockdep_is_held(l) == LOCK_STATE_NOT_HELD);	\
> -	} while (0)
> +#define lockdep_assert(cond)		\
> +	do { WARN_ON(debug_locks && !(cond)); } while (0)
>  
> -#define lockdep_assert_not_held(l)	do {				\
> -		WARN_ON(debug_locks &&					\
> -			lockdep_is_held(l) == LOCK_STATE_HELD);		\
> -	} while (0)
> +#define lockdep_assert_once(cond)	\
> +	do { WARN_ON_ONCE(debug_locks && !(cond)); } while (0)
>  
> -#define lockdep_assert_held_write(l)	do {			\
> -		WARN_ON(debug_locks && !lockdep_is_held_type(l, 0));	\
> -	} while (0)
> +#define lockdep_assert_held(l)		\
> +	lockdep_assert(lockdep_is_held(l) != LOCK_STAT_NOT_HELD)
>  
> -#define lockdep_assert_held_read(l)	do {				\
> -		WARN_ON(debug_locks && !lockdep_is_held_type(l, 1));	\
> -	} while (0)
> +#define lockdep_assert_not_held(l)	\
> +	lockdep_assert(lockdep_is_held(l) != LOCK_STATE_HELD)
>  
> -#define lockdep_assert_held_once(l)	do {				\
> -		WARN_ON_ONCE(debug_locks && !lockdep_is_held(l));	\
> -	} while (0)
> +#define lockdep_assert_held_write(l)	\
> +	lockdep_assert(lockdep_is_held_type(l, 0))
>  
> -#define lockdep_assert_none_held_once()	do {				\
> -		WARN_ON_ONCE(debug_locks && current->lockdep_depth);	\
> -	} while (0)
> +#define lockdep_assert_held_read(l)	\
> +	lockdep_assert(lockdep_is_held_type(l, 1))
> +
> +#define lockdep_assert_held_once(l)		\
> +	lockdep_assert_once(lockdep_is_held(l) != LOCK_STAT_NOT_HELD)
> +
> +#define lockdep_assert_none_held_once()		\
> +	lockdep_assert_once(!current->lockdep_depth)
>  
>  #define lockdep_recursing(tsk)	((tsk)->lockdep_recursion)
>  
> @@ -407,6 +405,9 @@ extern int lock_is_held(const void *);
>  extern int lockdep_is_held(const void *);
>  #define lockdep_is_held_type(l, r)		(1)
>  
> +#define lockdep_assert(c)			do { } while (0)
> +#define lockdep_assert_once(c)			do { } while (0)
> +
>  #define lockdep_assert_held(l)			do { (void)(l); } while (0)
>  #define lockdep_assert_not_held(l)		do { (void)(l); } while (0)
>  #define lockdep_assert_held_write(l)		do { (void)(l); } while (0)
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-29  7:00       ` Daniel Vetter
@ 2021-07-29 14:32         ` Desmond Cheong Zhi Xi
  2021-07-29 14:45           ` Peter Zijlstra
  0 siblings, 1 reply; 18+ messages in thread
From: Desmond Cheong Zhi Xi @ 2021-07-29 14:32 UTC (permalink / raw)
  To: Daniel Vetter, Peter Zijlstra, Boqun Feng, LKML,
	linux-graphics-maintainer, zackr, airlied, maarten.lankhorst,
	mripard, tzimmermann
  Cc: dri-devel, intel-gfx, skhan, gregkh, linux-kernel-mentees

On 29/7/21 3:00 pm, Daniel Vetter wrote:
> On Tue, Jul 27, 2021 at 04:37:22PM +0200, Peter Zijlstra wrote:
>> On Thu, Jul 22, 2021 at 12:38:10PM +0200, Daniel Vetter wrote:
>>> On Thu, Jul 22, 2021 at 05:29:27PM +0800, Desmond Cheong Zhi Xi wrote:
>>>> Inside drm_is_current_master, using the outer drm_device.master_mutex
>>>> to protect reads of drm_file.master makes the function prone to creating
>>>> lock hierarchy inversions. Instead, we can use the
>>>> drm_file.master_lookup_lock that sits at the bottom of the lock
>>>> hierarchy.
>>>>
>>>> Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>> Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
>>>> ---
>>>>   drivers/gpu/drm/drm_auth.c | 9 +++++----
>>>>   1 file changed, 5 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
>>>> index f00354bec3fb..9c24b8cc8e36 100644
>>>> --- a/drivers/gpu/drm/drm_auth.c
>>>> +++ b/drivers/gpu/drm/drm_auth.c
>>>> @@ -63,8 +63,9 @@
>>>>   
>>>>   static bool drm_is_current_master_locked(struct drm_file *fpriv)
>>>>   {
>>>> -	lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
>>>> -
>>>> +	/* Either drm_device.master_mutex or drm_file.master_lookup_lock
>>>> +	 * should be held here.
>>>> +	 */
>>>
>>> Disappointing that lockdep can't check or conditions for us, a
>>> lockdep_assert_held_either would be really neat in some cases.
>>>
>>> Adding lockdep folks, maybe they have ideas.
>>
>> #ifdef CONFIG_LOCKDEP
>> 	WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&drm_device.master_mutex) ||
>> 				      lockdep_is_held(&drm_file.master_lookup_lock)));
>> #endif
>>
>> doesn't exactly roll off the tongue, but should do as you want I
>> suppose.
>>
>> Would something like:
>>
>> #define lockdep_assert(cond)	WARN_ON_ONCE(debug_locks && !(cond))
>>
>> Such that we can write:
>>
>> 	lockdep_assert(lockdep_is_held(&drm_device.master_mutex) ||
>> 		       lockdep_is_held(&drm_file.master_lookup_lock));
>>
>> make it better ?
> 
> Yeah I think that's pretty tidy and flexible.
> 
> Desmond, can you pls give this a shot with Peter's patch below?
> -Daniel

Sounds good, will do. Thanks for the patch, Peter.

Just going to make a small edit:
s/LOCK_STAT_NOT_HELD/LOCK_STATE_NOT_HELD/

Best wishes,
Desmond

>>
>> ---
>> Subject: locking/lockdep: Provide lockdep_assert{,_once}() helpers
>>
>> Extract lockdep_assert{,_once}() helpers to more easily write composite
>> assertions like, for example:
>>
>> 	lockdep_assert(lockdep_is_held(&drm_device.master_mutex) ||
>> 		       lockdep_is_held(&drm_file.master_lookup_lock));
>>
>> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
>> ---
>> diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
>> index 5cf387813754..0da67341c1fb 100644
>> --- a/include/linux/lockdep.h
>> +++ b/include/linux/lockdep.h
>> @@ -306,31 +306,29 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
>>   
>>   #define lockdep_depth(tsk)	(debug_locks ? (tsk)->lockdep_depth : 0)
>>   
>> -#define lockdep_assert_held(l)	do {					\
>> -		WARN_ON(debug_locks &&					\
>> -			lockdep_is_held(l) == LOCK_STATE_NOT_HELD);	\
>> -	} while (0)
>> +#define lockdep_assert(cond)		\
>> +	do { WARN_ON(debug_locks && !(cond)); } while (0)
>>   
>> -#define lockdep_assert_not_held(l)	do {				\
>> -		WARN_ON(debug_locks &&					\
>> -			lockdep_is_held(l) == LOCK_STATE_HELD);		\
>> -	} while (0)
>> +#define lockdep_assert_once(cond)	\
>> +	do { WARN_ON_ONCE(debug_locks && !(cond)); } while (0)
>>   
>> -#define lockdep_assert_held_write(l)	do {			\
>> -		WARN_ON(debug_locks && !lockdep_is_held_type(l, 0));	\
>> -	} while (0)
>> +#define lockdep_assert_held(l)		\
>> +	lockdep_assert(lockdep_is_held(l) != LOCK_STAT_NOT_HELD)
>>   
>> -#define lockdep_assert_held_read(l)	do {				\
>> -		WARN_ON(debug_locks && !lockdep_is_held_type(l, 1));	\
>> -	} while (0)
>> +#define lockdep_assert_not_held(l)	\
>> +	lockdep_assert(lockdep_is_held(l) != LOCK_STATE_HELD)
>>   
>> -#define lockdep_assert_held_once(l)	do {				\
>> -		WARN_ON_ONCE(debug_locks && !lockdep_is_held(l));	\
>> -	} while (0)
>> +#define lockdep_assert_held_write(l)	\
>> +	lockdep_assert(lockdep_is_held_type(l, 0))
>>   
>> -#define lockdep_assert_none_held_once()	do {				\
>> -		WARN_ON_ONCE(debug_locks && current->lockdep_depth);	\
>> -	} while (0)
>> +#define lockdep_assert_held_read(l)	\
>> +	lockdep_assert(lockdep_is_held_type(l, 1))
>> +
>> +#define lockdep_assert_held_once(l)		\
>> +	lockdep_assert_once(lockdep_is_held(l) != LOCK_STAT_NOT_HELD)
>> +
>> +#define lockdep_assert_none_held_once()		\
>> +	lockdep_assert_once(!current->lockdep_depth)
>>   
>>   #define lockdep_recursing(tsk)	((tsk)->lockdep_recursion)
>>   
>> @@ -407,6 +405,9 @@ extern int lock_is_held(const void *);
>>   extern int lockdep_is_held(const void *);
>>   #define lockdep_is_held_type(l, r)		(1)
>>   
>> +#define lockdep_assert(c)			do { } while (0)
>> +#define lockdep_assert_once(c)			do { } while (0)
>> +
>>   #define lockdep_assert_held(l)			do { (void)(l); } while (0)
>>   #define lockdep_assert_not_held(l)		do { (void)(l); } while (0)
>>   #define lockdep_assert_held_write(l)		do { (void)(l); } while (0)
>>
> 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/3] drm: use the lookup lock in drm_is_current_master
  2021-07-29 14:32         ` Desmond Cheong Zhi Xi
@ 2021-07-29 14:45           ` Peter Zijlstra
  0 siblings, 0 replies; 18+ messages in thread
From: Peter Zijlstra @ 2021-07-29 14:45 UTC (permalink / raw)
  To: Desmond Cheong Zhi Xi
  Cc: Daniel Vetter, Boqun Feng, LKML, linux-graphics-maintainer,
	zackr, airlied, maarten.lankhorst, mripard, tzimmermann,
	dri-devel, intel-gfx, skhan, gregkh, linux-kernel-mentees

On Thu, Jul 29, 2021 at 10:32:13PM +0800, Desmond Cheong Zhi Xi wrote:
> Sounds good, will do. Thanks for the patch, Peter.
> 
> Just going to make a small edit:
> s/LOCK_STAT_NOT_HELD/LOCK_STATE_NOT_HELD/

Bah, I knew I should've compile tested it :-), Thanks!

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2021-07-29 14:47 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-22  9:29 [PATCH 0/3] drm, drm/vmwgfx: fixes and updates related to drm_master Desmond Cheong Zhi Xi
2021-07-22  9:29 ` [PATCH 1/3] drm: use the lookup lock in drm_is_current_master Desmond Cheong Zhi Xi
2021-07-22 10:38   ` Daniel Vetter
2021-07-22 15:04     ` Boqun Feng
2021-07-22 19:02       ` Daniel Vetter
2021-07-23  7:16         ` Boqun Feng
2021-07-27 14:37     ` Peter Zijlstra
2021-07-29  7:00       ` Daniel Vetter
2021-07-29 14:32         ` Desmond Cheong Zhi Xi
2021-07-29 14:45           ` Peter Zijlstra
2021-07-22  9:29 ` [PATCH 2/3] drm: clarify lifetime/locking for drm_master's lease fields Desmond Cheong Zhi Xi
2021-07-22 10:35   ` Daniel Vetter
2021-07-22 13:02     ` Desmond Cheong Zhi Xi
2021-07-22 14:17       ` Daniel Vetter
2021-07-22  9:29 ` [PATCH 3/3] drm/vmwgfx: fix potential UAF in vmwgfx_surface.c Desmond Cheong Zhi Xi
2021-07-22 10:39   ` Daniel Vetter
2021-07-22 19:17   ` Zack Rusin
2021-07-23  6:44     ` Desmond Cheong Zhi Xi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).