On Mon, Jun 21, 2021 at 4:25 PM Daniel Vetter daniel@ffwll.ch wrote:
On Sun, Jun 20, 2021 at 07:03:26PM +0800, Desmond Cheong Zhi Xi wrote:
While checking the master status of the DRM file in drm_is_current_master(), the device's master mutex should be held. Without the mutex, the pointer fpriv->master may be freed concurrently by another process calling drm_setmaster_ioctl(). This could lead to use-after-free errors when the pointer is subsequently dereferenced in drm_lease_owner().
The callers of drm_is_current_master() from drm_auth.c hold the device's master mutex, but external callers do not. Hence, we implement drm_is_current_master_locked() to be used within drm_auth.c, and modify drm_is_current_master() to grab the device's master mutex before checking the master status.
Reported-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Desmond Cheong Zhi Xi desmondcheongzx@gmail.com Reviewed-by: Emil Velikov emil.l.velikov@gmail.com
Merged to drm-misc-fixes, thanks for your patch.
Cc'ed you on the revert, but this blew up in intel-gfx CI. Please cc: intel-gfx@lists.freedesktop.org for the next round so CI can pick it up (it doesn't read dri-devel here).
I'm not exactly sure how we can best fix that issue in general, maybe there's more. But for the specific lockdep splat around getconnector I think just pulling the call to drm_is_current_master out from the connector mutex should avoid the issue (just store it locally and then still have the if() condition under the connector mutex ofc). -Daniel
-Daniel
drivers/gpu/drm/drm_auth.c | 51 ++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 232abbba3686..86d4b72e95cb 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -61,6 +61,35 @@
- trusted clients.
*/
+static bool drm_is_current_master_locked(struct drm_file *fpriv) +{
lockdep_assert_held_once(&fpriv->master->dev->master_mutex);
return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
+}
+/**
- drm_is_current_master - checks whether @priv is the current master
- @fpriv: DRM file private
- Checks whether @fpriv is current master on its device. This decides whether a
- client is allowed to run DRM_MASTER IOCTLs.
- Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
- the current master is assumed to own the non-shareable display hardware.
- */
+bool drm_is_current_master(struct drm_file *fpriv) +{
bool ret;
mutex_lock(&fpriv->master->dev->master_mutex);
ret = drm_is_current_master_locked(fpriv);
mutex_unlock(&fpriv->master->dev->master_mutex);
return ret;
+} +EXPORT_SYMBOL(drm_is_current_master);
int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_auth *auth = data; @@ -223,7 +252,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, if (ret) goto out_unlock;
if (drm_is_current_master(file_priv))
if (drm_is_current_master_locked(file_priv)) goto out_unlock; if (dev->master) {
@@ -272,7 +301,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, if (ret) goto out_unlock;
if (!drm_is_current_master(file_priv)) {
if (!drm_is_current_master_locked(file_priv)) { ret = -EINVAL; goto out_unlock; }
@@ -321,7 +350,7 @@ void drm_master_release(struct drm_file *file_priv) if (file_priv->magic) idr_remove(&file_priv->master->magic_map, file_priv->magic);
if (!drm_is_current_master(file_priv))
if (!drm_is_current_master_locked(file_priv)) goto out; drm_legacy_lock_master_cleanup(dev, master);
@@ -342,22 +371,6 @@ void drm_master_release(struct drm_file *file_priv) mutex_unlock(&dev->master_mutex); }
-/**
- drm_is_current_master - checks whether @priv is the current master
- @fpriv: DRM file private
- Checks whether @fpriv is current master on its device. This decides whether a
- client is allowed to run DRM_MASTER IOCTLs.
- Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
- the current master is assumed to own the non-shareable display hardware.
- */
-bool drm_is_current_master(struct drm_file *fpriv) -{
return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
-} -EXPORT_SYMBOL(drm_is_current_master);
/**
- drm_master_get - reference a master pointer
- @master: &struct drm_master
-- 2.25.1
-- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch