Commit 7de440db authored by Keith Packard's avatar Keith Packard Committed by Dave Airlie

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: default avatarKeith Packard <keithp@keithp.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 2ed077e4
...@@ -310,7 +310,7 @@ void drm_master_release(struct drm_file *file_priv) ...@@ -310,7 +310,7 @@ void drm_master_release(struct drm_file *file_priv)
*/ */
bool drm_is_current_master(struct drm_file *fpriv) 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); EXPORT_SYMBOL(drm_is_current_master);
......
...@@ -226,7 +226,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, ...@@ -226,7 +226,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
crtc = drm_encoder_get_crtc(encoder); 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; enc_resp->crtc_id = crtc->base.id;
else else
enc_resp->crtc_id = 0; enc_resp->crtc_id = 0;
...@@ -234,7 +234,8 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, ...@@ -234,7 +234,8 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_type = encoder->encoder_type;
enc_resp->encoder_id = encoder->base.id; 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; enc_resp->possible_clones = encoder->possible_clones;
return 0; return 0;
......
...@@ -122,10 +122,12 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -122,10 +122,12 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
count = 0; count = 0;
crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr); crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
drm_for_each_crtc(crtc, dev) { drm_for_each_crtc(crtc, dev) {
if (count < card_res->count_crtcs && if (drm_lease_held(file_priv, crtc->base.id)) {
put_user(crtc->base.id, crtc_id + count)) if (count < card_res->count_crtcs &&
return -EFAULT; put_user(crtc->base.id, crtc_id + count))
count++; return -EFAULT;
count++;
}
} }
card_res->count_crtcs = count; card_res->count_crtcs = count;
...@@ -143,12 +145,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -143,12 +145,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
count = 0; count = 0;
connector_id = u64_to_user_ptr(card_res->connector_id_ptr); connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
drm_for_each_connector_iter(connector, &conn_iter) { drm_for_each_connector_iter(connector, &conn_iter) {
if (count < card_res->count_connectors && if (drm_lease_held(file_priv, connector->base.id)) {
put_user(connector->base.id, connector_id + count)) { if (count < card_res->count_connectors &&
drm_connector_list_iter_end(&conn_iter); put_user(connector->base.id, connector_id + count)) {
return -EFAULT; drm_connector_list_iter_end(&conn_iter);
return -EFAULT;
}
count++;
} }
count++;
} }
card_res->count_connectors = count; card_res->count_connectors = count;
drm_connector_list_iter_end(&conn_iter); drm_connector_list_iter_end(&conn_iter);
......
...@@ -104,6 +104,25 @@ void drm_mode_object_unregister(struct drm_device *dev, ...@@ -104,6 +104,25 @@ void drm_mode_object_unregister(struct drm_device *dev,
mutex_unlock(&dev->mode_config.idr_mutex); 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_mode_object *__drm_mode_object_find(struct drm_device *dev,
struct drm_file *file_priv, struct drm_file *file_priv,
uint32_t id, uint32_t type) uint32_t id, uint32_t type)
...@@ -117,6 +136,9 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, ...@@ -117,6 +136,9 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
if (obj && obj->id != id) if (obj && obj->id != id)
obj = NULL; obj = NULL;
if (obj && drm_lease_required(obj->type) && !_drm_lease_held(file_priv, obj->id))
obj = NULL;
if (obj && obj->free_cb) { if (obj && obj->free_cb) {
if (!kref_get_unless_zero(&obj->refcount)) if (!kref_get_unless_zero(&obj->refcount))
obj = NULL; obj = NULL;
......
...@@ -479,10 +479,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, ...@@ -479,10 +479,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
!file_priv->universal_planes) !file_priv->universal_planes)
continue; continue;
if (count < plane_resp->count_planes && if (drm_lease_held(file_priv, plane->base.id)) {
put_user(plane->base.id, plane_ptr + count)) if (count < plane_resp->count_planes &&
return -EFAULT; put_user(plane->base.id, plane_ptr + count))
count++; return -EFAULT;
count++;
}
} }
plane_resp->count_planes = count; plane_resp->count_planes = count;
...@@ -504,9 +506,9 @@ int drm_mode_getplane(struct drm_device *dev, void *data, ...@@ -504,9 +506,9 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
return -ENOENT; return -ENOENT;
drm_modeset_lock(&plane->mutex, NULL); 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; 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; plane_resp->crtc_id = plane->crtc->base.id;
else else
plane_resp->crtc_id = 0; plane_resp->crtc_id = 0;
...@@ -520,7 +522,9 @@ int drm_mode_getplane(struct drm_device *dev, void *data, ...@@ -520,7 +522,9 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
drm_modeset_unlock(&plane->mutex); drm_modeset_unlock(&plane->mutex);
plane_resp->plane_id = plane->base.id; 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; plane_resp->gamma_size = 0;
/* /*
......
...@@ -1447,10 +1447,12 @@ static void drm_wait_vblank_reply(struct drm_device *dev, unsigned int pipe, ...@@ -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, int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_crtc *crtc;
struct drm_vblank_crtc *vblank; struct drm_vblank_crtc *vblank;
union drm_wait_vblank *vblwait = data; union drm_wait_vblank *vblwait = data;
int ret; int ret;
u64 req_seq, seq; u64 req_seq, seq;
unsigned int pipe_index;
unsigned int flags, pipe, high_pipe; unsigned int flags, pipe, high_pipe;
if (!dev->irq_enabled) if (!dev->irq_enabled)
...@@ -1472,9 +1474,25 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, ...@@ -1472,9 +1474,25 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
high_pipe = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK); high_pipe = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
if (high_pipe) if (high_pipe)
pipe = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT; pipe_index = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
else 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) if (pipe >= dev->num_crtcs)
return -EINVAL; return -EINVAL;
......
...@@ -31,6 +31,4 @@ void drm_lease_revoke(struct drm_master *master); ...@@ -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_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_ */ #endif /* _DRM_LEASE_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment