From 8637b407cf1740c52a01b9fc0cf506f31e225151 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 16 Aug 2013 13:29:33 -0700 Subject: [PATCH] drm/i915/vma: Correct use after free in eviction MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The vma will [possibly] be destroyed during unbind in eviction. Immediately after this, we try to delete the list entry. Chris and Ville did the debug on this before I woke up, I just get to take credit for the fix :p For future reference the Oops that Mika reported: [ 403.472448] BUG: unable to handle kernel paging request at 6b6b6b6b [ 403.472473] IP: [] __list_del_entry+0x20/0xe0 [ 403.472514] *pdpt = 000000002e89c001 *pde = 0000000000000000 [ 403.472556] Oops: 0000 [#1] SMP [ 403.472582] Modules linked in: mxm_wmi snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi snd_rawmidi psmouse snd_seq_midi_event snd_seq serio_raw snd_timer snd_seq_device snd soundcore snd_page_alloc wmi bnep rfcomm bluetooth mac_hid parport_pc ppdev lp parport usbhid dm_crypt firewire_ohci firewire_core crc_itu_t i915 drm_kms_helper e1000e ptp drm i2c_algo_bit pps_core xhci_hcd video [ 403.472895] CPU: 2 PID: 1940 Comm: Xorg Not tainted 3.11.0-rc2+ #827 [ 403.472938] Hardware name: /DZ77BH-55K, BIOS BHZ7710H.86A.0070.2012.0416.2117 04/16/2012 [ 403.473002] task: ec866c00 ti: ee6a2000 task.ti: ee6a2000 [ 403.473039] EIP: 0060:[] EFLAGS: 00013202 CPU: 2 [ 403.473078] EIP is at __list_del_entry+0x20/0xe0 [ 403.473109] EAX: f016d9bc EBX: f016d9bc ECX: 6b6b6b6b EDX: 6b6b6b6b [ 403.473151] ESI: 00000000 EDI: ee6a3c90 EBP: ee6a3c60 ESP: ee6a3c48 [ 403.473193] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 403.473230] CR0: 80050033 CR2: 6b6b6b6b CR3: 2ec43000 CR4: 001407f0 [ 403.473271] Stack: [ 403.473285] f63b2ff0 f61f98c0 f61f8000 f016d9bc 00000000 f016d9bc ee6a3cac f8519a4a [ 403.473347] 00000000 00000000 10000000 f61f8000 0100a000 10000000 00000001 008ca000 [ 403.473410] f64ee840 f61f98c0 f016d9bc f016dcec ee6a3c98 ee6a3c98 f61f98c0 dcc58f00 [ 403.473472] Call Trace: [ 403.473509] [] i915_gem_evict_something+0x17a/0x2d0 [i915] [ 403.473567] [] i915_gem_object_pin+0x271/0x660 [i915] [ 403.473622] [] ? i915_ggtt_clear_range+0x20/0x20 [i915] [ 403.473676] [] i915_gem_object_pin_to_display_plane+0xda/0x190 [i915] [ 403.473742] [] intel_pin_and_fence_fb_obj+0xba/0x140 [i915] [ 403.473800] [] intel_gen7_queue_flip+0x30/0x1c0 [i915] [ 403.473856] [] intel_crtc_page_flip+0x1a0/0x320 [i915] [ 403.473911] [] ? drm_framebuffer_reference+0x39/0x80 [drm] [ 403.473965] [] drm_mode_page_flip_ioctl+0x28b/0x320 [drm] [ 403.474018] [] drm_ioctl+0x4b8/0x560 [drm] [ 403.474064] [] ? drm_mode_gamma_get_ioctl+0xd0/0xd0 [drm] [ 403.474113] [] ? do_sync_read+0x6a/0xa0 [ 403.474154] [] ? drm_copy_field+0x80/0x80 [drm] [ 403.474193] [] do_vfs_ioctl+0x7c/0x5b0 [ 403.474228] [] ? vfs_read+0xef/0x160 [ 403.474263] [] ? ktime_get_ts+0x4b/0x120 [ 403.474298] [] SyS_ioctl+0x97/0xa0 [ 403.474330] [] sysenter_do_call+0x12/0x22 [ 403.474364] Code: 55 f4 8b 45 f8 e9 75 ff ff ff 90 55 89 e5 53 83 ec 14 8b 08 8b 50 04 81 f9 00 01 10 00 74 24 81 fa 00 02 20 00 0f 84 8e 00 00 00 <8b> 1a 39 d8 75 62 8b 59 04 39 d8 75 35 89 51 04 89 0a 83 c4 14 [ 403.474566] EIP: [] __list_del_entry+0x20/0xe0 SS:ESP 0068:ee6a3c48 [ 403.476513] CR2: 000000006b6b6b6b v2: Missed the drm_object_unreference use after free (Ville) Daniel Vetter writes: Reported-by: Mika Kuoppala Cc: Ville Syrjälä Cc: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson [danvet: Add the Oops from Mika to the commit message.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_evict.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 8787588..91b7001 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -136,14 +136,17 @@ found: /* Unbinding will emit any required flushes */ while (!list_empty(&eviction_list)) { + struct drm_gem_object *obj; vma = list_first_entry(&eviction_list, struct i915_vma, exec_list); + + obj = &vma->obj->base; + list_del_init(&vma->exec_list); if (ret == 0) ret = i915_vma_unbind(vma); - list_del_init(&vma->exec_list); - drm_gem_object_unreference(&vma->obj->base); + drm_gem_object_unreference(obj); } return ret; -- 2.7.4