aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-07-23 21:53:45 -0400
committerDave Airlie <airlied@redhat.com>2014-08-04 02:54:02 -0400
commit2ee39452fa2fff1e8edb954ccb7e0daee9646557 (patch)
tree94e29c96825e2a90dd6a103caf07585eed8e49c6
parentf68d697eaf3278200a7fc3c8b1d95d72837b84d8 (diff)
drm: close race in connector registration (v2)
Daniel pointed out with hotplug that userspace could be trying to oops us as root for lols, and that to be correct we shouldn't register the object with the idr before we have fully set the connector object up. His proposed solution was a lot more life changing, this seemed like a simpler proposition to me, get the connector object id from the idr, but don't register the object until the drm_connector_register callback. The open question is whether the drm_mode_object_register needs a bigger lock than just the idr one, but I can't see why it would, but I can be locking challenged. v2: fix bool noreg into sane - add comment. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_crtc.c48
1 files changed, 35 insertions, 13 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 1ccf5cb9aa86..c3a5a8f0825b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -361,6 +361,32 @@ const char *drm_get_format_name(uint32_t format)
361} 361}
362EXPORT_SYMBOL(drm_get_format_name); 362EXPORT_SYMBOL(drm_get_format_name);
363 363
364/*
365 * Internal function to assign a slot in the object idr and optionally
366 * register the object into the idr.
367 */
368static int drm_mode_object_get_reg(struct drm_device *dev,
369 struct drm_mode_object *obj,
370 uint32_t obj_type,
371 bool register_obj)
372{
373 int ret;
374
375 mutex_lock(&dev->mode_config.idr_mutex);
376 ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
377 if (ret >= 0) {
378 /*
379 * Set up the object linking under the protection of the idr
380 * lock so that other users can't see inconsistent state.
381 */
382 obj->id = ret;
383 obj->type = obj_type;
384 }
385 mutex_unlock(&dev->mode_config.idr_mutex);
386
387 return ret < 0 ? ret : 0;
388}
389
364/** 390/**
365 * drm_mode_object_get - allocate a new modeset identifier 391 * drm_mode_object_get - allocate a new modeset identifier
366 * @dev: DRM device 392 * @dev: DRM device
@@ -379,21 +405,15 @@ EXPORT_SYMBOL(drm_get_format_name);
379int drm_mode_object_get(struct drm_device *dev, 405int drm_mode_object_get(struct drm_device *dev,
380 struct drm_mode_object *obj, uint32_t obj_type) 406 struct drm_mode_object *obj, uint32_t obj_type)
381{ 407{
382 int ret; 408 return drm_mode_object_get_reg(dev, obj, obj_type, true);
409}
383 410
411static void drm_mode_object_register(struct drm_device *dev,
412 struct drm_mode_object *obj)
413{
384 mutex_lock(&dev->mode_config.idr_mutex); 414 mutex_lock(&dev->mode_config.idr_mutex);
385 ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL); 415 idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
386 if (ret >= 0) {
387 /*
388 * Set up the object linking under the protection of the idr
389 * lock so that other users can't see inconsistent state.
390 */
391 obj->id = ret;
392 obj->type = obj_type;
393 }
394 mutex_unlock(&dev->mode_config.idr_mutex); 416 mutex_unlock(&dev->mode_config.idr_mutex);
395
396 return ret < 0 ? ret : 0;
397} 417}
398 418
399/** 419/**
@@ -849,7 +869,7 @@ int drm_connector_init(struct drm_device *dev,
849 869
850 drm_modeset_lock_all(dev); 870 drm_modeset_lock_all(dev);
851 871
852 ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); 872 ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false);
853 if (ret) 873 if (ret)
854 goto out_unlock; 874 goto out_unlock;
855 875
@@ -942,6 +962,8 @@ int drm_connector_register(struct drm_connector *connector)
942{ 962{
943 int ret; 963 int ret;
944 964
965 drm_mode_object_register(connector->dev, &connector->base);
966
945 ret = drm_sysfs_connector_add(connector); 967 ret = drm_sysfs_connector_add(connector);
946 if (ret) 968 if (ret)
947 return ret; 969 return ret;