Skip to content

Commit 764e77d

Browse files
committed
Merge tag 'locking-core-2026-06-14' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip
Pull locking updates from Ingo Molnar: "Futex updates: - Optimize futex hash bucket access patterns (Peter Zijlstra) - Large series to address the robust futex unlock race for real, by Thomas Gleixner: "The robust futex unlock mechanism is racy in respect to the clearing of the robust_list_head::list_op_pending pointer because unlock and clearing the pointer are not atomic. The race window is between the unlock and clearing the pending op pointer. If the task is forced to exit in this window, exit will access a potentially invalid pending op pointer when cleaning up the robust list. That happens if another task manages to unmap the object containing the lock before the cleanup, which results in an UAF. In the worst case this UAF can lead to memory corruption when unrelated content has been mapped to the same address by the time the access happens. User space can't solve this problem without help from the kernel. This series provides the kernel side infrastructure to help it along: 1) Combined unlock, pointer clearing, wake-up for the contended case 2) VDSO based unlock and pointer clearing helpers with a fix-up function in the kernel when user space was interrupted within the critical section. ... with help by André Almeida: - Add a note about robust list race condition (André Almeida) - Add self-tests for robust release operations (André Almeida) Context analysis updates: - Implement context analysis for 'struct rt_mutex'. (Bart Van Assche) - Bump required Clang version to 23 (Marco Elver) Guard infrastructure updates: - Series to remove NULL check from unconditional guards (Dmitry Ilvokhin) Lockdep updates: - Restore self-test migrate_disable() and sched_rt_mutex state on PREEMPT_RT (Karl Mehltretter) Membarriers updates: - Use per-CPU mutexes for targeted commands (Aniket Gattani) - Modernize membarrier_global_expedited with cleanup guards (Aniket Gattani) - Add rseq stress test for CFS throttle interactions (Aniket Gattani) percpu-rwsems updates: - Extract __percpu_up_read() to optimize inlining overhead (Dmitry Ilvokhin) Seqlocks updates: - Allow UBSAN_ALIGNMENT to fail optimizing (Heiko Carstens) Lock tracing: - Add contended_release tracepoint to sleepable locks such as mutexes, percpu-rwsems, rtmutexes, rwsems and semaphores (Dmitry Ilvokhin) MAINTAINERS updates: - MAINTAINERS: Add RUST [SYNC] entry (Boqun Feng) Misc updates and fixes by Randy Dunlap, YE WEI-HONG, Fabricio Parra, Dmitry Ilvokhin and Peter Zijlstra" * tag 'locking-core-2026-06-14' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip: (36 commits) locking: Add contended_release tracepoint to sleepable locks locking/percpu-rwsem: Extract __percpu_up_read() tracing/lock: Remove unnecessary linux/sched.h include futex: Optimize futex hash bucket access patterns rust: sync: completion: Mark inline complete_all and wait_for_completion MAINTAINERS: Add RUST [SYNC] entry cleanup: Specify nonnull argument index selftests: futex: Add tests for robust release operations Documentation: futex: Add a note about robust list race condition x86/vdso: Implement __vdso_futex_robust_try_unlock() x86/vdso: Prepare for robust futex unlock support futex: Provide infrastructure to plug the non contended robust futex unlock race futex: Add robust futex unlock IP range futex: Add support for unlocking robust futexes futex: Cleanup UAPI defines x86: Select ARCH_MEMORY_ORDER_TSO uaccess: Provide unsafe_atomic_store_release_user() futex: Provide UABI defines for robust list entry modifiers futex: Move futex related mm_struct data into a struct futex: Make futex_mm_init() void ...
2 parents 186d3c4 + 4f070cc commit 764e77d

71 files changed

Lines changed: 2402 additions & 491 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Documentation/dev-tools/context-analysis.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ features. To enable for Clang, configure the kernel with::
1717

1818
CONFIG_WARN_CONTEXT_ANALYSIS=y
1919

20-
The feature requires Clang 22 or later.
20+
The feature requires Clang 23 or later.
2121

2222
The analysis is *opt-in by default*, and requires declaring which modules and
2323
subsystems should be analyzed in the respective `Makefile`::

Documentation/locking/robust-futex-ABI.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ On removal:
153153
3) release the futex lock, and
154154
4) clear the 'lock_op_pending' word.
155155

