summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_gem.c75
-rw-r--r--drivers/gpu/drm/drm_ioctl.c3
2 files changed, 37 insertions, 41 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index e12cdf91f4dc..3b2448a3a9de 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1015,12 +1015,25 @@ err:
return ret;
}
+/*
+ * This ioctl is disabled for security reasons but also it failed
+ * to follow process in terms of adding testing in igt and verifying
+ * all the corner cases which made fixing security bugs in it even
+ * harder than necessary.
+ *
+ * To re-enable this ioctl
+ * 1. land working IGT tests in igt-gpu-tools that cover
+ * all corner cases and race conditions.
+ * 2. handle idr_preload
+ * 3. handle == 0
+ * 4. handle == new_handle semantics definition.
+ */
int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_gem_change_handle *args = data;
- struct drm_gem_object *obj, *idrobj;
- int handle, ret;
+ struct drm_gem_object *obj;
+ int new_handle, ret;
if (!drm_core_check_feature(dev, DRIVER_GEM))
return -EOPNOTSUPP;
@@ -1028,52 +1041,36 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
/* idr_alloc() limitation. */
if (args->new_handle > INT_MAX)
return -EINVAL;
- handle = args->new_handle;
-
- obj = drm_gem_object_lookup(file_priv, args->handle);
- if (!obj)
- return -ENOENT;
+ new_handle = args->new_handle;
- if (args->handle == handle) {
- ret = 0;
- goto out;
- }
+ if (args->handle == new_handle)
+ return 0;
mutex_lock(&file_priv->prime.lock);
-
spin_lock(&file_priv->table_lock);
-
- /* When create_tail allocs an obj idr, it needs to first alloc as NULL,
- * then later replace with the correct object. This is not necessary
- * here, because the only operations that could race are drm_prime
- * bookkeeping, and we hold the prime lock.
- */
- ret = idr_alloc(&file_priv->object_idr, obj, handle, handle + 1,
+ ret = idr_alloc(&file_priv->object_idr, NULL, new_handle, new_handle + 1,
GFP_NOWAIT);
- if (ret < 0) {
- spin_unlock(&file_priv->table_lock);
- goto out_unlock;
- }
-
- idrobj = idr_replace(&file_priv->object_idr, NULL, handle);
- if (idrobj != obj) {
- idr_replace(&file_priv->object_idr, idrobj, handle);
- idr_remove(&file_priv->object_idr, args->new_handle);
- spin_unlock(&file_priv->table_lock);
- ret = -ENOENT;
- goto out_unlock;
- }
-
- idr_replace(&file_priv->object_idr, NULL, args->handle);
+ if (ret < 0) {
+ spin_unlock(&file_priv->table_lock);
+ goto out_unlock;
+ }
+
+ obj = idr_replace(&file_priv->object_idr, NULL, args->handle);
+ if (IS_ERR_OR_NULL(obj)) {
+ idr_remove(&file_priv->object_idr, new_handle);
+ spin_unlock(&file_priv->table_lock);
+ ret = -ENOENT;
+ goto out_unlock;
+ }
spin_unlock(&file_priv->table_lock);
if (obj->dma_buf) {
ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf,
- handle);
+ new_handle);
if (ret < 0) {
spin_lock(&file_priv->table_lock);
- idr_remove(&file_priv->object_idr, handle);
+ idr_remove(&file_priv->object_idr, new_handle);
idr_replace(&file_priv->object_idr, obj, args->handle);
spin_unlock(&file_priv->table_lock);
goto out_unlock;
@@ -1086,14 +1083,12 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
spin_lock(&file_priv->table_lock);
idr_remove(&file_priv->object_idr, args->handle);
- idrobj = idr_replace(&file_priv->object_idr, obj, handle);
+ obj = idr_replace(&file_priv->object_idr, obj, new_handle);
spin_unlock(&file_priv->table_lock);
- WARN_ON(idrobj != NULL);
+ WARN_ON(obj != NULL);
out_unlock:
mutex_unlock(&file_priv->prime.lock);
-out:
- drm_gem_object_put(obj);
return ret;
}
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index ff193155129e..e2df4becce62 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -660,7 +660,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_gem_change_handle_ioctl, DRM_RENDER_ALLOW),
+ /* see drm_gem.c:drm_gem_change_handle_ioctl for why this is invalid */
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_invalid_op, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0),