[PATCH i-g-t 3/3] tests/intel/gem_mmap_offset: Introduce mmap-unmap test

Krzysztof Niemiec krzysztof.niemiec at intel.com
Wed Aug 14 13:24:04 UTC 2024


Introduce the mmap-unmap test, which creates two adjacent VMAs, and
checks whether a fault in the first one results in a page table UAF if
the second one is being concurrently freed.

Signed-off-by: Krzysztof Niemiec <krzysztof.niemiec at intel.com>
---
 tests/intel/gem_mmap_offset.c | 113 ++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/tests/intel/gem_mmap_offset.c b/tests/intel/gem_mmap_offset.c
index 95e1b2106..eb6732b7c 100644
--- a/tests/intel/gem_mmap_offset.c
+++ b/tests/intel/gem_mmap_offset.c
@@ -64,6 +64,7 @@
  * SUBTEST: pf-nonblock
  * SUBTEST: ptrace
  * SUBTEST: mmap-boundaries
+ * SUBTEST: mmap-unmap
  *
  */
 
@@ -1014,6 +1015,110 @@ static void test_mmap_boundaries(int i915, struct gem_memory_region *r)
 	}
 }
 
+static void __test_mmap_unmap(int i915, struct gem_memory_region *r,
+			      int limit, uint64_t obj_size, uint64_t map_addr,
+			      uint64_t map_size, uint64_t poke_addr, int flags,
+			      bool is_main)
+{
+	struct drm_i915_gem_mmap_offset mmap_offset_arg = { };
+	uint32_t handle;
+
+	handle = gem_create(i915, obj_size);
+	handle = gem_create_in_memory_region_list(i915, obj_size, 0, &r->ci, 1);
+
+	mmap_offset_arg.handle = handle;
+	mmap_offset_arg.flags = flags;
+	mmap_offset_ioctl(i915, &mmap_offset_arg);
+
+	for (int i = 0; i < limit; i++) {
+		void *errp;
+		int err;
+
+		errp = mmap((void *)map_addr,
+			    map_size,
+			    PROT_READ | PROT_WRITE,
+			    MAP_SHARED | MAP_FIXED_NOREPLACE,
+			    i915,
+			    mmap_offset_arg.offset);
+
+		if (is_main)
+			*(volatile char *)(poke_addr - SZ_1K);
+
+		igt_assert_f(errp != MAP_FAILED, "Failed to map\n");
+
+		err = munmap((void *)map_addr, map_size);
+		igt_assert_f(err >= 0, "Failed to unmap\n");
+	}
+}
+
+struct flipper_thread_args {
+	int i915;
+	struct gem_memory_region *r;
+	int limit;
+	uint64_t map_addr;
+	uint64_t map_size;
+	uint64_t flags;
+};
+
+static void *flipper_thread_fn(void *data)
+{
+	struct flipper_thread_args *args;
+
+	args = data;
+	__test_mmap_unmap(args->i915,
+			  args->r,
+			  args->limit,
+			  args->map_size, /* obj_size == map_size in flipper */
+			  args->map_addr,
+			  args->map_size,
+			  args->map_addr,  /* we ignore the poke in flipper thread */
+			  args->flags,
+			  false
+			  );
+	return NULL;
+}
+
+/* This test's failure is detected by checking the dmesg. */
+
+static void test_mmap_unmap(int i915, int limit, struct gem_memory_region *r)
+{
+	struct flipper_thread_args data;
+	pthread_t flipper_thread;
+
+	uint64_t flipper_map_addr;
+	uint64_t flipper_map_size;
+	uint64_t main_map_size;
+	uint64_t main_map_addr;
+	uint64_t poke_addr;
+	uint64_t obj_size;
+
+	flipper_map_addr = 0x8000000000;
+	flipper_map_size = SZ_2M;
+	main_map_size = SZ_128M - SZ_512K;
+	main_map_addr = flipper_map_addr - main_map_size;
+	poke_addr = flipper_map_addr;
+	obj_size = 1060 * SZ_1M;
+
+	data.i915 = i915;
+	data.r = r;
+	data.limit = limit;
+	data.map_addr = flipper_map_addr;
+	data.map_size = flipper_map_size;
+
+	for_each_mmap_offset_type(i915, t) {
+		int err;
+
+		data.flags = t->type;
+		err = pthread_create(&flipper_thread, NULL, flipper_thread_fn, &data);
+		igt_assert_f(err == 0, "Failed to create flipper\n");
+
+		__test_mmap_unmap(i915, r, limit, obj_size, main_map_addr,
+				  main_map_size, poke_addr, t->type, true);
+
+		pthread_join(flipper_thread, NULL);
+	}
+}
+
 static int mmap_gtt_version(int i915)
 {
 	int gtt_version = -1;
@@ -1115,6 +1220,14 @@ igt_main
 		}
 	}
 
+	igt_describe("Check for UAF if one VMA faults while an adjacent one unmaps");
+	igt_subtest_with_dynamic("mmap-unmap") {
+		for_each_memory_region(r, i915) {
+			igt_dynamic_f("%s", r->name)
+				test_mmap_unmap(i915, 10000, r);
+		}
+	}
+
 	igt_fixture {
 		drm_close_driver(i915);
 	}
-- 
2.45.2



More information about the igt-dev mailing list