156+
Please note that the removal of a robust futex purely in userspace is
157+
racy. Refer to the next chapter to learn more and how to avoid this.
158+
156159
On exit, the kernel will consider the address stored in
157160
'list_op_pending' and the address of each 'lock word' found by walking
158161
the list starting at 'head'. For each such address, if the bottom 30
@@ -182,3 +185,44 @@ any point:
182185
When the kernel sees a list entry whose 'lock word' doesn't have the
183186
current threads TID in the lower 30 bits, it does nothing with that
184187
entry, and goes on to the next entry.
188+
189+
Robust release is racy
190+
----------------------
191+
192+
The removal of a robust futex from the list is racy when doing it solely in
193+
userspace. Quoting Thomas Gleixner for the explanation:
194+
195+
The robust futex unlock mechanism is racy in respect to the clearing of the
196+
robust_list_head::list_op_pending pointer because unlock and clearing the
197+
pointer are not atomic. The race window is between the unlock and clearing
198+
the pending op pointer. If the task is forced to exit in this window, exit
199+
will access a potentially invalid pending op pointer when cleaning up the
200+
robust list. That happens if another task manages to unmap the object
201+
containing the lock before the cleanup, which results in an UAF. In the
202+
worst case this UAF can lead to memory corruption when unrelated content
203+
has been mapped to the same address by the time the access happens.
204+
205+
A full in-depth analysis can be read at
206+
https://lore.kernel.org/lkml/20260316162316.356674433@kernel.org/
207+
208+
To overcome that, the kernel needs to participate in the lock release operation.
209+
This ensures that the release happens "atomically" with regard to releasing
210+
the lock and removing the address from ``list_op_pending``. If the release is
211+
interrupted by a signal, the kernel will also verify if it interrupted the
212+
release operation.
213+
214+
For the contended unlock case, where other threads are waiting for the lock
215+
release, there's the ``FUTEX_ROBUST_UNLOCK`` operation feature flag for the
216+
``futex()`` system call, which must be used with one of the following
217+
operations: ``FUTEX_WAKE``, ``FUTEX_WAKE_BITSET`` or ``FUTEX_UNLOCK_PI``.
218+
The kernel will release the lock (set the futex word to zero), clean the
219+
``list_op_pending`` field. Then, it will proceed with the normal wake path.
220+
221+
For the non-contended path, there's still a race between checking the futex word
222+
and clearing the ``list_op_pending`` field. To solve this without the need of a
223+
complete system call, userspace should call the virtual syscall
224+
``__vdso_futex_robust_listXX_try_unlock()`` (where XX is either 32 or 64,
225+
depending on the size of the pointer). If the vDSO call succeeds, it means that
226+
it released the lock and cleared ``list_op_pending``. If it fails, that means
227+
that there are waiters for this lock and a call to ``futex()`` syscall with
228+
``FUTEX_ROBUST_UNLOCK`` is needed.

Documentation/locking/robust-futexes.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ time, the kernel checks this user-space list: are there any robust futex
9494
locks to be cleaned up?
9595

9696
In the common case, at do_exit() time, there is no list registered, so
97-
the cost of robust futexes is just a simple current->robust_list != NULL
97+
the cost of robust futexes is just a current->futex.robust_list != NULL
9898
comparison. If the thread has registered a list, then normally the list
9999
is empty. If the thread/process crashed or terminated in some incorrect
100100
way then the list might be non-empty: in this case the kernel carefully
@@ -178,9 +178,9 @@ one to query the registered list pointer::
178178
size_t __user *len_ptr);
179179

180180
List registration is very fast: the pointer is simply stored in
181-
current->robust_list. [Note that in the future, if robust futexes become
182-
widespread, we could extend sys_clone() to register a robust-list head
183-
for new threads, without the need of another syscall.]
181+
current->futex.robust_list. [Note that in the future, if robust futexes
182+
become widespread, we could extend sys_clone() to register a robust-list
183+
head for new threads, without the need of another syscall.]
184184

185185
So there is virtually zero overhead for tasks not using robust futexes,
186186
and even for robust futex users, there is only one extra syscall per

MAINTAINERS

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23482,6 +23482,20 @@ S: Maintained
2348223482
T: git https://github.com/Rust-for-Linux/linux.git rust-analyzer-next
2348323483
F: scripts/generate_rust_analyzer.py
2348423484

23485+
RUST [SYNC]
23486+
M: Boqun Feng <boqun@kernel.org>
23487+
M: Gary Guo <gary@garyguo.net>
23488+
M: Alice Ryhl <aliceryhl@google.com>
23489+
R: Lyude Paul <lyude@redhat.com>
23490+
R: Daniel Almeida <daniel.almeida@collabora.com>
23491+
R: "Onur Özkan" <work@onurozkan.dev>
23492+
L: linux-kernel@vger.kernel.org
23493+
L: rust-for-linux@vger.kernel.org
23494+
S: Maintained
23495+
T: git git://git.kernel.org/pub/scm/linux/kernel/git/boqun/linux.git rust-sync
23496+
F: rust/kernel/sync.rs
23497+
F: rust/kernel/sync/
23498+
2348523499
RXRPC SOCKETS (AF_RXRPC)
2348623500
M: David Howells <dhowells@redhat.com>
2348723501
M: Marc Dionne <marc.dionne@auristor.com>

arch/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ config ARCH_32BIT_OFF_T
403403
config ARCH_32BIT_USTAT_F_TINODE
404404
bool
405405

406+
# Selected by architectures with Total Store Order (TSO)
407+
config ARCH_MEMORY_ORDER_TSO
408+
bool
409+
406410
config HAVE_ASM_MODVERSIONS
407411
bool
408412
help

arch/um/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \
7171
-D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \
7272
-idirafter $(objtree)/include -D__KERNEL__ -D__UM_HOST__ \
7373
-include $(srctree)/include/linux/compiler-version.h \
74-
-include $(srctree)/include/linux/kconfig.h
74+
-include $(srctree)/include/linux/kconfig.h \
75+
-idirafter $(ARCH_DIR)/include/generated
7576

