kms_rotation_crc: Remove useless comments
[platform/upstream/intel-gpu-tools.git] / tests / gem_reloc_overflow.c
1 /*
2  * Copyright © 2013 Google
3  * Copyright © 2013 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Kees Cook <keescook@chromium.org>
26  *    Daniel Vetter <daniel.vetter@ffwll.ch>
27  *    Rafael Barbalho <rafael.barbalho@intel.com>
28  *
29  */
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <stdint.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <inttypes.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <malloc.h>
40 #include <limits.h>
41 #include <sys/ioctl.h>
42 #include <sys/stat.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include "drm.h"
46 #include "ioctl_wrappers.h"
47 #include "intel_chipset.h"
48 #include "drmtest.h"
49 #include "intel_io.h"
50
51 /*
52  * Testcase: Kernel relocation overflows are caught.
53  */
54
55 int fd, entries, num;
56 size_t reloc_size;
57 uint32_t *handles;
58 struct drm_i915_gem_exec_object2 *execobjs;
59 struct drm_i915_gem_execbuffer2 execbuf = { 0 };
60 struct drm_i915_gem_relocation_entry *reloc;
61
62 uint32_t handle;
63 uint32_t batch_handle;
64
65 static void source_offset_tests(int devid, bool reloc_gtt)
66 {
67         struct drm_i915_gem_relocation_entry single_reloc;
68         void *dst_gtt;
69         const char *relocation_type;
70
71         if (reloc_gtt)
72                 relocation_type = "reloc-gtt";
73         else
74                 relocation_type = "reloc-cpu";
75
76         igt_fixture {
77                 handle = gem_create(fd, 8192);
78
79                 execobjs[1].handle = batch_handle;
80                 execobjs[1].relocation_count = 0;
81                 execobjs[1].relocs_ptr = 0;
82
83                 execobjs[0].handle = handle;
84                 execobjs[0].relocation_count = 1;
85                 execobjs[0].relocs_ptr = (uintptr_t) &single_reloc;
86                 execbuf.buffer_count = 2;
87
88                 if (reloc_gtt) {
89                         dst_gtt = gem_mmap(fd, handle, 8192, PROT_READ | PROT_WRITE);
90                         igt_assert(dst_gtt != MAP_FAILED);
91                         gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
92                         memset(dst_gtt, 0, 8192);
93                         munmap(dst_gtt, 8192);
94                         relocation_type = "reloc-gtt";
95                 } else {
96                         relocation_type = "reloc-cpu";
97                 }
98         }
99
100         /* Special tests for 64b relocs. */
101         igt_subtest_f("source-offset-page-stradle-gen8-%s", relocation_type) {
102                 igt_require(intel_gen(devid) >= 8);
103                 single_reloc.offset = 4096 - 4;
104                 single_reloc.delta = 0;
105                 single_reloc.target_handle = handle;
106                 single_reloc.read_domains = I915_GEM_DOMAIN_RENDER;
107                 single_reloc.write_domain = I915_GEM_DOMAIN_RENDER;
108                 single_reloc.presumed_offset = 0;
109
110                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) == 0);
111                 single_reloc.delta = 1024;
112                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) == 0);
113         }
114
115         igt_subtest_f("source-offset-end-gen8-%s", relocation_type) {
116                 igt_require(intel_gen(devid) >= 8);
117                 single_reloc.offset = 8192 - 8;
118                 single_reloc.delta = 0;
119                 single_reloc.target_handle = handle;
120                 single_reloc.read_domains = I915_GEM_DOMAIN_RENDER;
121                 single_reloc.write_domain = I915_GEM_DOMAIN_RENDER;
122                 single_reloc.presumed_offset = 0;
123
124                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) == 0);
125         }
126
127         igt_subtest_f("source-offset-overflow-gen8-%s", relocation_type) {
128                 igt_require(intel_gen(devid) >= 8);
129                 single_reloc.offset = 8192 - 4;
130                 single_reloc.delta = 0;
131                 single_reloc.target_handle = handle;
132                 single_reloc.read_domains = I915_GEM_DOMAIN_RENDER;
133                 single_reloc.write_domain = I915_GEM_DOMAIN_RENDER;
134                 single_reloc.presumed_offset = 0;
135
136                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) != 0);
137                 igt_assert(errno == EINVAL);
138         }
139
140         /* Tests for old 4byte relocs on pre-gen8. */
141         igt_subtest_f("source-offset-end-%s", relocation_type) {
142                 igt_require(intel_gen(devid) < 8);
143                 single_reloc.offset = 8192 - 4;
144                 single_reloc.delta = 0;
145                 single_reloc.target_handle = handle;
146                 single_reloc.read_domains = I915_GEM_DOMAIN_RENDER;
147                 single_reloc.write_domain = I915_GEM_DOMAIN_RENDER;
148                 single_reloc.presumed_offset = 0;
149
150                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) == 0);
151         }
152
153         igt_subtest_f("source-offset-big-%s", relocation_type) {
154                 single_reloc.offset = 8192;
155                 single_reloc.delta = 0;
156                 single_reloc.target_handle = handle;
157                 single_reloc.read_domains = I915_GEM_DOMAIN_RENDER;
158                 single_reloc.write_domain = I915_GEM_DOMAIN_RENDER;
159                 single_reloc.presumed_offset = 0;
160
161                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) != 0);
162                 igt_assert(errno == EINVAL);
163         }
164
165         igt_subtest_f("source-offset-negative-%s", relocation_type) {
166                 single_reloc.offset = (int64_t) -4;
167                 single_reloc.delta = 0;
168                 single_reloc.target_handle = handle;
169                 single_reloc.read_domains = I915_GEM_DOMAIN_RENDER;
170                 single_reloc.write_domain = I915_GEM_DOMAIN_RENDER;
171                 single_reloc.presumed_offset = 0;
172
173                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) != 0);
174                 igt_assert(errno == EINVAL);
175         }
176
177         igt_subtest_f("source-offset-unaligned-%s", relocation_type) {
178                 single_reloc.offset = 1;
179                 single_reloc.delta = 0;
180                 single_reloc.target_handle = handle;
181                 single_reloc.read_domains = I915_GEM_DOMAIN_RENDER;
182                 single_reloc.write_domain = I915_GEM_DOMAIN_RENDER;
183                 single_reloc.presumed_offset = 0;
184
185                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) != 0);
186                 igt_assert(errno == EINVAL);
187         }
188
189         igt_fixture {
190                 gem_close(fd, handle);
191         }
192 }
193
194 static void reloc_tests(void)
195 {
196         int i;
197         unsigned int total_unsigned = 0;
198
199         igt_subtest("invalid-address") {
200                 /* Attempt unmapped single entry. */
201                 execobjs[0].relocation_count = 1;
202                 execobjs[0].relocs_ptr = 0;
203                 execbuf.buffer_count = 1;
204
205                 errno = 0;
206                 ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
207                 igt_assert(errno == EFAULT);
208         }
209
210         igt_subtest("single-overflow") {
211                 /* Attempt single overflowed entry. */
212                 execobjs[0].relocation_count = (1 << 31);
213                 execobjs[0].relocs_ptr = (uintptr_t)reloc;
214                 execbuf.buffer_count = 1;
215
216                 errno = 0;
217                 ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
218                 igt_assert(errno == EINVAL);
219         }
220
221         igt_fixture {
222                 execobjs[0].handle = batch_handle;
223                 execobjs[0].relocation_count = 0;
224                 execobjs[0].relocs_ptr = 0;
225
226                 execbuf.buffer_count = 1;
227
228                 /* Make sure the batch would succeed except for the thing we're
229                  * testing. */
230                 execbuf.batch_start_offset = 0;
231                 execbuf.batch_len = 8;
232                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) == 0);
233         }
234
235         igt_subtest("batch-start-unaligned") {
236                 execbuf.batch_start_offset = 1;
237                 execbuf.batch_len = 8;
238
239                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) != 0);
240                 igt_assert(errno == EINVAL);
241         }
242
243         igt_subtest("batch-end-unaligned") {
244                 execbuf.batch_start_offset = 0;
245                 execbuf.batch_len = 7;
246
247                 igt_assert(ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf) != 0);
248                 igt_assert(errno == EINVAL);
249         }
250
251         igt_fixture {
252                 /* Undo damage for next tests. */
253                 execbuf.batch_start_offset = 0;
254                 execbuf.batch_len = 8;
255         }
256
257         igt_subtest("wrapped-overflow") {
258                 /* Attempt wrapped overflow entries. */
259                 for (i = 0; i < num; i++) {
260                         struct drm_i915_gem_exec_object2 *obj = &execobjs[i];
261                         obj->handle = handles[i];
262
263                         if (i == num - 1) {
264                                 /* Wraps to 1 on last count. */
265                                 obj->relocation_count = 1 - total_unsigned;
266                                 obj->relocs_ptr = (uintptr_t)reloc;
267                         } else {
268                                 obj->relocation_count = entries;
269                                 obj->relocs_ptr = (uintptr_t)reloc;
270                         }
271
272                         total_unsigned += obj->relocation_count;
273                 }
274                 execbuf.buffer_count = num;
275
276                 errno = 0;
277                 ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
278                 igt_assert(errno == EINVAL);
279         }
280 }
281
282 static void buffer_count_tests(void)
283 {
284         igt_subtest("buffercount-overflow") {
285                 for (int i = 0; i < num; i++) {
286                         execobjs[i].relocation_count = 0;
287                         execobjs[i].relocs_ptr = 0;
288                         execobjs[i].handle = handles[i];
289                 }
290
291                 execobjs[0].relocation_count = 0;
292                 execobjs[0].relocs_ptr = 0;
293                 /* We only have num buffers actually, but the overflow will make
294                  * sure we blow up the kernel before we blow up userspace. */
295                 execbuf.buffer_count = num;
296
297                 /* Put a real batch at the end. */
298                 execobjs[num - 1].handle = batch_handle;
299
300                 /* Make sure the basic thing would work first ... */
301                 errno = 0;
302                 ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
303                 igt_assert(errno == 0);
304
305                 /* ... then be evil: Overflow of the pointer table (which has a
306                  * bit of lead datastructures, so no + 1 needed to overflow). */
307                 execbuf.buffer_count = INT_MAX / sizeof(void *);
308
309                 errno = 0;
310                 ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
311                 igt_assert(errno == EINVAL);
312
313                 /* ... then be evil: Copying/allocating the array. */
314                 execbuf.buffer_count = UINT_MAX / sizeof(execobjs[0]) + 1;
315
316                 errno = 0;
317                 ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
318                 igt_assert(errno == EINVAL);
319         }
320 }
321
322 igt_main
323 {
324         int devid = 0;
325
326         igt_fixture {
327                 int ring;
328                 uint32_t batch_data [2] = { MI_NOOP, MI_BATCH_BUFFER_END };
329
330                 fd = drm_open_any();
331
332                 devid = intel_get_drm_devid(fd);
333
334                 /* Create giant reloc buffer area. */
335                 num = 257;
336                 entries = ((1ULL << 32) / (num - 1));
337                 reloc_size = entries * sizeof(struct drm_i915_gem_relocation_entry);
338                 reloc = mmap(NULL, reloc_size, PROT_READ | PROT_WRITE,
339                              MAP_PRIVATE | MAP_ANON, -1, 0);
340                 igt_assert(reloc != MAP_FAILED);
341
342                 /* Allocate the handles we'll need to wrap. */
343                 handles = calloc(num, sizeof(*handles));
344                 for (int i = 0; i < num; i++)
345                         handles[i] = gem_create(fd, 4096);
346
347                 if (intel_gen(devid) >= 6)
348                         ring = I915_EXEC_BLT;
349                 else
350                         ring = 0;
351
352                 /* Create relocation objects. */
353                 execobjs = calloc(num, sizeof(*execobjs));
354                 execbuf.buffers_ptr = (uintptr_t)execobjs;
355                 execbuf.batch_start_offset = 0;
356                 execbuf.batch_len = 8;
357                 execbuf.cliprects_ptr = 0;
358                 execbuf.num_cliprects = 0;
359                 execbuf.DR1 = 0;
360                 execbuf.DR4 = 0;
361                 execbuf.flags = ring;
362                 i915_execbuffer2_set_context_id(execbuf, 0);
363                 execbuf.rsvd2 = 0;
364
365                 batch_handle = gem_create(fd, 4096);
366
367                 gem_write(fd, batch_handle, 0, batch_data, sizeof(batch_data));
368         }
369
370         reloc_tests();
371
372         source_offset_tests(devid, false);
373         source_offset_tests(devid, true);
374
375         buffer_count_tests();
376
377         igt_fixture {
378                 gem_close(fd, batch_handle);
379                 close(fd);
380         }
381 }