diff options
author | Christian König <christian.koenig@amd.com> | 2013-08-05 08:10:57 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-08-07 17:37:16 -0400 |
commit | 56cc2c15389770d2f95a791f73d0ab6b15d530e1 (patch) | |
tree | 910652fc42c01fd8a4f1eac5eabc62eea5bbbd88 | |
parent | 641a00593f7d07eab778fbabf546fb68fff3d5ce (diff) |
drm/radeon: add more UVD CS checking
Improve error handling in case userspace sends us
an invalid command buffer.
Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_uvd.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 4fec195e0dd4..f1c15754e73c 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c | |||
@@ -357,8 +357,10 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, | |||
357 | } | 357 | } |
358 | 358 | ||
359 | r = radeon_bo_kmap(bo, &ptr); | 359 | r = radeon_bo_kmap(bo, &ptr); |
360 | if (r) | 360 | if (r) { |
361 | DRM_ERROR("Failed mapping the UVD message (%d)!\n", r); | ||
361 | return r; | 362 | return r; |
363 | } | ||
362 | 364 | ||
363 | msg = ptr + offset; | 365 | msg = ptr + offset; |
364 | 366 | ||
@@ -384,8 +386,14 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, | |||
384 | radeon_bo_kunmap(bo); | 386 | radeon_bo_kunmap(bo); |
385 | return 0; | 387 | return 0; |
386 | } else { | 388 | } else { |
387 | /* it's a create msg, no special handling needed */ | ||
388 | radeon_bo_kunmap(bo); | 389 | radeon_bo_kunmap(bo); |
390 | |||
391 | if (msg_type != 0) { | ||
392 | DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | /* it's a create msg, no special handling needed */ | ||
389 | } | 397 | } |
390 | 398 | ||
391 | /* create or decode, validate the handle */ | 399 | /* create or decode, validate the handle */ |
@@ -408,7 +416,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, | |||
408 | 416 | ||
409 | static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, | 417 | static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, |
410 | int data0, int data1, | 418 | int data0, int data1, |
411 | unsigned buf_sizes[]) | 419 | unsigned buf_sizes[], bool *has_msg_cmd) |
412 | { | 420 | { |
413 | struct radeon_cs_chunk *relocs_chunk; | 421 | struct radeon_cs_chunk *relocs_chunk; |
414 | struct radeon_cs_reloc *reloc; | 422 | struct radeon_cs_reloc *reloc; |
@@ -437,7 +445,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, | |||
437 | 445 | ||
438 | if (cmd < 0x4) { | 446 | if (cmd < 0x4) { |
439 | if ((end - start) < buf_sizes[cmd]) { | 447 | if ((end - start) < buf_sizes[cmd]) { |
440 | DRM_ERROR("buffer to small (%d / %d)!\n", | 448 | DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd, |
441 | (unsigned)(end - start), buf_sizes[cmd]); | 449 | (unsigned)(end - start), buf_sizes[cmd]); |
442 | return -EINVAL; | 450 | return -EINVAL; |
443 | } | 451 | } |
@@ -462,9 +470,17 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, | |||
462 | } | 470 | } |
463 | 471 | ||
464 | if (cmd == 0) { | 472 | if (cmd == 0) { |
473 | if (*has_msg_cmd) { | ||
474 | DRM_ERROR("More than one message in a UVD-IB!\n"); | ||
475 | return -EINVAL; | ||
476 | } | ||
477 | *has_msg_cmd = true; | ||
465 | r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); | 478 | r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); |
466 | if (r) | 479 | if (r) |
467 | return r; | 480 | return r; |
481 | } else if (!*has_msg_cmd) { | ||
482 | DRM_ERROR("Message needed before other commands are send!\n"); | ||
483 | return -EINVAL; | ||
468 | } | 484 | } |
469 | 485 | ||
470 | return 0; | 486 | return 0; |
@@ -473,7 +489,8 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, | |||
473 | static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, | 489 | static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, |
474 | struct radeon_cs_packet *pkt, | 490 | struct radeon_cs_packet *pkt, |
475 | int *data0, int *data1, | 491 | int *data0, int *data1, |
476 | unsigned buf_sizes[]) | 492 | unsigned buf_sizes[], |
493 | bool *has_msg_cmd) | ||
477 | { | 494 | { |
478 | int i, r; | 495 | int i, r; |
479 | 496 | ||
@@ -487,7 +504,8 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, | |||
487 | *data1 = p->idx; | 504 | *data1 = p->idx; |
488 | break; | 505 | break; |
489 | case UVD_GPCOM_VCPU_CMD: | 506 | case UVD_GPCOM_VCPU_CMD: |
490 | r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes); | 507 | r = radeon_uvd_cs_reloc(p, *data0, *data1, |
508 | buf_sizes, has_msg_cmd); | ||
491 | if (r) | 509 | if (r) |
492 | return r; | 510 | return r; |
493 | break; | 511 | break; |
@@ -508,6 +526,9 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) | |||
508 | struct radeon_cs_packet pkt; | 526 | struct radeon_cs_packet pkt; |
509 | int r, data0 = 0, data1 = 0; | 527 | int r, data0 = 0, data1 = 0; |
510 | 528 | ||
529 | /* does the IB has a msg command */ | ||
530 | bool has_msg_cmd = false; | ||
531 | |||
511 | /* minimum buffer sizes */ | 532 | /* minimum buffer sizes */ |
512 | unsigned buf_sizes[] = { | 533 | unsigned buf_sizes[] = { |
513 | [0x00000000] = 2048, | 534 | [0x00000000] = 2048, |
@@ -534,8 +555,8 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) | |||
534 | return r; | 555 | return r; |
535 | switch (pkt.type) { | 556 | switch (pkt.type) { |
536 | case RADEON_PACKET_TYPE0: | 557 | case RADEON_PACKET_TYPE0: |
537 | r = radeon_uvd_cs_reg(p, &pkt, &data0, | 558 | r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1, |
538 | &data1, buf_sizes); | 559 | buf_sizes, &has_msg_cmd); |
539 | if (r) | 560 | if (r) |
540 | return r; | 561 | return r; |
541 | break; | 562 | break; |
@@ -547,6 +568,12 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) | |||
547 | return -EINVAL; | 568 | return -EINVAL; |
548 | } | 569 | } |
549 | } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); | 570 | } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); |
571 | |||
572 | if (!has_msg_cmd) { | ||
573 | DRM_ERROR("UVD-IBs need a msg command!\n"); | ||
574 | return -EINVAL; | ||
575 | } | ||
576 | |||
550 | return 0; | 577 | return 0; |
551 | } | 578 | } |
552 | 579 | ||