DF-1754 / harness.c
/* * DF-1754 - radeon_vce.c OOB read of p->relocs[] and wild pointer deref * via non-multiple-of-4 chunk_relocs length_dw. * * Vulnerable code (sys/dev/drm/radeon/radeon_vce.c): * 470 int radeon_vce_cs_reloc(p, lo, hi, size) { * 482 if (idx >= relocs_chunk->length_dw) return -EINVAL; * 488 reloc = &p->relocs[(idx / 4)]; * 489 start = reloc->gpu_offset; // wild deref if OOB * 490 end = start + radeon_bo_size(reloc->robj); * * nrelocs = chunk_relocs->length_dw / 4 (radeon_cs.c:89, integer division). * For length_dw not a multiple of 4 (e.g. 5): nrelocs=1, idx can be 4 * (passes 4>=5 false), idx/4=1 indexes past the 1-element relocs array. * reloc->robj is then a wild pointer dereferenced at radeon_bo_size(). * * Identical root cause to DF-1725 in radeon_cs.c (same nrelocs arithmetic). * * This harness is the same logic as DF-1725's harness, parameterized for * the radeon_vce path; see DF-1725/harness.c for the full arithmetic. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> struct radeon_bo_list { uint64_t gpu_offset; uint32_t tiling_flags; void *robj; }; int vce_cs_reloc(unsigned length_dw, unsigned idx_in, struct radeon_bo_list **out, struct radeon_bo_list *relocs, unsigned nrelocs) { unsigned idx = idx_in; if (idx >= length_dw) return -1; /* radeon_vce.c:482 */ *out = &relocs[idx / 4]; /* radeon_vce.c:488 */ return 0; } int main(void) { unsigned length_dw = 5; unsigned nrelocs = length_dw / 4; struct radeon_bo_list *relocs = calloc(nrelocs, sizeof(*relocs)); relocs[0].robj = (void*)0xCAFE; printf("=== DF-1754 radeon_vce_cs_reloc idx/4 OOB harness ===\n"); printf("chunk_relocs->length_dw = %u (not multiple of 4)\n", length_dw); printf("p->nrelocs = %u\n", nrelocs); printf("\n"); int oob = 0; for (unsigned idx = 0; idx < length_dw; idx++) { struct radeon_bo_list *r; if (vce_cs_reloc(length_dw, idx, &r, relocs, nrelocs) == 0) { unsigned slot = idx / 4; int is_oob = (slot >= nrelocs); printf("idx=%u -> relocs[%u]%s reloc->robj=%p (wild deref at radeon_bo_size)\n", idx, slot, is_oob ? " <-- OOB" : "", r->robj); if (is_oob) oob++; } } printf("\n"); if (oob > 0) { printf("VERDICT: BUG CONFIRMED. Same root cause as DF-1725:\n" " chunk_relocs->length_dw=%u / 4 = nrelocs=%u, but the\n" " (idx >= length_dw) check at line 482 admits idx=%u,\n" " and relocs[%u] is OOB. Wild deref of reloc->robj.\n", length_dw, nrelocs, length_dw-1, (length_dw-1)/4); free(relocs); return 0; } printf("VERDICT: not reproduced.\n"); free(relocs); return 1; } |