Skip to content

Commit 9f909e2

Browse files
committed
drm/i915: Implement vm_ops->access for gdb access into mmaps
gdb uses ptrace() to peek and poke bytes of the target's address space. The driver must implement an vm_ops->access() handler or else gdb will be unable to inspect the pointer and report it as out-of-bounds. Worse than useless as it causes immediate suspicion of the valid GTT pointer, distracting the poor programmer trying to find his bug. v2: Write-protect readonly objects (Matthew). Testcase: igt/gem_mmap_gtt/ptrace Testcase: igt/gem_mmap_offset/ptrace Suggested-by: Kristian H. Kristensen <[email protected]> Signed-off-by: Chris Wilson <[email protected]> Cc: Matthew Auld <[email protected]> Cc: Joonas Lahtinen <[email protected]> Cc: Maciej Patelczyk <[email protected]> Cc: Kristian H. Kristensen <[email protected]> Reviewed-by: Matthew Auld <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent a211da9 commit 9f909e2

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

drivers/gpu/drm/i915/gem/i915_gem_mman.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,38 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
396396
return i915_error_to_vmf_fault(ret);
397397
}
398398

399+
static int
400+
vm_access(struct vm_area_struct *area, unsigned long addr,
401+
void *buf, int len, int write)
402+
{
403+
struct i915_mmap_offset *mmo = area->vm_private_data;
404+
struct drm_i915_gem_object *obj = mmo->obj;
405+
void *vaddr;
406+
407+
if (i915_gem_object_is_readonly(obj) && write)
408+
return -EACCES;
409+
410+
addr -= area->vm_start;
411+
if (addr >= obj->base.size)
412+
return -EINVAL;
413+
414+
/* As this is primarily for debugging, let's focus on simplicity */
415+
vaddr = i915_gem_object_pin_map(obj, I915_MAP_FORCE_WC);
416+
if (IS_ERR(vaddr))
417+
return PTR_ERR(vaddr);
418+
419+
if (write) {
420+
memcpy(vaddr + addr, buf, len);
421+
__i915_gem_object_flush_map(obj, addr, len);
422+
} else {
423+
memcpy(buf, vaddr + addr, len);
424+
}
425+
426+
i915_gem_object_unpin_map(obj);
427+
428+
return len;
429+
}
430+
399431
void __i915_gem_object_release_mmap_gtt(struct drm_i915_gem_object *obj)
400432
{
401433
struct i915_vma *vma;
@@ -745,12 +777,14 @@ static void vm_close(struct vm_area_struct *vma)
745777

746778
static const struct vm_operations_struct vm_ops_gtt = {
747779
.fault = vm_fault_gtt,
780+
.access = vm_access,
748781
.open = vm_open,
749782
.close = vm_close,
750783
};
751784

752785
static const struct vm_operations_struct vm_ops_cpu = {
753786
.fault = vm_fault_cpu,
787+
.access = vm_access,
754788
.open = vm_open,
755789
.close = vm_close,
756790
};

drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,129 @@ static int igt_mmap(void *arg)
952952
return 0;
953953
}
954954

