lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <06a8cb3f5da040c2a439f9f16d6abcec@huawei.com>
Date: Sat, 31 Jan 2026 10:22:50 +0000
From: "liukai (Y)" <liukai284@...wei.com>
To: "maarten.lankhorst@...ux.intel.com" <maarten.lankhorst@...ux.intel.com>,
	"mripard@...nel.org" <mripard@...nel.org>, "tzimmermann@...e.de"
	<tzimmermann@...e.de>, "airlied@...ux.ie" <airlied@...ux.ie>,
	"daniel@...ll.ch" <daniel@...ll.ch>, "dri-devel@...ts.freedesktop.org"
	<dri-devel@...ts.freedesktop.org>, "linux-kernel@...r.kernel.org"
	<linux-kernel@...r.kernel.org>
CC: "Chenhui (Judy)" <judy.chenhui@...wei.com>, "tanghui (C)"
	<tanghui20@...wei.com>, "Zhangqiao (2012 lab)" <zhangqiao22@...wei.com>
Subject: drm/atomic: KASAN: use-after-free in
 drm_atomic_helper_wait_for_vblanks

Dear Linux Kernel Developers,
I’ve identified a use-after-free (UAF) in the DRM atomic core that
occurs under a specific race condition between a non-blocking (async)
atomic commit and a synchronous one. This can lead to crashes like the
KASAN report below.

Reproduction Scenario:
CPU1: A non-blocking atomic commit (e.g., from drm_mode_page_flip_ioctl)
1. Creates new_crtc_state1 by atomic_duplicate_state()
2. Calls drm_atomic_helper_swap_state(), making crtc->state = new_crtc_state1
3. Queues commit_work for deferred execution (via queue_work)

CPU2: A synchronous atomic commit (e.g., from drm_fb_helper_damage_work)
runs before the async work starts:
1. Calls drm_atomic_get_crtc_state(), which reads crtc->state (= new_crtc_state1) as the current state
2. Duplicates it to create new_crtc_state2
3. Sets its internal crtcs[i].old_crtc_state = crtc->state (to be destroyed later)
4. Calls drm_atomic_helper_swap_state(), making crtcs[i].state_to_destroy = old_crtc_state (= new_crtc_state1)
5. Completes immediately and calls drm_atomic_state_put()
5. During clear, atomic_destroy_state() is called on crtcs[i].state_to_destory → new_crtc_state1 is freed.

CPU3: The deferred commit_work from CPU1 finally runs and accesses
state->crtcs[i].new_crtc_state (which points to the now-freed
new_crtc_state1) → UAF.

The core problem is that the DRM atomic framework assumes crtc_state
objects are only owned by a single drm_atomic_state. But once a state
becomes crtc->state, it can be captured as the "old state" by a
subsequent commit and destroyed prematurely.

The generic atomic helpers do not protect crtc_state across commit
boundaries. This violates the implicit lifetime contract and leads to
UAF in the async path.

Proposed fix:
For non-blocking commits, explicitly take a kref on each new_crtc_state
before queuing the work, and release it only after commit_tail()
completes. This ensures the state remains valid even if another commit
tries to destroy it as its "previous state".

I’m preparing a patch that adds a kref to drm_crtc_state and implements
the refcounting in the async commit path.

Is this the right direction, or should we instead enforce stricter
serialization between async and sync commits on the same CRTC?

==================================================================
BUG: KASAN: use-after-free in drm_atomic_helper_wait_for_vblanks.part.0+0x13f/0x530
Read of size 1 at addr ffff88810f1b7809 by task kworker/u8:0/350737

Call Trace:
 dump_stack+0xbe/0xfd
 print_address_description.constprop.0+0x19/0x170
 ? drm_atomic_helper_wait_for_vblanks.part.0+0x13f/0x530
 __kasan_report.cold+0x6c/0x84
 ? irq_enter_rcu+0x90/0xd0
 ? drm_atomic_helper_wait_for_vblanks.part.0+0x13f/0x530
 kasan_report+0x3a/0x50
 drm_atomic_helper_wait_for_vblanks.part.0+0x13f/0x530
 ? disable_outputs+0x760/0x760
 ? swake_up_all_locked+0x1e/0xc0
 ? _raw_spin_unlock_irqrestore+0xe/0x20
 ? drm_atomic_helper_commit_hw_done+0x276/0x320
 drm_atomic_helper_commit_tail+0x99/0xb0
 commit_tail+0x1f9/0x260
 process_one_work+0x414/0x7e0
 worker_thread+0x93/0x6f0
 ? rescuer_thread+0x7a0/0x7a0
 kthread+0x1cc/0x220
 ? kthread_park+0x150/0x150
 ret_from_fork+0x22/0x30

Allocated by task 487100:
 kasan_save_stack+0x1b/0x40
 __kasan_kmalloc.constprop.0+0xb5/0xe0
 drm_atomic_helper_crtc_duplicate_state+0x4f/0x90
 drm_atomic_get_crtc_state+0xeb/0x1f0
 page_flip_common+0x46/0x1a0
 drm_atomic_helper_page_flip+0x7a/0x130
 drm_mode_page_flip_ioctl+0xb03/0xb70
 drm_ioctl_kernel+0x1b3/0x220
 drm_ioctl+0x453/0x6c0
 __se_sys_ioctl+0x114/0x160
 do_syscall_64+0x2b/0x40
 entry_SYSCALL_64_after_hwframe+0x6c/0xd6

Freed by task 417955:
 kasan_save_stack+0x1b/0x40
 kasan_set_track+0x1c/0x30
 kasan_set_free_info+0x20/0x40
 __kasan_slab_free+0x151/0x180
 kfree+0xa9/0x5c0
 drm_atomic_state_default_clear+0x249/0x710
 __drm_atomic_state_free+0xbf/0x120
 drm_atomic_helper_dirtyfb+0x4d5/0x500
 drm_fb_helper_dirty_work+0x1fe/0x270
 process_one_work+0x414/0x7e0
 worker_thread+0x93/0x6f0
 kthread+0x1cc/0x220
 ret_from_fork+0x22/0x30

The buggy address belongs to the object at ffff88810f1b7800
 which belongs to the cache kmalloc-512 of size 512
The buggy address is located 9 bytes inside of
 512-byte region [ffff88810f1b7800, ffff88810f1b7a00)
The buggy address belongs to the page:
page:00000000ec2ce044 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10f1b4
head:00000000ec2ce044 order:2 compound_mapcount:0 compound_pincount:0
flags: 0x17ffffc0010200(slab|head|node=0|zone=2|lastcpupid=0x1fffff)
raw: 0017ffffc0010200 dead000000000100 dead000000000122 ffff888100043400
raw: 0000000000000000 0000000000100010 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff88810f1b7700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff88810f1b7780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff88810f1b7800: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                      ^
 ffff88810f1b7880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff88810f1b7900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================

Best regards, Liu Kai

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