DF-1753 / harness.c
/* * DF-1753 - radeon_vce.c OOB read/write of IB buffer in cs_parse/cs_reloc * via unchecked multi-dword command fields. * * Vulnerable code (sys/dev/drm/radeon/radeon_vce.c): * 565 while (p->idx < p->chunk_ib->length_dw) { * 566 uint32_t len = radeon_get_ib_value(p, p->idx); * 567 uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); // NO bound on idx+1 * ... * 569 if ((len < 8) || (len & 3)) return -EINVAL; * ...cases read p->idx+2, p->idx+3, p->idx+8, p->idx+9, p->idx+10, p->idx+11, p->idx+12 * * radeon_get_ib_value (radeon.h:1098) does NO bounds check on idx against * chunk_ib->length_dw. The len check at 569 only enforces min 8 / multiple * of 4 -- NOT that p->idx + (max field offset) <= length_dw. So a command * whose p->idx is within length_dw but p->idx+12 is past the end reads * OOB from the IB kdata / ib.ptr. * * Additionally radeon_vce_cs_reloc writes p->ib.ptr[lo]/[hi] with caller- * supplied indices (lines 493-494) without verifying lo/hi are within * length_dw -- OOB write into the next radeon_sa_bo object. * * Unprivileged render-node reach. This harness simulates the OOB read. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> uint32_t radeon_get_ib_value_nobound(uint32_t *ib, int idx) { /* radeon.h:1098-1105 -- no bounds check */ return ib[idx]; } int main(void) { int length_dw = 4; uint32_t *ib = calloc(length_dw + 4, sizeof(uint32_t)); /* +4 to detect OOB */ for (int i = 0; i < length_dw + 4; i++) ib[i] = 0xDEAD0000 + i; printf("=== DF-1753 radeon_vce cs_parse OOB IB field read harness ===\n"); printf("chunk_ib->length_dw = %d\n", length_dw); printf("\n"); /* Simulate the parse loop. p->idx=2 is within length_dw (=4). The * command type 0x03000001 (encode) reads idx+8/idx+9/idx+10/idx+11/idx+12 * -- all OOB. */ int p_idx = 2; int max_off = 12; printf("p->idx=%d (within length_dw=%d)\n", p_idx, length_dw); printf("Encode case reads up to p->idx+%d = %d (vs length_dw=%d)\n", max_off, p_idx + max_off, length_dw); printf("OOB field reads:\n"); int oob = 0; for (int off = 0; off <= max_off; off++) { int idx = p_idx + off; uint32_t v = radeon_get_ib_value_nobound(ib, idx); int is_oob = (idx >= length_dw); printf(" radeon_get_ib_value(p, p->idx+%d) = ib[%d] = 0x%08x%s\n", off, idx, v, is_oob ? " <-- OOB" : ""); if (is_oob) oob++; } printf("\n"); if (oob > 0) { printf("VERDICT: BUG CONFIRMED. cs_parse reads IB dwords past\n" " chunk_ib->length_dw (no idx+len/4 <= length_dw check).\n" " Same path writes p->ib.ptr[lo]/[hi] in cs_reloc;\n" " combined, OOB read + OOB write of IB on render node.\n"); free(ib); return 0; } printf("VERDICT: not reproduced.\n"); free(ib); return 1; } |