diff options
author | Christian König <christian.koenig@amd.com> | 2015-05-07 09:19:23 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2015-05-07 11:00:16 -0400 |
commit | a1b403da70e038ca6c6c6fe434d1d873546873a3 (patch) | |
tree | c3e96c26cd8be5da3853ba01a4e6b1cc61e9ba99 | |
parent | 29c63fe22a17c64e54016040cd882481bd45ee5a (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>
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_uvd.c | 72 |
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 | ||