DF-4447 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | diff --git a/amdgpu_vce.c b/amdgpu_vce.c index 5519d2f..b26e228 100644 --- a/amdgpu_vce.c +++ b/amdgpu_vce.c @@ -791,8 +791,23 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx); uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1); + /* DF-4447: loop 2 re-reads len/cmd from dwords that + * amdgpu_vce_cs_reloc() may have patched in a previous + * iteration; make sure the declared length covers every + * field this loop reads or patches, so a relocation can + * never alias the next command's header. */ + if ((len < 8) || (len & 3)) { + DRM_ERROR("invalid VCE command length (%d)!\n", len); + r = -EINVAL; + goto out; + } + switch (cmd) { case 0x00000001: /* session */ + if (len < 12) { + r = -EINVAL; + goto out; + } handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); session_idx = amdgpu_vce_validate_handle(p, handle, &allocated); @@ -804,11 +819,19 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x00000002: /* task info */ + if (len < 32) { + r = -EINVAL; + goto out; + } fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6); bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7); break; case 0x01000001: /* create */ + if (len < 44) { + r = -EINVAL; + goto out; + } created |= 1 << session_idx; if (destroyed & (1 << session_idx)) { destroyed &= ~(1 << session_idx); @@ -850,6 +873,10 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x03000001: /* encode */ + if (len < 52) { /* patches idx+9..idx+12 */ + r = -EINVAL; + goto out; + } r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, *size, 0); if (r) @@ -866,6 +893,10 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x05000001: /* context buffer */ + if (len < 16) { /* patches idx+2..idx+3 */ + r = -EINVAL; + goto out; + } r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, *size * 2, 0); if (r) @@ -873,6 +904,10 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x05000004: /* video bitstream buffer */ + if (len < 20) { /* reads idx+4, patches idx+2..3 */ + r = -EINVAL; + goto out; + } tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, tmp, bs_idx); @@ -881,6 +916,10 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x05000005: /* feedback buffer */ + if (len < 16) { + r = -EINVAL; + goto out; + } r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, 4096, fb_idx); if (r) @@ -888,6 +927,10 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x0500000d: /* MV buffer */ + if (len < 36) { /* patches idx+2..3, idx+7..8 */ + r = -EINVAL; + goto out; + } r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, *size, 0); if (r) |