7677
#This will adjust *FLAGS accordingly to the platform.
7778
include $(srctree)/$(ARCH_DIR)/Makefile-os-Linux

arch/um/include/asm/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ generic-y += module.h
1616
generic-y += module.lds.h
1717
generic-y += parport.h
1818
generic-y += percpu.h
19+
generic-y += percpu_types.h
1920
generic-y += preempt.h
2021
generic-y += ring_buffer.h
2122
generic-y += runtime-const.h

arch/x86/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ config X86
113113
select ARCH_HAS_ZONE_DMA_SET if EXPERT
114114
select ARCH_HAVE_NMI_SAFE_CMPXCHG
115115
select ARCH_HAVE_EXTRA_ELF_NOTES
116+
select ARCH_MEMORY_ORDER_TSO
116117
select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE
117118
select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
118119
select ARCH_MIGHT_HAVE_PC_PARPORT
@@ -235,6 +236,7 @@ config X86
235236
select HAVE_EFFICIENT_UNALIGNED_ACCESS
236237
select HAVE_EISA if X86_32
237238
select HAVE_EXIT_THREAD
239+
select HAVE_FUTEX_ROBUST_UNLOCK
238240
select HAVE_GENERIC_TIF_BITS
239241
select HAVE_GUP_FAST
240242
select HAVE_FENTRY if X86_64 || DYNAMIC_FTRACE
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <vdso/futex.h>
3+
4+
/*
5+
* Assembly template for the try unlock functions. The basic functionality is:
6+
*
7+
* mov esi, %eax Move the TID into EAX
8+
* xor %ecx, %ecx Clear ECX
9+
* lock_cmpxchgl %ecx, (%rdi) Attempt the TID -> 0 transition
10+
* .Lcs_start: Start of the critical section
11+
* jnz .Lcs_end If cmpxchl failed jump to the end
12+
* .Lcs_success: Start of the success section
13+
* movq %rcx, (%rdx) Set the pending op pointer to 0
14+
* .Lcs_end: End of the critical section
15+
*
16+
* .Lcs_start and .Lcs_end establish the critical section range. .Lcs_success is
17+
* technically not required, but there for illustration, debugging and testing.
18+
*
19+
* When CONFIG_COMPAT is enabled then the 64-bit VDSO provides two functions.
20+
* One for the regular 64-bit sized pending operation pointer and one for a
21+
* 32-bit sized pointer to support gaming emulators.
22+
*
23+
* The 32-bit VDSO provides only the one for 32-bit sized pointers.
24+
*/
25+
#define __stringify_1(x...) #x
26+
#define __stringify(x...) __stringify_1(x)
27+
28+
#define LABEL(prefix, which) __stringify(prefix##_try_unlock_cs_##which:)
29+
30+
#define JNZ_END(prefix) "jnz " __stringify(prefix) "_try_unlock_cs_end\n"
31+
32+
#define CLEAR_POPQ "movq %[zero], %a[pop]\n"
33+
#define CLEAR_POPL "movl %k[zero], %a[pop]\n"
34+
35+
#define futex_robust_try_unlock(prefix, clear_pop, __lock, __tid, __pop)\
36+
({ \
37+
asm volatile ( \
38+
" \n" \
39+
" lock cmpxchgl %k[zero], %a[lock] \n" \
40+
" \n" \
41+
LABEL(prefix, start) \
42+
" \n" \
43+
JNZ_END(prefix) \
44+
" \n" \
45+
LABEL(prefix, success) \
46+
" \n" \
47+
clear_pop \
48+
" \n" \
49+
LABEL(prefix, end) \
50+
: [tid] "+&a" (__tid) \
51+
: [lock] "D" (__lock), \
52+
[pop] "d" (__pop), \
53+
[zero] "r" (0UL) \
54+
: "memory" \
55+
); \
56+
__tid; \
57+
})
58+
59+
#ifdef __x86_64__
60+
__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
61+
{
62+
return futex_robust_try_unlock(__futex_list64, CLEAR_POPQ, lock, tid, pop);
63+
}
64+
#endif /* __x86_64__ */
65+
66+
#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT)
67+
__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
68+
{
69+
return futex_robust_try_unlock(__futex_list32, CLEAR_POPL, lock, tid, pop);
70+
}
71+
#endif /* CONFIG_X86_32 || CONFIG_COMPAT */

arch/x86/entry/vdso/vdso32/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
vdsos-y := 32
88

99
# Files to link into the vDSO:
10-
vobjs-y := note.o vclock_gettime.o vgetcpu.o
11-
vobjs-y += system_call.o sigreturn.o
10+
vobjs-y := note.o vclock_gettime.o vgetcpu.o
11+
vobjs-y += system_call.o sigreturn.o
12+
vobjs-$(CONFIG_FUTEX_ROBUST_UNLOCK) += vfutex.o
1213

1314
# Compilation flags
1415
flags-y := -DBUILD_VDSO32 -m32 -mregparm=0

0 commit comments

Comments
 (0)