lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sat,  1 Apr 2017 10:08:40 -0700
From:   Keith Packard <keithp@...thp.com>
To:     linux-kernel@...r.kernel.org, Dave Airlie <airlied@...hat.com>
Cc:     Keith Packard <keithp@...thp.com>, dri-devel@...ts.freedesktop.org
Subject: [PATCH 3/4] drm: Check mode object lease status in all master ioctl paths

Attempts to modify un-leased objects are rejected with an error.
Information returned about unleased objects is modified to make them
appear unusable and/or disconnected.

Signed-off-by: Keith Packard <keithp@...thp.com>
---
 drivers/gpu/drm/drm_atomic.c      |  3 +++
 drivers/gpu/drm/drm_auth.c        |  2 +-
 drivers/gpu/drm/drm_color_mgmt.c  |  3 +++
 drivers/gpu/drm/drm_connector.c   | 52 ++++++++++++++++++++++++++-------------
 drivers/gpu/drm/drm_crtc.c        | 15 ++++++++---
 drivers/gpu/drm/drm_encoder.c     | 18 +++++++++++---
 drivers/gpu/drm/drm_mode_object.c |  3 +++
 drivers/gpu/drm/drm_plane.c       | 36 +++++++++++++++++++++++----
 include/drm/drm_lease.h           |  4 +++
 include/drm/drm_mode_object.h     |  1 +
 10 files changed, 108 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index fdfb1ec17e66..a3cb95f7f1c1 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -2134,6 +2134,9 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
 			goto out;
 		}
 
+		if ((ret = drm_lease_check(file_priv->master, obj->id)) < 0)
+			goto out;
+
 		if (!obj->properties) {
 			drm_mode_object_unreference(obj);
 			ret = -ENOENT;
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 1db4f63860d1..44c99d12f4c1 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -303,7 +303,7 @@ void drm_master_release(struct drm_file *file_priv)
  */
 bool drm_is_current_master(struct drm_file *fpriv)
 {
-	return fpriv->is_master && fpriv->master == fpriv->minor->dev->master;
+	return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
 }
 EXPORT_SYMBOL(drm_is_current_master);
 
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c
index 6543ebde501a..f8d7a499cf95 100644
--- a/drivers/gpu/drm/drm_color_mgmt.c
+++ b/drivers/gpu/drm/drm_color_mgmt.c
@@ -206,6 +206,9 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 		goto out;
 	}
 
+	if ((ret = drm_lease_check(file_priv->master, crtc->base.id)) < 0)
+		goto out;
+
 	if (crtc->funcs->gamma_set == NULL) {
 		ret = -ENOSYS;
 		goto out;
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 7a7019ac9388..a95db57dd966 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1079,6 +1079,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 	struct drm_mode_modeinfo u_mode;
 	struct drm_mode_modeinfo __user *mode_ptr;
 	uint32_t __user *encoder_ptr;
+	bool leased;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -1093,9 +1094,16 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 		goto out_unlock;
 	}
 
-	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
-		if (connector->encoder_ids[i] != 0)
-			encoders_count++;
+	leased = drm_lease_check(file_priv->master, connector->base.id) == 0;
+
+	DRM_DEBUG_LEASE("connector %d leased %s\n", connector->base.id, leased ? "true" : "false");
+
+	if (leased) {
+		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
+			if (connector->encoder_ids[i] != 0 &&
+			    drm_lease_check(file_priv->master, connector->encoder_ids[i]) == 0)
+				encoders_count++;
+	}
 
 	if (out_resp->count_modes == 0) {
 		connector->funcs->fill_modes(connector,
@@ -1104,21 +1112,29 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 	}
 
 	/* delayed so we get modes regardless of pre-fill_modes state */
-	list_for_each_entry(mode, &connector->modes, head)
-		if (drm_mode_expose_to_userspace(mode, file_priv))
-			mode_count++;
+	if (leased)
+		list_for_each_entry(mode, &connector->modes, head)
+			if (drm_mode_expose_to_userspace(mode, file_priv))
+				mode_count++;
 
 	out_resp->connector_id = connector->base.id;
 	out_resp->connector_type = connector->connector_type;
 	out_resp->connector_type_id = connector->connector_type_id;
-	out_resp->mm_width = connector->display_info.width_mm;
-	out_resp->mm_height = connector->display_info.height_mm;
-	out_resp->subpixel = connector->display_info.subpixel_order;
-	out_resp->connection = connector->status;
+	if (leased) {
+		out_resp->mm_width = connector->display_info.width_mm;
+		out_resp->mm_height = connector->display_info.height_mm;
+		out_resp->subpixel = connector->display_info.subpixel_order;
+		out_resp->connection = connector->status;
+	} else {
+		out_resp->mm_width = 0;
+		out_resp->mm_height = 0;
+		out_resp->subpixel = 0;
+		out_resp->connection = connector_status_disconnected;
+	}
 
 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 	encoder = drm_connector_get_encoder(connector);
-	if (encoder)
+	if (encoder && leased)
 		out_resp->encoder_id = encoder->base.id;
 	else
 		out_resp->encoder_id = 0;
@@ -1145,12 +1161,14 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 	}
 	out_resp->count_modes = mode_count;
 
