[Intel-gfx] [PATCH 01/11] drm/i915/selftests: Prevent background reaping of active objects

Mika Kuoppala mika.kuoppala at linux.intel.com
Mon Jul 9 13:48:31 UTC 2018


Chris Wilson <chris at chris-wilson.co.uk> writes:

> igt_mmap_offset_exhaustion() wants to test what happens when the mmap
> space is filled with zombie objects, objects discarded by userspace but
> still active on the GPU. As they are only protected by the active
> reference, we have to be certain that active reference is kept while we
> peek into our dangling pointer. That active reference should not be
> freed until we retire, but we do that retirement from a background
> thread. This leaves us with a subtle timing problem, exacerbated and
> highlighted by KASAN:
>
> <3>[  132.380399] BUG: KASAN: use-after-free in drm_gem_create_mmap_offset+0x8c/0xd0
> <3>[  132.380430] Read of size 8 at addr ffff8801e13245f8 by task drv_selftest/5822
>
> <4>[  132.380470] CPU: 0 PID: 5822 Comm: drv_selftest Tainted: G     U            4.18.0-rc3-g7ae7763aa2be-kasan_48+ #1
> <4>[  132.380473] Hardware name: Dell Inc. XPS 8300  /0Y2MRG, BIOS A06 10/17/2011
> <4>[  132.380475] Call Trace:
> <4>[  132.380481]  dump_stack+0x7c/0xbb
> <4>[  132.380487]  print_address_description+0x65/0x270
> <4>[  132.380493]  kasan_report+0x25b/0x380
> <4>[  132.380497]  ? drm_gem_create_mmap_offset+0x8c/0xd0
> <4>[  132.380503]  drm_gem_create_mmap_offset+0x8c/0xd0
> <4>[  132.380584]  i915_gem_object_create_mmap_offset+0x6d/0x100 [i915]
> <4>[  132.380650]  igt_mmap_offset_exhaustion+0x462/0x940 [i915]
> <4>[  132.380714]  ? i915_gem_close_object+0x740/0x740 [i915]
> <4>[  132.380784]  ? igt_gem_huge+0x269/0x3d0 [i915]
> <4>[  132.380865]  __i915_subtests+0x5a/0x160 [i915]
> <4>[  132.380936]  __run_selftests+0x1a2/0x2f0 [i915]
> <4>[  132.381008]  i915_live_selftests+0x4e/0x80 [i915]
> <4>[  132.381071]  i915_pci_probe+0xd8/0x1b0 [i915]
> <4>[  132.381077]  pci_device_probe+0x1c5/0x3a0
> <4>[  132.381087]  driver_probe_device+0x6b6/0xcb0
> <4>[  132.381094]  __driver_attach+0x22d/0x2c0
> <4>[  132.381100]  ? driver_probe_device+0xcb0/0xcb0
> <4>[  132.381103]  bus_for_each_dev+0x113/0x1a0
> <4>[  132.381108]  ? check_flags.part.24+0x450/0x450
> <4>[  132.381112]  ? subsys_dev_iter_exit+0x10/0x10
> <4>[  132.381123]  bus_add_driver+0x38b/0x6e0
> <4>[  132.381131]  driver_register+0x189/0x400
> <4>[  132.381136]  ? 0xffffffffc12d8000
> <4>[  132.381140]  do_one_initcall+0xa0/0x4c0
> <4>[  132.381145]  ? initcall_blacklisted+0x180/0x180
> <4>[  132.381152]  ? do_init_module+0x4a/0x54c
> <4>[  132.381156]  ? rcu_lockdep_current_cpu_online+0xdc/0x130
> <4>[  132.381161]  ? kasan_unpoison_shadow+0x30/0x40
> <4>[  132.381169]  do_init_module+0x1b5/0x54c
> <4>[  132.381177]  load_module+0x619e/0x9b70
> <4>[  132.381202]  ? module_frob_arch_sections+0x20/0x20
> <4>[  132.381211]  ? vfs_read+0x257/0x2f0
> <4>[  132.381214]  ? vfs_read+0x257/0x2f0
> <4>[  132.381221]  ? kernel_read+0x8b/0x130
> <4>[  132.381231]  ? copy_strings_kernel+0x120/0x120
> <4>[  132.381244]  ? __se_sys_finit_module+0x17c/0x1a0
> <4>[  132.381248]  __se_sys_finit_module+0x17c/0x1a0
> <4>[  132.381252]  ? __ia32_sys_init_module+0xa0/0xa0
> <4>[  132.381261]  ? __se_sys_newstat+0x77/0xd0
> <4>[  132.381265]  ? cp_new_stat+0x590/0x590
> <4>[  132.381269]  ? kmem_cache_free+0x2f0/0x340
> <4>[  132.381285]  do_syscall_64+0x97/0x400
> <4>[  132.381292]  entry_SYSCALL_64_after_hwframe+0x49/0xbe
> <4>[  132.381295] RIP: 0033:0x7eff4af46839
> <4>[  132.381297] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 1f f6 2c 00 f7 d8 64 89 01 48
> <4>[  132.381426] RSP: 002b:00007ffcd84f4cf8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
> <4>[  132.381432] RAX: ffffffffffffffda RBX: 000055dfdeb429a0 RCX: 00007eff4af46839
> <4>[  132.381435] RDX: 0000000000000000 RSI: 000055dfdeb43670 RDI: 0000000000000004
> <4>[  132.381437] RBP: 000055dfdeb43670 R08: 0000000000000004 R09: 0000000000000000
> <4>[  132.381440] R10: 00007ffcd84f4e60 R11: 0000000000000246 R12: 0000000000000000
> <4>[  132.381442] R13: 000055dfdeb3bec0 R14: 0000000000000000 R15: 000000000000003b
>
> <3>[  132.381466] Allocated by task 5822:
> <4>[  132.381485]  kmem_cache_alloc+0xdf/0x2e0
> <4>[  132.381546]  i915_gem_object_create_internal+0x24/0x1e0 [i915]
> <4>[  132.381609]  igt_mmap_offset_exhaustion+0x257/0x940 [i915]
> <4>[  132.381677]  __i915_subtests+0x5a/0x160 [i915]
> <4>[  132.381742]  __run_selftests+0x1a2/0x2f0 [i915]
> <4>[  132.381806]  i915_live_selftests+0x4e/0x80 [i915]
> <4>[  132.381865]  i915_pci_probe+0xd8/0x1b0 [i915]
> <4>[  132.381868]  pci_device_probe+0x1c5/0x3a0
> <4>[  132.381871]  driver_probe_device+0x6b6/0xcb0
> <4>[  132.381874]  __driver_attach+0x22d/0x2c0
> <4>[  132.381877]  bus_for_each_dev+0x113/0x1a0
> <4>[  132.381880]  bus_add_driver+0x38b/0x6e0
> <4>[  132.381884]  driver_register+0x189/0x400
> <4>[  132.381886]  do_one_initcall+0xa0/0x4c0
> <4>[  132.381889]  do_init_module+0x1b5/0x54c
> <4>[  132.381892]  load_module+0x619e/0x9b70
> <4>[  132.381895]  __se_sys_finit_module+0x17c/0x1a0
> <4>[  132.381898]  do_syscall_64+0x97/0x400
> <4>[  132.381901]  entry_SYSCALL_64_after_hwframe+0x49/0xbe
>
> <3>[  132.381914] Freed by task 150:
> <4>[  132.381931]  kmem_cache_free+0xb7/0x340
> <4>[  132.381995]  __i915_gem_free_objects+0x875/0xf50 [i915]
> <4>[  132.382054]  __i915_gem_free_work+0x69/0xb0 [i915]
> <4>[  132.382058]  process_one_work+0x78b/0x1740
> <4>[  132.382061]  worker_thread+0x82/0xb80
> <4>[  132.382064]  kthread+0x30c/0x3d0
> <4>[  132.382067]  ret_from_fork+0x3a/0x50
>
> <3>[  132.382081] The buggy address belongs to the object at ffff8801e1324500
>                    which belongs to the cache drm_i915_gem_object of size 1168
> <3>[  132.382133] The buggy address is located 248 bytes inside of
>                    1168-byte region [ffff8801e1324500, ffff8801e1324990)
> <3>[  132.382179] The buggy address belongs to the page:
> <0>[  132.382202] page:ffffea000784c800 count:1 mapcount:0 mapping:ffff8801dedf6500 index:0xffff8801e1323ec0 compound_mapcount: 0
> <0>[  132.382251] flags: 0x8000000000008100(slab|head)
> <1>[  132.382274] raw: 8000000000008100 ffff8801d6317440 ffff8801d6317440 ffff8801dedf6500
> <1>[  132.382307] raw: ffff8801e1323ec0 0000000000140013 00000001ffffffff 0000000000000000
> <1>[  132.382339] page dumped because: kasan: bad access detected
>
> <3>[  132.382373] Memory state around the buggy address:
> <3>[  132.382395]  ffff8801e1324480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> <3>[  132.382426]  ffff8801e1324500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> <3>[  132.382457] >ffff8801e1324580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> <3>[  132.382488]                                                                 ^
> <3>[  132.382517]  ffff8801e1324600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> <3>[  132.382548]  ffff8801e1324680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>
> This patch tricks the system into running without the background retire
> thread, until after we finish the test. The only reaping should then be
> performed by the mmap offset routine to reclaim the space as required.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
>  .../gpu/drm/i915/selftests/i915_gem_object.c  | 19 ++++++++++++++++++-
>  1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> index f4a5099c75b5..d77acf4cc439 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
> @@ -507,6 +507,15 @@ static int igt_mmap_offset_exhaustion(void *arg)
>  	u64 hole_start, hole_end;
>  	int loop, err;
>  
> +	/* Disable background reaper */

