DF-1725 / harness.c
/* * DF-1725 - radeon_cs.c heap OOB read in radeon_cs_packet_next_reloc * via non-4-aligned chunk_relocs length_dw. * * Vulnerable code: * sys/dev/drm/radeon/radeon_cs.c:89 p->nrelocs = chunk->length_dw / 4; * sys/dev/drm/radeon/radeon_cs.c:90 p->relocs = kvmalloc_array(nrelocs,...); * sys/dev/drm/radeon/radeon_cs.c:865 if (idx >= relocs_chunk->length_dw) return -EINVAL; * sys/dev/drm/radeon/radeon_cs.c:878 *cs_reloc = &p->relocs[(idx / 4)]; * * If chunk_relocs->length_dw is not a multiple of 4 (e.g. 5), then * nrelocs=1 but idx can be 4 (passes the 4<5 check), idx/4 = 1, so * p->relocs[1] is one-past-end OOB. Callers then dereference * reloc->robj/gpu_offset -> wild pointer / info leak. * * DF-1754 is the identical bug in radeon_vce.c:radeon_vce_cs_reloc. * * This harness simulates the index arithmetic and shows the OOB. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> struct radeon_bo_list { uint64_t gpu_offset; uint32_t tiling_flags; void *robj; }; int next_reloc(unsigned length_dw, unsigned idx_in, struct radeon_bo_list **out, struct radeon_bo_list *relocs, unsigned nrelocs) { unsigned idx = idx_in; /* radeon_cs.c:865 / radeon_vce.c:482 */ if (idx >= length_dw) return -1; /* radeon_cs.c:878 / radeon_vce.c:488 */ *out = &relocs[idx / 4]; return 0; } int main(void) { unsigned length_dw = 5; /* non-multiple-of-4 -> nrelocs=1 */ unsigned nrelocs = length_dw / 4; struct radeon_bo_list *relocs = calloc(nrelocs, sizeof(*relocs)); relocs[0].robj = (void *)0xDEADBEEF; printf("=== DF-1725 / DF-1754 radeon relocs idx/4 OOB harness ===\n"); printf("chunk_relocs->length_dw = %u (not multiple of 4)\n", length_dw); printf("p->nrelocs = length_dw/4 = %u (allocated array size)\n", nrelocs); printf("\n"); int oob = 0; for (unsigned idx = 0; idx < length_dw; idx++) { struct radeon_bo_list *r; int rc = next_reloc(length_dw, idx, &r, relocs, nrelocs); if (rc == 0) { unsigned slot = idx / 4; int is_oob = (slot >= nrelocs); printf("idx=%u passes check, indexes relocs[%u]%s (robj=%p)\n", idx, slot, is_oob ? " <-- OOB" : "", r->robj); if (is_oob) oob++; } } printf("\n"); if (oob > 0) { printf("VERDICT: BUG CONFIRMED. length_dw=%u yields nrelocs=%u but\n" " idx=%u (valid per the >= length_dw check) maps to\n" " relocs[%u] which is one-past-end OOB. Wild deref of\n" " reloc->robj/gpu_offset follows. Same root cause as\n" " DF-1754 in radeon_vce.c.\n", length_dw, nrelocs, length_dw-1, (length_dw-1)/4); free(relocs); return 0; } printf("VERDICT: not reproduced.\n"); free(relocs); return 1; } |