drm: Check mode object lease status in all master ioctl paths [v4]
authorKeith Packard <keithp@keithp.com>
Mon, 10 Apr 2017 04:35:34 +0000 (22:35 -0600)
committerDave Airlie <airlied@redhat.com>
Wed, 25 Oct 2017 06:31:30 +0000 (16:31 +1000)
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>
drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_encoder.c
drivers/gpu/drm/drm_mode_config.c
drivers/gpu/drm/drm_mode_object.c
drivers/gpu/drm/drm_plane.c
drivers/gpu/drm/drm_vblank.c
include/drm/drm_lease.h

index 4f0e274f411122a570e53c50022dab2527b205e4..aad468d170a7e786fb5c460b6dd01ecff015ef3a 100644 (file)
@@ -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);
 
index 43f644844b836ac746921b069407644d1114cd69..59e0ebe733f8e847994e23e4b53aca484b88edbc 100644 (file)
@@ -226,7 +226,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;
@@ -234,7 +234,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;
index 919e78d45ab00f406fa2086ace4955a929266e73..cda8bfab6d3b49e3e31516ae5895b878ed4e7581 100644 (file)
@@ -122,10 +122,12 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        count = 0;
        crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
        drm_for_each_crtc(crtc, dev) {
-               if (count < card_res->count_crtcs &&
-                   put_user(crtc->base.id, crtc_id + count))
-                       return -EFAULT;
-               count++;
+               if (drm_lease_held(file_priv, crtc->base.id)) {
+                       if (count < card_res->count_crtcs &&
+                           put_user(crtc->base.id, crtc_id + count))
+                               return -EFAULT;
+                       count++;
+               }
        }
        card_res->count_crtcs = count;
 
@@ -143,12 +145,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        count = 0;
        connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
        drm_for_each_connector_iter(connector, &conn_iter) {
-               if (count < card_res->count_connectors &&
-                   put_user(connector->base.id, connector_id + count)) {
-                       drm_connector_list_iter_end(&conn_iter);
-                       return -EFAULT;
+               if (drm_lease_held(file_priv, connector->base.id)) {
+                       if (count < card_res->count_connectors &&
+                           put_user(connector->base.id, connector_id + count)) {
+                               drm_connector_list_iter_end(&conn_iter);
+                               return -EFAULT;
+                       }
+                       count++;
                }
-               count++;
        }
        card_res->count_connectors = count;
        drm_connector_list_iter_end(&conn_iter);
index 240a05d91a5386a5a21de1c5a9f8faaba14be620..d1599f36b605a4a08f17bc5f66de1ec871fc3e0a 100644 (file)
@@ -104,6 +104,25 @@ void drm_mode_object_unregister(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
 }
 
+/**
+ * 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;
+       }
+}
+
 struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
                                               struct drm_file *file_priv,
                                               uint32_t id, uint32_t type)
@@ -117,6 +136,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;
index 8d9824804b0c82b526e787101e5563f68837605f..19404e34cd592d4a19720efa8b64d3fc4854569f 100644 (file)
@@ -479,10 +479,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
                    !file_priv->universal_planes)
                        continue;
 
-               if (count < plane_resp->count_planes &&
-                   put_user(plane->base.id, plane_ptr + count))
-                       return -EFAULT;
-               count++;
+               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;
+                       count++;
+               }
        }
        plane_resp->count_planes = count;
 
@@ -504,9 +506,9 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
                return -ENOENT;
 
        drm_modeset_lock(&plane->mutex, NULL);
-       if (plane->state && plane->state->crtc)
+       if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id))
                plane_resp->crtc_id = plane->state->crtc->base.id;
-       else if (!plane->state && plane->crtc)
+       else if (!plane->state && 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;
@@ -520,7 +522,9 @@ 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;
 
        /*
index 13722c373a6a5a6805adff5b11c268ad806742eb..57cc6e37c81083fe9c7727ce851d6119692399a9 100644 (file)
@@ -1447,10 +1447,12 @@ static void drm_wait_vblank_reply(struct drm_device *dev, unsigned int pipe,
 int drm_wait_vblank_ioctl(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;
        u64 req_seq, seq;
+       unsigned int pipe_index;
        unsigned int flags, pipe, high_pipe;
 
        if (!dev->irq_enabled)
@@ -1472,9 +1474,25 @@ int drm_wait_vblank_ioctl(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;
 
index 890018976a3c6c540274f3477f2f43b9ba0b597e..6149e56ddbf31742a45ef46c884216b9628fb1fb 100644 (file)
@@ -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_ */