From c3bfd738c71b2821fcdc5c769c088578d84dc0a1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2013 11:09:07 -0700 Subject: [PATCH] tests: add gem_reloc_overflow to check wrapping This adds a test to make sure that the execbuffer validation routine is checking for invalid addresses, single entry overflow, and multi-entry wrapping overflow. Signed-off-by: Kees Cook Signed-off-by: Daniel Vetter --- tests/.gitignore | 1 + tests/Makefile.am | 1 + tests/gem_reloc_overflow.c | 154 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 tests/gem_reloc_overflow.c diff --git a/tests/.gitignore b/tests/.gitignore index 7e2d901..fd30412 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -45,6 +45,7 @@ gem_pipe_control_store_loop gem_pread_after_blit gem_pwrite gem_readwrite +gem_reloc_overflow gem_reloc_vs_gpu gem_reg_read gem_render_linear_blits diff --git a/tests/Makefile.am b/tests/Makefile.am index ef68a02..2fddfe8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -84,6 +84,7 @@ TESTS_progs = \ gem_pipe_control_store_loop \ gem_unfence_active_buffers \ gem_unref_active_buffers \ + gem_reloc_overflow \ gem_reloc_vs_gpu \ drm_vma_limiter \ drm_vma_limiter_cpu \ diff --git a/tests/gem_reloc_overflow.c b/tests/gem_reloc_overflow.c new file mode 100644 index 0000000..140b684 --- /dev/null +++ b/tests/gem_reloc_overflow.c @@ -0,0 +1,154 @@ +/* + * Copyright © 2013 Google + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Kees Cook + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" + +/* + * Testcase: Kernel relocation overflows are caught. + */ + +int main(int argc, char *argv[]) +{ + int fd, i, entries, num; + size_t reloc_size; + size_t total_actual = 0; + unsigned int total_unsigned = 0; + int total_signed = 0; + uint32_t *handles; + struct drm_i915_gem_relocation_entry *reloc; + struct drm_i915_gem_exec_object2 *execobjs; + struct drm_i915_gem_execbuffer2 execbuf = { 0 }; + + fd = drm_open_any(); + + /* Create giant reloc buffer area. */ + num = 257; + entries = ((1ULL << 32) / (num - 1)); + reloc_size = entries * sizeof(struct drm_i915_gem_relocation_entry); + reloc = mmap(NULL, reloc_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (reloc == MAP_FAILED) { + perror("mmap"); + return errno; + } + + /* Allocate the handles we'll need to wrap. */ + handles = calloc(num, sizeof(*handles)); + for (i = 0; i < num; i++) { + struct drm_i915_gem_create create_args = { 0 }; + create_args.size = 0x1000; + if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create_args)) { + perror("DRM_IOCTL_I915_GEM_CREATE"); + return errno; + } + handles[i] = create_args.handle; + } + + /* Create relocation objects. */ + execobjs = calloc(num, sizeof(*execobjs)); + execbuf.buffers_ptr = (uintptr_t)execobjs; + + /* Attempt unmapped single entry. */ + execobjs[0].relocation_count = 1; + execobjs[0].relocs_ptr = 0; + execbuf.buffer_count = 1; + + errno = 0; + ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + if (errno != EFAULT) { + perror("DRM_IOCTL_I915_GEM_EXECBUFFER2, invalid address"); + abort(); + } + + /* Attempt single overflowed entry. */ + execobjs[0].relocation_count = (1 << 31); + execobjs[0].relocs_ptr = (uintptr_t)reloc; + execbuf.buffer_count = 1; + + errno = 0; + ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + if (errno != EINVAL) { + perror("DRM_IOCTL_I915_GEM_EXECBUFFER2, single overflow"); + abort(); + } + + /* Attempt wrapped overflow entries. */ + for (i = 0; i < num; i++) { + struct drm_i915_gem_exec_object2 *obj = &execobjs[i]; + obj->handle = handles[i]; + + if (i == num - 1) { + /* Wraps to 1 on last count. */ + obj->relocation_count = 1 - total_unsigned; + obj->relocs_ptr = (uintptr_t)reloc; + } else { + obj->relocation_count = entries; + obj->relocs_ptr = (uintptr_t)reloc; + } + + total_unsigned += obj->relocation_count; + total_signed += obj->relocation_count; + total_actual += obj->relocation_count; + } + execbuf.buffer_count = num; + + errno = 0; + ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + if (errno != EINVAL) { + /* ENOENT means we're subject to wrapping overflow since + * processing has continued into validating buffer contents. + */ + perror("DRM_IOCTL_I915_GEM_EXECBUFFER2, wrap overflow"); + abort(); + } + + if (close(fd)) { + perror("close"); + return errno; + } + + return 0; +} -- 2.7.4