-	ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic,
-			(uint32_t __user *)(unsigned long)(out_resp->props_ptr),
-			(uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
-			&out_resp->count_props);
-	if (ret)
-		goto out;
+	if (leased) {
+		ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic,
+						     (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
+						     (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
+						     &out_resp->count_props);
+		if (ret)
+			goto out;
+	}
 
 	if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
 		copied = 0;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e75f62cd8a65..95026ca74568 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -347,6 +347,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
 {
 	struct drm_mode_crtc *crtc_resp = data;
 	struct drm_crtc *crtc;
+	bool leased;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -355,9 +356,13 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	if (!crtc)
 		return -ENOENT;
 
+	leased = drm_lease_check(file_priv->master, crtc->base.id) == 0;
+
+	DRM_DEBUG_LEASE("crtc %d leased %s\n", crtc->base.id, leased ? "true" : "false");
+
 	drm_modeset_lock_crtc(crtc, crtc->primary);
 	crtc_resp->gamma_size = crtc->gamma_size;
-	if (crtc->primary->fb)
+	if (crtc->primary->fb && leased)
 		crtc_resp->fb_id = crtc->primary->fb->base.id;
 	else
 		crtc_resp->fb_id = 0;
@@ -365,7 +370,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	if (crtc->state) {
 		crtc_resp->x = crtc->primary->state->src_x >> 16;
 		crtc_resp->y = crtc->primary->state->src_y >> 16;
-		if (crtc->state->enable) {
+		if (crtc->state->enable && leased) {
 			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
 			crtc_resp->mode_valid = 1;
 
@@ -375,7 +380,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	} else {
 		crtc_resp->x = crtc->x;
 		crtc_resp->y = crtc->y;
-		if (crtc->enabled) {
+		if (crtc->enabled && leased) {
 			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
 			crtc_resp->mode_valid = 1;
 
@@ -529,6 +534,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	}
 	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
 
+	if ((ret = drm_lease_check(file_priv->master, crtc->base.id)) < 0) {
+		DRM_DEBUG_KMS("CRTC lease not held\n");
+		goto out;
+	}
 	if (crtc_req->mode_valid) {
 		/* If we have a mode we need a framebuffer. */
 		/* If we pass -1, set the mode with the currently bound fb */
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 992879f15f23..24d03e13f522 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -201,6 +201,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 	struct drm_mode_get_encoder *enc_resp = data;
 	struct drm_encoder *encoder;
 	struct drm_crtc *crtc;
+	bool leased;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -209,9 +210,13 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 	if (!encoder)
 		return -ENOENT;
 
+	leased = drm_lease_check(file_priv->master, encoder->base.id) == 0;
+
+	DRM_DEBUG_LEASE("encoder %d leased %s\n", encoder->base.id, leased ? "true" : "false");
+
 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 	crtc = drm_encoder_get_crtc(encoder);
-	if (crtc)
+	if (crtc && leased)
 		enc_resp->crtc_id = crtc->base.id;
 	else
 		enc_resp->crtc_id = 0;
@@ -219,8 +224,15 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 
 	enc_resp->encoder_type = encoder->encoder_type;
 	enc_resp->encoder_id = encoder->base.id;
-	enc_resp->possible_crtcs = encoder->possible_crtcs;
-	enc_resp->possible_clones = encoder->possible_clones;
+	if (leased) {
+		enc_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv->master,
+								  encoder->possible_crtcs);
+		enc_resp->possible_clones = drm_lease_filter_encoders(file_priv->master,
+								      encoder->possible_clones);
+	} else {
+		enc_resp->possible_crtcs = 0;
+		enc_resp->possible_clones = 0;
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index 9f17085b1fdd..9f8559d82a17 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -404,6 +404,9 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 		goto out;
 	}
 
+	if ((ret = drm_lease_check(file_priv->master, arg->obj_id)) != 0)
+		goto out;
+
 	if (!arg_obj->properties)
 		goto out_unref;
 
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 62b98f386fd1..df811869c1dd 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -383,6 +383,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	struct drm_mode_get_plane *plane_resp = data;
 	struct drm_plane *plane;
 	uint32_t __user *format_ptr;
+	bool leased;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -391,27 +392,34 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	if (!plane)
 		return -ENOENT;
 
+	leased = drm_lease_check(file_priv->master, plane->base.id) == 0;
+
 	drm_modeset_lock(&plane->mutex, NULL);
-	if (plane->crtc)
+	if (plane->crtc && leased)
 		plane_resp->crtc_id = plane->crtc->base.id;
 	else
 		plane_resp->crtc_id = 0;
 
-	if (plane->fb)
+	if (plane->fb && leased)
 		plane_resp->fb_id = plane->fb->base.id;
 	else
 		plane_resp->fb_id = 0;
 	drm_modeset_unlock(&plane->mutex);
 
 	plane_resp->plane_id = plane->base.id;
-	plane_resp->possible_crtcs = plane->possible_crtcs;
+	if (leased)
+		plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv->master,
+								    plane->possible_crtcs);
+	else
+		plane_resp->possible_crtcs = 0;
+
 	plane_resp->gamma_size = 0;
 
 	/*
 	 * This ioctl is called twice, once to determine how much space is
 	 * needed, and the 2nd time to fill it.
 	 */
-	if (plane->format_count &&
+	if (plane->format_count && leased &&
 	    (plane_resp->count_format_types >= plane->format_count)) {
 		format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
 		if (copy_to_user(format_ptr,
@@ -420,7 +428,10 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 			return -EFAULT;
 		}
 	}
-	plane_resp->count_format_types = plane->format_count;
+	if (leased)
+		plane_resp->count_format_types = plane->format_count;
+	else
+		plane_resp->count_format_types = 0;
 
 	return 0;
 }
@@ -551,6 +562,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	struct drm_plane *plane;
 	struct drm_crtc *crtc = NULL;
 	struct drm_framebuffer *fb = NULL;
+	int ret;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -566,6 +578,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 		return -ENOENT;
 	}
 
+	if ((ret = drm_lease_check(file_priv->master, plane->base.id)) < 0) {
+		DRM_DEBUG_KMS("Plane lease not held: %d error %d\n",
+			      plane->base.id, ret);
+		return ret;
+	}
+
 	if (plane_req->fb_id) {
 		fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
 		if (!fb) {
@@ -687,6 +705,11 @@ static int drm_mode_cursor_common(struct drm_device *dev,
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
 		return -ENOENT;
 	}
+	if ((ret = drm_lease_check(file_priv->master, crtc->base.id)) < 0) {
+		DRM_DEBUG_KMS("CRTC lease not held %d error %d\n",
+			      crtc->base.id, ret);
+		goto out;
+	}
 
 	/*
 	 * If this crtc has a universal cursor plane, call that plane's update
@@ -785,6 +808,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if (!crtc)
 		return -ENOENT;
 
+	if ((ret = drm_lease_check(file_priv->master, crtc->base.id)) < 0)
+		return ret;
+
 	if (crtc->funcs->page_flip_target) {
 		u32 current_vblank;
 		int r;
diff --git a/include/drm/drm_lease.h b/include/drm/drm_lease.h
index e02adf3e42fd..8f91fc4226e3 100644
--- a/include/drm/drm_lease.h
+++ b/include/drm/drm_lease.h
@@ -48,4 +48,8 @@ static inline int drm_lease_check(struct drm_master *master, int id) {
 	return 0;
 }
 
+uint32_t drm_lease_filter_crtcs(struct drm_master *master, uint32_t crtcs);
+
+uint32_t drm_lease_filter_encoders(struct drm_master *master, uint32_t encoders);
+
 #endif /* _DRM_LEASE_H_ */
diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h
index 43460b21d112..07830182598b 100644
--- a/include/drm/drm_mode_object.h
+++ b/include/drm/drm_mode_object.h
@@ -24,6 +24,7 @@
 #define __DRM_MODESET_H__
 
 #include <linux/kref.h>
+#include <drm/drm_lease.h>
 struct drm_object_properties;
 struct drm_property;
 struct drm_device;
-- 
2.11.0

Powered by blists - more mailing lists