955+
static const char *repr_mmap_type(enum i915_mmap_type type)
956+
{
957+
switch (type) {
958+
case I915_MMAP_TYPE_GTT: return "gtt";
959+
case I915_MMAP_TYPE_WB: return "wb";
960+
case I915_MMAP_TYPE_WC: return "wc";
961+
case I915_MMAP_TYPE_UC: return "uc";
962+
default: return "unknown";
963+
}
964+
}
965+
966+
static bool can_access(const struct drm_i915_gem_object *obj)
967+
{
968+
unsigned int flags =
969+
I915_GEM_OBJECT_HAS_STRUCT_PAGE | I915_GEM_OBJECT_HAS_IOMEM;
970+
971+
return i915_gem_object_type_has(obj, flags);
972+
}
973+
974+
static int __igt_mmap_access(struct drm_i915_private *i915,
975+
struct drm_i915_gem_object *obj,
976+
enum i915_mmap_type type)
977+
{
978+
struct i915_mmap_offset *mmo;
979+
unsigned long __user *ptr;
980+
unsigned long A, B;
981+
unsigned long x, y;
982+
unsigned long addr;
983+
int err;
984+
985+
memset(&A, 0xAA, sizeof(A));
986+
memset(&B, 0xBB, sizeof(B));
987+
988+
if (!can_mmap(obj, type) || !can_access(obj))
989+
return 0;
990+
991+
mmo = mmap_offset_attach(obj, type, NULL);
992+
if (IS_ERR(mmo))
993+
return PTR_ERR(mmo);
994+
995+
addr = igt_mmap_node(i915, &mmo->vma_node, 0, PROT_WRITE, MAP_SHARED);
996+
if (IS_ERR_VALUE(addr))
997+
return addr;
998+
ptr = (unsigned long __user *)addr;
999+
1000+
err = __put_user(A, ptr);
1001+
if (err) {
1002+
pr_err("%s(%s): failed to write into user mmap\n",
1003+
obj->mm.region->name, repr_mmap_type(type));
1004+
goto out_unmap;
1005+
}
1006+
1007+
intel_gt_flush_ggtt_writes(&i915->gt);
1008+
1009+
err = access_process_vm(current, addr, &x, sizeof(x), 0);
1010+
if (err != sizeof(x)) {
1011+
pr_err("%s(%s): access_process_vm() read failed\n",
1012+
obj->mm.region->name, repr_mmap_type(type));
1013+
goto out_unmap;
1014+
}
1015+
1016+
err = access_process_vm(current, addr, &B, sizeof(B), FOLL_WRITE);
1017+
if (err != sizeof(B)) {
1018+
pr_err("%s(%s): access_process_vm() write failed\n",
1019+
obj->mm.region->name, repr_mmap_type(type));
1020+
goto out_unmap;
1021+
}
1022+
1023+
intel_gt_flush_ggtt_writes(&i915->gt);
1024+
1025+
err = __get_user(y, ptr);
1026+
if (err) {
1027+
pr_err("%s(%s): failed to read from user mmap\n",
1028+
obj->mm.region->name, repr_mmap_type(type));
1029+
goto out_unmap;
1030+
}
1031+
1032+
if (x != A || y != B) {
1033+
pr_err("%s(%s): failed to read/write values, found (%lx, %lx)\n",
1034+
obj->mm.region->name, repr_mmap_type(type),
1035+
x, y);
1036+
err = -EINVAL;
1037+
goto out_unmap;
1038+
}
1039+
1040+
out_unmap:
1041+
vm_munmap(addr, obj->base.size);
1042+
return err;
1043+
}
1044+
1045+
static int igt_mmap_access(void *arg)
1046+
{
1047+
struct drm_i915_private *i915 = arg;
1048+
struct intel_memory_region *mr;
1049+
enum intel_region_id id;
1050+
1051+
for_each_memory_region(mr, i915, id) {
1052+
struct drm_i915_gem_object *obj;
1053+
int err;
1054+
1055+
obj = i915_gem_object_create_region(mr, PAGE_SIZE, 0);
1056+
if (obj == ERR_PTR(-ENODEV))
1057+
continue;
1058+
1059+
if (IS_ERR(obj))
1060+
return PTR_ERR(obj);
1061+
1062+
err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_GTT);
1063+
if (err == 0)
1064+
err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_WB);
1065+
if (err == 0)
1066+
err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_WC);
1067+
if (err == 0)
1068+
err = __igt_mmap_access(i915, obj, I915_MMAP_TYPE_UC);
1069+
1070+
i915_gem_object_put(obj);
1071+
if (err)
1072+
return err;
1073+
}
1074+
1075+
return 0;
1076+
}
1077+
9551078
static int __igt_mmap_gpu(struct drm_i915_private *i915,
9561079
struct drm_i915_gem_object *obj,
9571080
enum i915_mmap_type type)
@@ -1229,6 +1352,7 @@ int i915_gem_mman_live_selftests(struct drm_i915_private *i915)
12291352
SUBTEST(igt_smoke_tiling),
12301353
SUBTEST(igt_mmap_offset_exhaustion),
12311354
SUBTEST(igt_mmap),
1355+
SUBTEST(igt_mmap_access),
12321356
SUBTEST(igt_mmap_revoke),
12331357
SUBTEST(igt_mmap_gpu),
12341358
};

0 commit comments

Comments
 (0)