drm/amdgpu: make UVD handle checking more strict
authorLeo Liu <leo.liu@amd.com>
Tue, 15 Sep 2015 14:38:38 +0000 (10:38 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 23 Sep 2015 21:23:40 +0000 (17:23 -0400)
Invalid messages can crash the hw otherwise

Ported from radeon commit a1b403da70e038ca6c6c6fe434d1d873546873a3

Signed-off-by: Leo Liu <leo.liu@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Cc: stable@vger.kernel.org
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c

index 1a8e43b3039e65ef7143b990bd27a402910b0102..d0312364d950bec9968c220f876fd0f24b1ebe16 100644 (file)
@@ -543,46 +543,60 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx,
                return -EINVAL;
        }
 
-       if (msg_type == 1) {
+       switch (msg_type) {
+       case 0:
+               /* it's a create msg, calc image size (width * height) */
+               amdgpu_bo_kunmap(bo);
+
+               /* try to alloc a new handle */
+               for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
+                       if (atomic_read(&adev->uvd.handles[i]) == handle) {
+                               DRM_ERROR("Handle 0x%x already in use!\n", handle);
+                               return -EINVAL;
+                       }
+
+                       if (!atomic_cmpxchg(&adev->uvd.handles[i], 0, handle)) {
+                               adev->uvd.filp[i] = ctx->parser->filp;
+                               return 0;
+                       }
+               }
+
+               DRM_ERROR("No more free UVD handles!\n");
+               return -EINVAL;
+
+       case 1:
                /* it's a decode msg, calc buffer sizes */
                r = amdgpu_uvd_cs_msg_decode(msg, ctx->buf_sizes);
                amdgpu_bo_kunmap(bo);
                if (r)
                        return r;
 
-       } else if (msg_type == 2) {
+               /* validate the handle */
+               for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
+                       if (atomic_read(&adev->uvd.handles[i]) == handle) {
+                               if (adev->uvd.filp[i] != ctx->parser->filp) {
+                                       DRM_ERROR("UVD handle collision detected!\n");
+                                       return -EINVAL;
+                               }
+                               return 0;
+                       }
+               }
+
+               DRM_ERROR("Invalid UVD handle 0x%x!\n", handle);
+               return -ENOENT;
+
+       case 2:
                /* it's a destroy msg, free the handle */
                for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i)
                        atomic_cmpxchg(&adev->uvd.handles[i], handle, 0);
                amdgpu_bo_kunmap(bo);
                return 0;
-       } else {
-               /* it's a create msg */
-               amdgpu_bo_kunmap(bo);
-
-               if (msg_type != 0) {
-                       DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
-                       return -EINVAL;
-               }
-
-               /* it's a create msg, no special handling needed */
-       }
-
-       /* create or decode, validate the handle */
-       for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
-               if (atomic_read(&adev->uvd.handles[i]) == handle)
-                       return 0;
-       }
 
-       /* handle not found try to alloc a new one */
-       for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
-               if (!atomic_cmpxchg(&adev->uvd.handles[i], 0, handle)) {
-                       adev->uvd.filp[i] = ctx->parser->filp;
-                       return 0;
-               }
+       default:
+               DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
+               return -EINVAL;
        }
-
-       DRM_ERROR("No more free UVD handles!\n");
+       BUG();
        return -EINVAL;
 }