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>
This commit is contained in:
parent
2ed077e467
commit
7de440db20
@ -310,7 +310,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
!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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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);
|
|||||||
|
|
||||||
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_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user