Re: [PATCH v4 1/3] drm/sched: cache the timeline name to fix a use-after-free
From: Tvrtko Ursulin
Date: Tue Sep 08 2026 - 13:18:12 EST
On 07/09/2026 13:28, Tvrtko Ursulin wrote:
On 07/09/2026 12:06, Tvrtko Ursulin wrote:
On 07/09/2026 11:47, Philipp Stanner wrote:
On Mon, 2026-09-07 at 11:28 +0100, Tvrtko Ursulin wrote:
[…]
How did the others fix that?
Combination of kfree_rcu, synchronize_rcu and storing the name in an
object protected by those:
[…]
For the scheduler (nouveau_sched_destroy()) the same, kfree_rcu.
That makes scheduler timeline name vfunc safe:
static const char *drm_sched_fence_get_timeline_name(struct dma_fence *f)
{
struct drm_sched_fence *fence = to_drm_sched_fence(f);
return (const char *)fence->sched->name;
sched is then RCU protected. sched->name is already static so not a concern.
As you say nouveau_sched_fini() only tears down the scheduler after
fences have been signaled it seems adding two new kfree_rcu make is safe.
I don't see how any RCU mechanism would make anything here safe.
As long as ops->release is implemented, ops will never be set to NULL,
(with or without RCU) – so everyone who holds a reference to finished-
fence can still run into drm_sched_fence_get_timeline_name() and cause
UAF on the sched pointer *and* the name pointer.
Moreover, all of this falls apart should the driver unload.
So I maintain the position that we only get it right by having the
signaled-bit be the decoupling point.
Or am I missing something?
The driver fixes you asked about and I listed work(ed) in the context of 506aa8b02a8d ("dma-fence: Add safe access helpers and document the rules"). In that "world" it would have been safe. Did 035219a760ed ("dma-buf: dma-fence: Fix potential NULL pointer dereference") break those fixes a bit?
I can try my IGT and see..
With RCU frees in xe it is harder to hit it reliably for KASAN to notice. Guess I would need to have a way to flush the RCU callbacks from IGT but I did not bother with that, it seemed easier to check the returned name. Since it is not returning "detached-driver" / "detached- timeline" post signalling that proves things are indeed broken:
$ sudo tests/xe_sync_file
IGT-Version: 2.5-ge37a85b91 (x86_64) (Linux: 7.3.0-rc1+ x86_64)
Using IGT_SRANDOM=1788784104 for randomisation
Opened device: /dev/dri/card0
Starting subtest: sync_file_race
[2178.517756] (xe_sync_file:10970) CRITICAL: Test assertion failure function test_race, file ../tests/intel/xe_sync_file.c:130:
[2178.517790] (xe_sync_file:10970) CRITICAL: Failed assertion: ! strcmp(driver_name, "detached-driver")
Stack trace:
#0 ../lib/igt_core.c:2089 __igt_fail_assert()
#1 ../tests/intel/xe_sync_file.c:155 __igt_unique____real_main136()
#2 ../tests/intel/xe_sync_file.c:136 main()
#3 ../sysdeps/nptl/libc_start_call_main.h:83 __libc_start_call_main()
#4 ../csu/libc-start.c:128 __libc_start_main@@GLIBC_2.34()
#5 [_start+0x25]
Subtest sync_file_race failed.
**** DEBUG ****
[2177.516393] (xe_sync_file:10970) DEBUG: 'drm_sched'/'rcs16' = 1
[2178.517745] (xe_sync_file:10970) DEBUG: 'drm_sched'/'rcs16' = 1
[2178.517756] (xe_sync_file:10970) CRITICAL: Test assertion failure function test_race, file ../tests/intel/xe_sync_file.c:130:
[2178.517790] (xe_sync_file:10970) CRITICAL: Failed assertion: ! strcmp(driver_name, "detached-driver")
[2178.518762] (xe_sync_file:10970) igt_core-INFO: Stack trace:
[2178.523313] (xe_sync_file:10970) igt_core-INFO: #0 ../lib/ igt_core.c:2089 __igt_fail_assert()
[2178.523428] (xe_sync_file:10970) igt_core-INFO: #1 ../tests/intel/ xe_sync_file.c:155 __igt_unique____real_main136()
[2178.523436] (xe_sync_file:10970) igt_core-INFO: #2 ../tests/intel/ xe_sync_file.c:136 main()
[2178.564635] (xe_sync_file:10970) igt_core-INFO: #3 ../sysdeps/nptl/ libc_start_call_main.h:83 __libc_start_call_main()
[2178.564690] (xe_sync_file:10970) igt_core-INFO: #4 ../csu/libc- start.c:128 __libc_start_main@@GLIBC_2.34()
[2178.564892] (xe_sync_file:10970) igt_core-INFO: #5 [_start+0x25]
**** END ****
Subtest sync_file_race: FAIL (1.054s)
I'll copy you on the updated IGT for reference.
For reference Intel's CI managed to catch the UAF using the test I re-posted yesterday:
https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_15796/shard-bmg-9/igt@xe_sync_file@sync_file_race.html
<6> [107.688696] [IGT] xe_sync_file: executing
<6> [107.711053] [IGT] xe_sync_file: starting subtest sync_file_race
<4> [108.719407] Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b: 0000 [#1] SMP NOPTI
<4> [108.730119] CPU: 11 UID: 0 PID: 4227 Comm: xe_sync_file Tainted: G S U 7.3.0-rc2-lgci-xe-xe-5698-547f981c369d4b8ad-debug+ #1 PREEMPT(lazy)
<4> [108.743915] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER
<4> [108.748699] Hardware name: ASUS System Product Name/PRIME Z790-P WIFI, BIOS 1645 03/15/2024
<4> [108.757038] RIP: 0010:strnlen+0x17/0x50
<4> [108.760873] Code: 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 48 8d 14 37 48 89 f8 48 85 f6 75 0b eb 2d 48 83 c0 01 48 39 c2 74 13 <80> 38 00 75 f2 48 29 f8 31 d2 31 f6 31 ff c3 cc cc cc cc 48 89 d0
<4> [108.779603] RSP: 0018:ffffc9000414fcc8 EFLAGS: 00010202
<4> [108.784827] RAX: 6b6b6b6b6b6b6b6b RBX: 0000000000000050 RCX: 0000000000000000
<4> [108.791954] RDX: 6b6b6b6b6b6b6b8b RSI: 0000000000000020 RDI: 6b6b6b6b6b6b6b6b
<4> [108.799079] RBP: ffffc9000414fd90 R08: 0000000000000000 R09: 0000000000000000
<4> [108.806201] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8881098231a0
<4> [108.813329] R13: 0000000000000020 R14: ffff88816a833ab8 R15: 6b6b6b6b6b6b6b6b
<4> [108.820454] FS: 00007de5028bebc0(0000) GS:ffff8888d5fdb000(0000) knlGS:0000000000000000
<4> [108.828530] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4> [108.834268] CR2: 00007de5028bc000 CR3: 000000012c9b7001 CR4: 0000000000f72ef0
<4> [108.841396] PKRU: 55555554
<4> [108.844104] Call Trace:
<4> [108.846554] <TASK>
<4> [108.848656] ? sync_file_ioctl+0x1ed/0x750
<4> [108.852754] ? sync_file_ioctl+0x153/0x750
<4> [108.856850] __x64_sys_ioctl+0xa5/0x100
<4> [108.860691] x64_sys_call+0x2b5/0x27e0
<4> [108.864439] do_syscall_64+0xea/0x670
<4> [108.868101] ? do_syscall_64+0x224/0x670
<4> [108.872024] ? trace_hardirqs_on_prepare+0xcb/0xf0
<4> [108.876812] ? do_syscall_64+0x224/0x670
<4> [108.880736] ? trace_hardirqs_on_prepare+0xcb/0xf0
<4> [108.885522] ? trace_hardirqs_off_finish+0xc7/0xe0
<4> [108.890307] ? do_syscall_64+0x58/0x670
<4> [108.894143] entry_SYSCALL_64_after_hwframe+0x76/0x7e
<4> [108.899190] RIP: 0033:0x7de504724f1d
<4> [108.902764] Code: 04 25 28 00 00 00 48 89 45 c8 31 c0 48 8d 45 10 c7 45 b0 10 00 00 00 48 89 45 b8 48 8d 45 d0 48 89 45 c0 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1a 48 8b 45 c8 64 48 2b 04 25 28 00 00 00
<4> [108.921497] RSP: 002b:00007ffdc9fd5e50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
<4> [108.929059] RAX: ffffffffffffffda RBX: 00007ffdc9fd5fd8 RCX: 00007de504724f1d
<4> [108.936182] RDX: 00007ffdc9fd5ee0 RSI: 00000000c0383e04 RDI: 0000000000000006
<4> [108.943310] RBP: 00007ffdc9fd5ea0 R08: 0000000000000000 R09: 0000000000000000
<4> [108.950435] R10: 00007ffdc9fd5f60 R11: 0000000000000246 R12: 00007ffdc9fd5ee0
<4> [108.957558] R13: 00000000c0383e04 R14: 0000000000000006 R15: 0000000000000005
<4> [108.964686] </TASK>
Regards,
Tvrtko