aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2015-05-07 09:19:23 -0400
committerAlex Deucher <alexander.deucher@amd.com>2015-05-07 11:00:16 -0400
commita1b403da70e038ca6c6c6fe434d1d873546873a3 (patch)
treec3e96c26cd8be5da3853ba01a4e6b1cc61e9ba99 /drivers/gpu
parent29c63fe22a17c64e54016040cd882481bd45ee5a (diff)
drm/radeon: make UVD handle checking more strict
Invalid messages can crash the hw otherwise. Signed-off-by: Christian König <christian.koenig@amd.com> CC: stable@vger.kernel.org Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/radeon/radeon_uvd.c72
1 files changed, 43 insertions, 29 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index c10b2aec6450..f67a6aae0010 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -436,50 +436,64 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
436 return -EINVAL; 436 return -EINVAL;
437 } 437 }
438 438
439 if (msg_type == 1) { 439 switch (msg_type) {
440 case 0:
441 /* it's a create msg, calc image size (width * height) */
442 img_size = msg[7] * msg[8];
443 radeon_bo_kunmap(bo);
444
445 /* try to alloc a new handle */
446 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
447 if (atomic_read(&p->rdev->uvd.handles[i]) == handle) {
448 DRM_ERROR("Handle 0x%x already in use!\n", handle);
449 return -EINVAL;
450 }
451
452 if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) {
453 p->rdev->uvd.filp[i] = p->filp;
454 p->rdev->uvd.img_size[i] = img_size;
455 return 0;
456 }
457 }
458
459 DRM_ERROR("No more free UVD handles!\n");
460 return -EINVAL;
461
462 case 1:
440 /* it's a decode msg, calc buffer sizes */ 463 /* it's a decode msg, calc buffer sizes */
441 r = radeon_uvd_cs_msg_decode(msg, buf_sizes); 464 r = radeon_uvd_cs_msg_decode(msg, buf_sizes);
442 /* calc image size (width * height) */
443 img_size = msg[6] * msg[7];
444 radeon_bo_kunmap(bo); 465 radeon_bo_kunmap(bo);
445 if (r) 466 if (r)
446 return r; 467 return r;
447 468
448 } else if (msg_type == 2) { 469 /* validate the handle */
470 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
471 if (atomic_read(&p->rdev->uvd.handles[i]) == handle) {
472 if (p->rdev->uvd.filp[i] != p->filp) {
473 DRM_ERROR("UVD handle collision detected!\n");
474 return -EINVAL;
475 }
476 return 0;
477 }
478 }
479
480 DRM_ERROR("Invalid UVD handle 0x%x!\n", handle);
481 return -ENOENT;
482
483 case 2:
449 /* it's a destroy msg, free the handle */ 484 /* it's a destroy msg, free the handle */
450 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) 485 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
451 atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); 486 atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0);
452 radeon_bo_kunmap(bo); 487 radeon_bo_kunmap(bo);
453 return 0; 488 return 0;
454 } else {
455 /* it's a create msg, calc image size (width * height) */
456 img_size = msg[7] * msg[8];
457 radeon_bo_kunmap(bo);
458 489
459 if (msg_type != 0) { 490 default:
460 DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
461 return -EINVAL;
462 }
463
464 /* it's a create msg, no special handling needed */
465 }
466
467 /* create or decode, validate the handle */
468 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
469 if (atomic_read(&p->rdev->uvd.handles[i]) == handle)
470 return 0;
471 }
472 491
473 /* handle not found try to alloc a new one */ 492 DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
474 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { 493 return -EINVAL;
475 if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) {
476 p->rdev->uvd.filp[i] = p->filp;
477 p->rdev->uvd.img_size[i] = img_size;
478 return 0;
479 }
480 } 494 }
481 495
482 DRM_ERROR("No more free UVD handles!\n"); 496 BUG();
483 return -EINVAL; 497 return -EINVAL;
484} 498}
485 499