Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1036297AbdD2GHY (ORCPT ); Sat, 29 Apr 2017 02:07:24 -0400 Received: from home.keithp.com ([63.227.221.253]:44240 "EHLO elaine.keithp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S968257AbdD2GHJ (ORCPT ); Sat, 29 Apr 2017 02:07:09 -0400 From: Keith Packard To: linux-kernel@vger.kernel.org, Dave Airlie , Daniel Vetter Cc: Keith Packard , dri-devel@lists.freedesktop.org Subject: [PATCH 4/5] drm: Check mode object lease status in all master ioctl paths [v2] Date: Fri, 28 Apr 2017 23:07:01 -0700 Message-Id: <20170429060702.6656-5-keithp@keithp.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170429060702.6656-1-keithp@keithp.com> References: <20170401170841.2643-1-keithp@keithp.com> <20170429060702.6656-1-keithp@keithp.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8672 Lines: 249 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 : 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. Signed-off-by: Keith Packard --- drivers/gpu/drm/drm_auth.c | 2 +- drivers/gpu/drm/drm_connector.c | 8 +++--- drivers/gpu/drm/drm_encoder.c | 8 +++--- drivers/gpu/drm/drm_mode_config.c | 52 ++++++++++++++++++++++++--------------- drivers/gpu/drm/drm_mode_object.c | 22 +++++++++++++++++ drivers/gpu/drm/drm_plane.c | 6 +++-- 6 files changed, 69 insertions(+), 29 deletions(-) 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_connector.c b/drivers/gpu/drm/drm_connector.c index 670c20d5660c..dbf34f08363b 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1094,7 +1094,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, } for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) - if (connector->encoder_ids[i] != 0) + if (connector->encoder_ids[i] != 0 && + drm_lease_held(file_priv, connector->encoder_ids[i])) encoders_count++; if (out_resp->count_modes == 0) { @@ -1118,7 +1119,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); encoder = drm_connector_get_encoder(connector); - if (encoder) + if (encoder && drm_lease_held(file_priv, encoder->base.id)) out_resp->encoder_id = encoder->base.id; else out_resp->encoder_id = 0; @@ -1156,7 +1157,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, copied = 0; encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] != 0) { + if (connector->encoder_ids[i] != 0 && + drm_lease_held(file_priv, connector->encoder_ids[i])) { if (put_user(connector->encoder_ids[i], encoder_ptr + copied)) { ret = -EFAULT; diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index dbaedd4e12e6..512d0b6cb7d2 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -211,7 +211,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; @@ -219,8 +219,10 @@ 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; + enc_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv, + encoder->possible_crtcs); + enc_resp->possible_clones = drm_lease_filter_encoders(file_priv, + encoder->possible_clones); return 0; } diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 2735a5847ffa..bb6b64e594b7 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -131,14 +131,20 @@ int drm_mode_getresources(struct drm_device *dev, void *data, /* 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_crtc(crtc, dev) { + if (drm_lease_held(file_priv, crtc->base.id)) + crtc_count++; + } - drm_for_each_connector(connector, dev) - connector_count++; + drm_for_each_connector(connector, dev) { + if (drm_lease_held(file_priv, connector->base.id)) + connector_count++; + } - drm_for_each_encoder(encoder, dev) - encoder_count++; + drm_for_each_encoder(encoder, dev) { + if (drm_lease_held(file_priv, encoder->base.id)) + encoder_count++; + } card_res->max_height = dev->mode_config.max_height; card_res->min_height = dev->mode_config.min_height; @@ -150,11 +156,13 @@ int drm_mode_getresources(struct drm_device *dev, void *data, 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; + if (drm_lease_held(file_priv, crtc->base.id)) { + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; } - copied++; } } card_res->count_crtcs = crtc_count; @@ -164,12 +172,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data, 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; + if (drm_lease_held(file_priv, encoder->base.id)) { + if (put_user(encoder->base.id, encoder_id + + copied)) { + ret = -EFAULT; + goto out; + } + copied++; } - copied++; } } card_res->count_encoders = encoder_count; @@ -179,12 +189,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data, 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; + if (drm_lease_held(file_priv, connector->base.id)) { + if (put_user(connector->base.id, + connector_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; } - copied++; } } card_res->count_connectors = connector_count; diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index daddc7640139..9763787492cc 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -107,6 +107,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_ENCODER: + 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) @@ -120,6 +139,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 819f74616f34..c9c687cdc747 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -392,7 +392,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, 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; @@ -404,7 +404,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; /* -- 2.11.0