disable|enable_reaper, but I have cream in my coffee
and perhaps we do it if another test ever wants this.

> +	mutex_lock(&i915->drm.struct_mutex);
> +	if (!i915->gt.active_requests++)
> +		i915_gem_unpark(i915);
> +	mutex_unlock(&i915->drm.struct_mutex);
> +	cancel_delayed_work_sync(&i915->gt.retire_work);

As the retire work can yield on mutex, you could
lift it inside mutex and do GEM_BUG_ON(!cancel_delayed...),
if you want to enforce the coupling.

Reviewed-by: Mika Kuoppala <mika.kuoppala at linux.intel.com>

> +	cancel_delayed_work_sync(&i915->gt.idle_work);
> +	GEM_BUG_ON(!i915->gt.awake);
> +
>  	/* Trim the device mmap space to only a page */
>  	memset(&resv, 0, sizeof(resv));
>  	drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
> @@ -515,7 +524,7 @@ static int igt_mmap_offset_exhaustion(void *arg)
>  		err = drm_mm_reserve_node(mm, &resv);
>  		if (err) {
>  			pr_err("Failed to trim VMA manager, err=%d\n", err);
> -			return err;
> +			goto out_park;
>  		}
>  		break;
>  	}
> @@ -576,6 +585,7 @@ static int igt_mmap_offset_exhaustion(void *arg)
>  			goto err_obj;
>  		}
>  
> +		/* NB we rely on the _active_ reference to access obj now */
>  		GEM_BUG_ON(!i915_gem_object_is_active(obj));
>  		err = i915_gem_object_create_mmap_offset(obj);
>  		if (err) {
> @@ -587,6 +597,13 @@ static int igt_mmap_offset_exhaustion(void *arg)
>  
>  out:
>  	drm_mm_remove_node(&resv);
> +out_park:
> +	mutex_lock(&i915->drm.struct_mutex);
> +	if (--i915->gt.active_requests)
> +		queue_delayed_work(i915->wq, &i915->gt.retire_work, 0);
> +	else
> +		queue_delayed_work(i915->wq, &i915->gt.idle_work, 0);
> +	mutex_unlock(&i915->drm.struct_mutex);
>  	return err;
>  err_obj:
>  	i915_gem_object_put(obj);
> -- 
> 2.18.0


More information about the Intel-gfx mailing list