summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2017-11-08 12:53:11 +0200
committerMarius Vlad <marius-cristian.vlad@nxp.com>2017-11-10 17:09:09 +0200
commitcddf17c8fff767b2f648cd2d4b0e47a7fd89b6ec (patch)
tree2438be67caced0896f274d5b2cba1439fbea1b65
parentef29d7829f590a4e716fdae143f7a0b7bf165b5a (diff)
drm: Check mode object lease status in all master ioctl paths [v4]
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. Changes for v2 as suggested by Daniel Vetter <daniel.vetter@ffwll.ch>: * With the change in the __drm_mode_object_find API to pass the file_priv along, we can now centralize most of the lease-based access checks in that function. * A few places skip that API and require in-line checks. Changes for v3 provided by Dave Airlie <airlied@redhat.com> * remove support for leasing encoders. * add support for leasing planes. Changes for v4 * Only call drm_lease_held if DRIVER_MODESET. Signed-off-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Marius Vlad <marius-cristian.vlad@nxp.com> (cherry-picked from: 48a5ad8c2e1a8e4014b19b113a94d42380b42915)
-rw-r--r--drivers/gpu/drm/drm_auth.c2
-rw-r--r--drivers/gpu/drm/drm_crtc.c83
-rw-r--r--drivers/gpu/drm/drm_encoder.c5
-rw-r--r--drivers/gpu/drm/drm_irq.c23
-rw-r--r--drivers/gpu/drm/drm_mode_object.c23
-rw-r--r--drivers/gpu/drm/drm_plane.c62
-rw-r--r--include/drm/drm_lease.h2
7 files changed, 113 insertions, 87 deletions
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index d644a1ef5554..d8249b9f6cc4 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -310,7 +310,7 @@ out:
*/
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_crtc.c b/drivers/gpu/drm/drm_crtc.c
index da001bea3e5a..690ff186b1b8 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -446,11 +446,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
struct drm_crtc *crtc;
struct drm_encoder *encoder;
int ret = 0;
- int connector_count = 0;
- int crtc_count = 0;
int fb_count = 0;
- int encoder_count = 0;
int copied = 0;
+ int count = 0;
uint32_t __user *fb_id;
uint32_t __user *crtc_id;
uint32_t __user *connector_id;
@@ -484,69 +482,60 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
card_res->count_fbs = fb_count;
mutex_unlock(&file_priv->fbs_lock);
- /* mode_config.mutex protects the connector list against e.g. DP MST
- * connector hot-adding. CRTC/Plane lists are invariant. */
- mutex_lock(&dev->mode_config.mutex);
- drm_for_each_crtc(crtc, dev)
- crtc_count++;
-
- drm_for_each_connector(connector, dev)
- connector_count++;
-
- drm_for_each_encoder(encoder, dev)
- encoder_count++;
-
card_res->max_height = dev->mode_config.max_height;
card_res->min_height = dev->mode_config.min_height;
card_res->max_width = dev->mode_config.max_width;
card_res->min_width = dev->mode_config.min_width;
/* CRTCs */
- if (card_res->count_crtcs >= crtc_count) {
- copied = 0;
- crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
- drm_for_each_crtc(crtc, dev) {
- if (put_user(crtc->base.id, crtc_id + copied)) {
- ret = -EFAULT;
- goto out;
+ crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_crtc(crtc, dev) {
+ if (drm_lease_held(file_priv, crtc->base.id)) {
+ if (count < card_res->count_crtcs &&
+ put_user(crtc->base.id, crtc_id + count)) {
+ mutex_unlock(&dev->mode_config.mutex);
+ return -EFAULT;
}
- copied++;
+ count++;
}
}
- card_res->count_crtcs = crtc_count;
+ mutex_unlock(&dev->mode_config.mutex);
+ card_res->count_crtcs = count;
/* Encoders */
- if (card_res->count_encoders >= encoder_count) {
- copied = 0;
- encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
- drm_for_each_encoder(encoder, dev) {
- if (put_user(encoder->base.id, encoder_id +
- copied)) {
- ret = -EFAULT;
- goto out;
- }
- copied++;
+ count = 0;
+ encoder_id = u64_to_user_ptr(card_res->encoder_id_ptr);
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_encoder(encoder, dev) {
+ if (count < card_res->count_encoders &&
+ put_user(encoder->base.id, encoder_id + count)) {
+ mutex_unlock(&dev->mode_config.mutex);
+ return -EFAULT;
}
+ count++;
}
- card_res->count_encoders = encoder_count;
+ mutex_unlock(&dev->mode_config.mutex);
+ card_res->count_encoders = count;
+
/* Connectors */
- if (card_res->count_connectors >= connector_count) {
- copied = 0;
- connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
- drm_for_each_connector(connector, dev) {
- if (put_user(connector->base.id,
- connector_id + copied)) {
- ret = -EFAULT;
- goto out;
+ count = 0;
+ connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_connector(connector, dev) {
+ if (drm_lease_held(file_priv, connector->base.id)) {
+ if (count < card_res->count_connectors &&
+ put_user(connector->base.id, connector_id + count)) {
+ mutex_unlock(&dev->mode_config.mutex);
+ return -EFAULT;
}
- copied++;
+ count++;
}
}
- card_res->count_connectors = connector_count;
-
-out:
mutex_unlock(&dev->mode_config.mutex);
+ card_res->count_connectors = count;
+
return ret;
}
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 75d43d34b0c2..0c545864080d 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -218,7 +218,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
crtc = drm_encoder_get_crtc(encoder);
- if (crtc)
+ if (crtc && drm_lease_held(file_priv, crtc->base.id))
enc_resp->crtc_id = crtc->base.id;
else
enc_resp->crtc_id = 0;
@@ -226,7 +226,8 @@ 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_crtcs = drm_lease_filter_crtcs(file_priv,
+ encoder->possible_crtcs);
enc_resp->possible_clones = encoder->possible_clones;
return 0;
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 48a6167f5e7b..38b06373cca6 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -1661,9 +1661,11 @@ err_put:
int drm_wait_vblank(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ struct drm_crtc *crtc;
struct drm_vblank_crtc *vblank;
union drm_wait_vblank *vblwait = data;
int ret;
+ unsigned int pipe_index;
unsigned int flags, seq, pipe, high_pipe;
if (!dev->irq_enabled)
@@ -1685,9 +1687,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
high_pipe = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
if (high_pipe)
- pipe = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
+ pipe_index = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
else
- pipe = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+ pipe_index = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+
+ /* Convert lease-relative crtc index into global crtc index */
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ pipe = 0;
+ drm_for_each_crtc(crtc, dev) {
+ if (drm_lease_held(file_priv, crtc->base.id)) {
+ if (pipe_index == 0)
+ break;
+ pipe_index--;
+ }
+ pipe++;
+ }
+ } else {
+ pipe = pipe_index;
+ }
+
+
if (pipe >= dev->num_crtcs)
return -EINVAL;
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index 9696e2c41702..ad1e7022794f 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -86,6 +86,26 @@ void drm_mode_object_register(struct drm_device *dev,
}
/**
+ * drm_lease_required - check types which must be leased to be used
+ * @type: type of object
+ *
+ * Returns whether the provided type of drm_mode_object must
+ * be owned or leased to be used by a process.
+ */
+static bool drm_lease_required(uint32_t type)
+{
+ switch(type) {
+ case DRM_MODE_OBJECT_CRTC:
+ case DRM_MODE_OBJECT_CONNECTOR:
+ case DRM_MODE_OBJECT_PLANE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+/**
* drm_mode_object_unregister - free a modeset identifer
* @dev: DRM device
* @object: object to free
@@ -120,6 +140,9 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
if (obj && obj->id != id)
obj = NULL;
+ if (obj && drm_lease_required(obj->type) && !_drm_lease_held(file_priv, obj->id))
+ obj = NULL;
+
if (obj && obj->free_cb) {
if (!kref_get_unless_zero(&obj->refcount))
obj = NULL;
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 249c0ae52c6d..68f607daf959 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -335,43 +335,38 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_mode_config *config;
struct drm_plane *plane;
uint32_t __user *plane_ptr;
- int copied = 0;
- unsigned num_planes;
+ int count = 0;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
config = &dev->mode_config;
-
- if (file_priv->universal_planes)
- num_planes = config->num_total_plane;
- else
- num_planes = config->num_overlay_plane;
+ plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
/*
* This ioctl is called twice, once to determine how much space is
* needed, and the 2nd time to fill it.
*/
- if (num_planes &&
- (plane_resp->count_planes >= num_planes)) {
- plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
-
- /* Plane lists are invariant, no locking needed. */
- drm_for_each_plane(plane, dev) {
- /*
- * Unless userspace set the 'universal planes'
- * capability bit, only advertise overlays.
- */
- if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
- !file_priv->universal_planes)
- continue;
-
- if (put_user(plane->base.id, plane_ptr + copied))
+
+ /* Plane lists are invariant, no locking needed. */
+ drm_for_each_plane(plane, dev) {
+ /*
+ * Unless userspace set the 'universal planes'
+ * capability bit, only advertise overlays.
+ */
+ if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
+ !file_priv->universal_planes)
+ continue;
+
+ if (drm_lease_held(file_priv, plane->base.id)) {
+ if (count < plane_resp->count_planes &&
+ put_user(plane->base.id, plane_ptr + count))
return -EFAULT;
- copied++;
+
+ count++;
}
}
- plane_resp->count_planes = num_planes;
+ plane_resp->count_planes = count;
return 0;
}
@@ -386,12 +381,12 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- plane = drm_plane_find(dev, plane_resp->plane_id);
+ plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);
if (!plane)
return -ENOENT;
drm_modeset_lock(&plane->mutex, NULL);
- if (plane->crtc)
+ if (plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))
plane_resp->crtc_id = plane->crtc->base.id;
else
plane_resp->crtc_id = 0;
@@ -403,7 +398,8 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
drm_modeset_unlock(&plane->mutex);
plane_resp->plane_id = plane->base.id;
- plane_resp->possible_crtcs = plane->possible_crtcs;
+ plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
+ plane->possible_crtcs);
plane_resp->gamma_size = 0;
/*
@@ -557,7 +553,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
* First, find the plane, crtc, and fb objects. If not available,
* we don't bother to call the driver.
*/
- plane = drm_plane_find(dev, plane_req->plane_id);
+ plane = drm_plane_find(dev, file_priv, plane_req->plane_id);
if (!plane) {
DRM_DEBUG_KMS("Unknown plane ID %d\n",
plane_req->plane_id);
@@ -565,14 +561,14 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
}
if (plane_req->fb_id) {
- fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);
if (!fb) {
DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
plane_req->fb_id);
return -ENOENT;
}
- crtc = drm_crtc_find(dev, plane_req->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
plane_req->crtc_id);
@@ -680,7 +676,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
return -EINVAL;
- crtc = drm_crtc_find(dev, req->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
return -ENOENT;
@@ -779,7 +775,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
return -EINVAL;
- crtc = drm_crtc_find(dev, page_flip->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);
if (!crtc)
return -ENOENT;
@@ -832,7 +828,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out;
}
- fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);
if (!fb) {
ret = -ENOENT;
goto out;
diff --git a/include/drm/drm_lease.h b/include/drm/drm_lease.h
index 890018976a3c..6149e56ddbf3 100644
--- a/include/drm/drm_lease.h
+++ b/include/drm/drm_lease.h
@@ -31,6 +31,4 @@ void drm_lease_revoke(struct drm_master *master);
uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs);
-uint32_t drm_lease_filter_encoders(struct drm_file *file_priv, uint32_t encoders);
-
#endif /* _DRM_LEASE_H_ */