1 /* 2 * Copyright © 2012 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Daniel Vetter <daniel.vetter@ffwll.ch> 25 * 26 */ 27 28 /** @file gem_unfence_active_buffers.c 29 * 30 * Testcase: Check for use-after free in the fence stealing code 31 * 32 * If we're stealing the fence of a active object where the active list is the 33 * only thing holding a reference, we need to be careful not to access the old 34 * object we're stealing the fence from after that reference has been dropped by 35 * retire_requests. 36 * 37 * Note that this needs slab poisoning enabled in the kernel to reliably hit the 38 * problem - the race window is too small. 39 */ 40 41 #include "igt.h" 42 #include <stdlib.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <fcntl.h> 46 #include <inttypes.h> 47 #include <errno.h> 48 #include <sys/stat.h> 49 #include <sys/time.h> 50 #include <stdbool.h> 51 #include "drm.h" 52 #include "intel_bufmgr.h" 53 54 IGT_TEST_DESCRIPTION("Check for use-after-free in the fence stealing code."); 55 56 static drm_intel_bufmgr *bufmgr; 57 struct intel_batchbuffer *batch; 58 uint32_t devid; 59 60 #define TEST_SIZE (1024*1024) 61 #define TEST_STRIDE (4*1024) 62 63 uint32_t data[TEST_SIZE/4]; 64 65 igt_simple_main 66 { 67 int i, ret, fd, num_fences; 68 drm_intel_bo *busy_bo, *test_bo; 69 uint32_t tiling = I915_TILING_X; 70 71 igt_skip_on_simulation(); 72 73 for (i = 0; i < 1024*256; i++) 74 data[i] = i; 75 76 fd = drm_open_driver(DRIVER_INTEL); 77 igt_require_gem(fd); 78 79 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); 80 drm_intel_bufmgr_gem_enable_reuse(bufmgr); 81 devid = intel_get_drm_devid(fd); 82 batch = intel_batchbuffer_alloc(bufmgr, devid); 83 84 igt_info("filling ring\n"); 85 busy_bo = drm_intel_bo_alloc(bufmgr, "busy bo bo", 16*1024*1024, 4096); 86 87 for (i = 0; i < 250; i++) { 88 BLIT_COPY_BATCH_START(0); 89 OUT_BATCH((3 << 24) | /* 32 bits */ 90 (0xcc << 16) | /* copy ROP */ 91 2*1024*4); 92 OUT_BATCH(0 << 16 | 1024); 93 OUT_BATCH((2048) << 16 | (2048)); 94 OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); 95 OUT_BATCH(0 << 16 | 0); 96 OUT_BATCH(2*1024*4); 97 OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0); 98 ADVANCE_BATCH(); 99 100 if (batch->gen >= 6) { 101 BEGIN_BATCH(3, 0); 102 OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); 103 OUT_BATCH(0); 104 OUT_BATCH(0); 105 ADVANCE_BATCH(); 106 } 107 } 108 intel_batchbuffer_flush(batch); 109 110 num_fences = gem_available_fences(fd); 111 igt_info("creating havoc on %i fences\n", num_fences); 112 113 for (i = 0; i < num_fences*2; i++) { 114 test_bo = drm_intel_bo_alloc(bufmgr, "test_bo", 115 TEST_SIZE, 4096); 116 ret = drm_intel_bo_set_tiling(test_bo, &tiling, TEST_STRIDE); 117 igt_assert(ret == 0); 118 119 drm_intel_bo_disable_reuse(test_bo); 120 121 BLIT_COPY_BATCH_START(0); 122 OUT_BATCH((3 << 24) | /* 32 bits */ 123 (0xcc << 16) | /* copy ROP */ 124 TEST_STRIDE); 125 OUT_BATCH(0 << 16 | 0); 126 OUT_BATCH((1) << 16 | (1)); 127 OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); 128 OUT_BATCH(0 << 16 | 0); 129 OUT_BATCH(TEST_STRIDE); 130 OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, 0, 0); 131 ADVANCE_BATCH(); 132 intel_batchbuffer_flush(batch); 133 igt_info("test bo offset: %#lx\n", test_bo->offset); 134 135 drm_intel_bo_unreference(test_bo); 136 } 137 138 /* launch a few batchs to ensure the damaged slab objects get reused. */ 139 for (i = 0; i < 10; i++) { 140 BLIT_COPY_BATCH_START(0); 141 OUT_BATCH((3 << 24) | /* 32 bits */ 142 (0xcc << 16) | /* copy ROP */ 143 2*1024*4); 144 OUT_BATCH(0 << 16 | 1024); 145 OUT_BATCH((1) << 16 | (1)); 146 OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); 147 OUT_BATCH(0 << 16 | 0); 148 OUT_BATCH(2*1024*4); 149 OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0); 150 ADVANCE_BATCH(); 151 152 if (batch->gen >= 8) { 153 BEGIN_BATCH(3, 0); 154 OUT_BATCH(XY_SETUP_CLIP_BLT_CMD); 155 OUT_BATCH(0); 156 OUT_BATCH(0); 157 ADVANCE_BATCH(); 158 } 159 } 160 intel_batchbuffer_flush(batch); 161 } 162