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