⬢ DragonFlyBSD Kernel Audit
DF-4447 / fix.diff
← back to finding ↓ download raw
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)