Skip to content

Commit 29c63fe

Browse files
ChristianKoenigAMDalexdeucher
authored andcommitted
drm/radeon: make VCE handle check more strict
Invalid handles can crash the hw. Signed-off-by: Christian König <christian.koenig@amd.com> CC: stable@vger.kernel.org Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent 247c405 commit 29c63fe

File tree

1 file changed

+48
-17
lines changed

1 file changed

+48
-17
lines changed

drivers/gpu/drm/radeon/radeon_vce.c

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -493,25 +493,35 @@ int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi,
493493
*
494494
* @p: parser context
495495
* @handle: handle to validate
496+
* @allocated: allocated a new handle?
496497
*
497498
* Validates the handle and return the found session index or -EINVAL
498499
* we we don't have another free session index.
499500
*/
500-
int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle)
501+
static int radeon_vce_validate_handle(struct radeon_cs_parser *p,
502+
uint32_t handle, bool *allocated)
501503
{
502504
unsigned i;
503505

506+
*allocated = false;
507+
504508
/* validate the handle */
505509
for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
506-
if (atomic_read(&p->rdev->vce.handles[i]) == handle)
510+
if (atomic_read(&p->rdev->vce.handles[i]) == handle) {
511+
if (p->rdev->vce.filp[i] != p->filp) {
512+
DRM_ERROR("VCE handle collision detected!\n");
513+
return -EINVAL;
514+
}
507515
return i;
516+
}
508517
}
509518

510519
/* handle not found try to alloc a new one */
511520
for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
512521
if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) {
513522
p->rdev->vce.filp[i] = p->filp;
514523
p->rdev->vce.img_size[i] = 0;
524+
*allocated = true;
515525
return i;
516526
}
517527
}
@@ -529,29 +539,32 @@ int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle)
529539
int radeon_vce_cs_parse(struct radeon_cs_parser *p)
530540
{
531541
int session_idx = -1;
532-
bool destroyed = false;
542+
bool destroyed = false, created = false, allocated = false;
533543
uint32_t tmp, handle = 0;
534544
uint32_t *size = &tmp;
535-
int i, r;
545+
int i, r = 0;
536546

537547
while (p->idx < p->chunk_ib->length_dw) {
538548
uint32_t len = radeon_get_ib_value(p, p->idx);
539549
uint32_t cmd = radeon_get_ib_value(p, p->idx + 1);
540550

541551
if ((len < 8) || (len & 3)) {
542552
DRM_ERROR("invalid VCE command length (%d)!\n", len);
543-
return -EINVAL;
553+
r = -EINVAL;
554+
goto out;
544555
}
545556

546557
if (destroyed) {
547558
DRM_ERROR("No other command allowed after destroy!\n");
548-
return -EINVAL;
559+
r = -EINVAL;
560+
goto out;
549561
}
550562

551563
switch (cmd) {
552564
case 0x00000001: // session
553565
handle = radeon_get_ib_value(p, p->idx + 2);
554-
session_idx = radeon_vce_validate_handle(p, handle);
566+
session_idx = radeon_vce_validate_handle(p, handle,
567+
&allocated);
555568
if (session_idx < 0)
556569
return session_idx;
557570
size = &p->rdev->vce.img_size[session_idx];
@@ -561,6 +574,13 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
561574
break;
562575

563576
case 0x01000001: // create
577+
created = true;
578+
if (!allocated) {
579+
DRM_ERROR("Handle already in use!\n");
580+
r = -EINVAL;
581+
goto out;
582+
}
583+
564584
*size = radeon_get_ib_value(p, p->idx + 8) *
565585
radeon_get_ib_value(p, p->idx + 10) *
566586
8 * 3 / 2;
@@ -578,12 +598,12 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
578598
r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9,
579599
*size);
580600
if (r)
581-
return r;
601+
goto out;
582602

583603
r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11,
584604
*size / 3);
585605
if (r)
586-
return r;
606+
goto out;
587607
break;
588608

589609
case 0x02000001: // destroy
@@ -594,44 +614,55 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
594614
r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
595615
*size * 2);
596616
if (r)
597-
return r;
617+
goto out;
598618
break;
599619

600620
case 0x05000004: // video bitstream buffer
601621
tmp = radeon_get_ib_value(p, p->idx + 4);
602622
r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
603623
tmp);
604624
if (r)
605-
return r;
625+
goto out;
606626
break;
607627

608628
case 0x05000005: // feedback buffer
609629
r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
610630
4096);
611631
if (r)
612-
return r;
632+
goto out;
613633
break;
614634

615635
default:
616636
DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
617-
return -EINVAL;
637+
r = -EINVAL;
638+
goto out;
618639
}
619640

620641
if (session_idx == -1) {
621642
DRM_ERROR("no session command at start of IB\n");
622-
return -EINVAL;
643+
r = -EINVAL;
644+
goto out;
623645
}
624646

625647
p->idx += len / 4;
626648
}
627649

628-
if (destroyed) {
629-
/* IB contains a destroy msg, free the handle */
650+
if (allocated && !created) {
651+
DRM_ERROR("New session without create command!\n");
652+
r = -ENOENT;
653+
}
654+
655+
out:
656+
if ((!r && destroyed) || (r && allocated)) {
657+
/*
658+
* IB contains a destroy msg or we have allocated an
659+
* handle and got an error, anyway free the handle
660+
*/
630661
for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
631662
atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0);
632663
}
633664

634-
return 0;
665+
return r;
635666
}
636667

637668
/**

0 commit comments

Comments
 (0)