mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v8 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
@ 2026-08-21 21:50 André Almeida
  2026-08-21 21:50 ` [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support André Almeida
                   ` (3 more replies)
  0 siblings, 4 replies; 16+ messages in thread
From: André Almeida @ 2026-08-21 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida

Hi folks,

This is my take on implementing the new vDSO for unlocking a robust futex in
arm64. If you don't know what's that, Thomas wrote a good summary,
including the motivation for this work and the x86 implementation:

   https://lore.kernel.org/lkml/878qb89g7b.ffs@tglx/

* Testing

There's one selftest proposed [1] that tests precisely if the task is
interrupted during the critical section, if the kernel will clear op_pending
pointer. I've adapted to arm64 [2] and it works as expected. This test is not
being upstreamed right now because it depends on a better way to expose
vdso.so.dbg [3].

I also used gdb to manually check if the address is cleared when the kernel
interrupts the critical section.

Thanks!
	André

[1] https://lore.kernel.org/lkml/20260404093939.7XgeW_54@linutronix.de/
[2] https://lore.kernel.org/lkml/20260529-tonyk-robust_arm-v3-3-a6f02684d4fe@igalia.com/
[3] https://lore.kernel.org/lkml/20260602090536.045586688@kernel.org/

Changes in v8:
- Fix build when CONFIG_FUTEX is disabled
- v7: https://patch.msgid.link/20260728-tonyk-robust_arm-v7-0-40873c377c63@igalia.com

Changes in v7:
- vdso32: Use stlex instead of strex to ensure release semanthics
- vdso32: result reg should use "=&r" clobber
- both: pop_reg will be read afterwards so it was moved to be an input operand,
  with "+Q" clobber"
v6: https://patch.msgid.link/20260720-tonyk-robust_arm-v6-0-7e68c122047e@igalia.com

Changes in v6:
- Reorganized the patchset, better split for helpers functions vs aarch64 vs
arm32 code
- Use "full name" for labels instead of macros
- Completely reworded "Implement __vdso_futex_robust_try_unlock()" to make it
more obvious what's the bug and how does this fix it
v5: https://patch.msgid.link/20260717-tonyk-robust_arm-v5-0-ffd1ad318d17@igalia.com

Changes in v5:
 - Drop unneeded commit "arm64/entry: Unify user mode handling"
 - Replace "_success" with "_start" labels in vdso_futex_robust_unlock_update_ips
 - Added "cc" to the asm clobberlist
v4: https://patch.msgid.link/20260705-tonyk-robust_arm-v4-0-e0fd0fa259d3@igalia.com

Changes in v4:
 - Added commit "arm64/entry: Unify user mode handling"
 - Added missing ifdef FUTEX_ROBUST_UNLOCK guards
 - Fixed the position of _start and _success labels in the critical section
 - Instead of checking the zero flag, check the result register to decide if the
 op_pending needs to be cleared
v3: https://patch.msgid.link/20260529-tonyk-robust_arm-v3-0-a6f02684d4fe@igalia.com

Changes in v3:
 - Change asm to always use x2 to store *pop
 - Fix clang asm errors
 - Moved 32 bit entry point to vdso32/ and use littlearm asm
 - Adapted Sebastians test for arm
v2: https://patch.msgid.link/20260424-tonyk-robust_arm-v2-0-db4e46f752cf@igalia.com

Changes in v2:
 - s/CONFIG_COMPAT/CONFIG_COMPAT_VDSO (Thomas Weißschuh)
 - Fixed linker not finding the symbols (Thomas Weißschuh)
v1: https://patch.msgid.link/20260417-tonyk-robust_arm-v1-0-03aa64e2ff1a@igalia.com

---
André Almeida (4):
      arm64: vdso: Prepare for robust futex unlock support
      arm64: vdso: Implement __vdso_futex_robust_try_unlock()
      arm64: vdso32: Bring vdso32-offsets.h back
      arm64: vdso32: Implement __vdso_futex_robust_try_unlock()

 arch/arm64/Kconfig                    |  1 +
 arch/arm64/Makefile                   |  2 +-
 arch/arm64/include/asm/futex_robust.h | 19 +++++++++++++
 arch/arm64/include/asm/vdso.h         |  3 ++
 arch/arm64/kernel/vdso.c              | 53 ++++++++++++++++++++++++++++++++++-
 arch/arm64/kernel/vdso/Makefile       | 10 +++++++
 arch/arm64/kernel/vdso/vdso.lds.S     |  9 ++++++
 arch/arm64/kernel/vdso/vfutex.c       | 35 +++++++++++++++++++++++
 arch/arm64/kernel/vdso32/Makefile     | 12 ++++++++
 arch/arm64/kernel/vdso32/vdso.lds.S   |  9 ++++++
 arch/arm64/kernel/vdso32/vfutex.c     | 34 ++++++++++++++++++++++
 11 files changed, 185 insertions(+), 2 deletions(-)
---
base-commit: 2be02a7c996aa733bb36e29e07715621b0de9736
change-id: 20260416-tonyk-robust_arm-54ff77d2c4e4

Best regards,
--  
André Almeida <andrealmeid@igalia.com>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support
  2026-08-21 21:50 [PATCH v8 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
@ 2026-08-21 21:50 ` André Almeida
  2026-09-16 14:24   ` Mark Rutland
  2026-08-21 21:50 ` [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 16+ messages in thread
From: André Almeida @ 2026-08-21 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida

To solve the robust futex's list_pending_op clearing race condition,
prepare for implement __vdso_futex_robust_try_unlock() for arm64 with the
following steps:

- Create a helper function that sets the struct futex_mm_data with the
VDSO's labels addresses. The robust futex fixup mechanism needs to
compare the current instruction pointer to the VDSO instructions range.

- Split vdso_mremap() in vdso_mremap() and aarch32_mremap(), this allows
the VDSO to be setup correctly regarding the instructions addresses for
both ABIs when a mremap happens.

- Implement arch_futex_robust_unlock_get_pop() for arm64, checking for r2
and r3 registers values for the fixup function. The role of this registers
is explained in the commit that implement the assembly portion of the VDSO.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
v6:
 - Restructured this commit. Move the arch bits away, kept just the
 generic/helper functions.

v4:
- Guard symbols from vdso.lds.S with ifdef
- drop update_ips() from sigpage remap function

v3:
 - Fix adding vdso base addr twice
 - Call vdso_futex_robust_unlock_update_ips() on remap as well
v2:
 - Fixed linker not finding VDSO symbols
---
---
 arch/arm64/include/asm/futex_robust.h | 19 +++++++++++++++++++
 arch/arm64/kernel/vdso.c              | 27 ++++++++++++++++++++++++++-
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/futex_robust.h b/arch/arm64/include/asm/futex_robust.h
new file mode 100644
index 000000000000..4ff783bb2dc3
--- /dev/null
+++ b/arch/arm64/include/asm/futex_robust.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_FUTEX_ROBUST_H
+#define _ASM_ARM64_FUTEX_ROBUST_H
+
+#include <asm/ptrace.h>
+
+static __always_inline void __user *arm64_futex_robust_unlock_get_pop(struct pt_regs *regs)
+{
+	/*
+	 * w3 stores the result of the stlxr instruction. If it's zero, the then
+	 * the ll/sc cmpxchg succeeded and the pending op pointer needs to be cleared.
+	 */
+	return (regs->user_regs.regs[3]) ? NULL : (void __user *) regs->user_regs.regs[2];
+}
+
+#define arch_futex_robust_unlock_get_pop(regs) \
+	arm64_futex_robust_unlock_get_pop(regs)
+
+#endif /* _ASM_ARM64_FUTEX_ROBUST_H */
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 592dd8668de4..3ef331b5b240 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -11,6 +11,7 @@
 #include <linux/clocksource.h>
 #include <linux/elf.h>
 #include <linux/err.h>
+#include <linux/futex.h>
 #include <linux/errno.h>
 #include <linux/gfp.h>
 #include <linux/kernel.h>
@@ -57,6 +58,22 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
 #endif /* CONFIG_COMPAT_VDSO */
 };
 
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
+					   void *endp)
+{
+	unsigned long start = (unsigned long) startp;
+	unsigned long end = (unsigned long) endp;
+	struct futex_mm_data *fd = &mm->futex;
+
+	futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);
+}
+
+#else
+static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
+					   void *endp)
+#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
+
 static int vdso_mremap(const struct vm_special_mapping *sm,
 		struct vm_area_struct *new_vma)
 {
@@ -162,6 +179,14 @@ static int aarch32_sigpage_mremap(const struct vm_special_mapping *sm,
 	return 0;
 }
 
+static int aarch32_mremap(const struct vm_special_mapping *sm,
+		struct vm_area_struct *new_vma)
+{
+	current->mm->context.vdso = (void *)new_vma->vm_start;
+
+	return 0;
+}
+
 static struct vm_special_mapping aarch32_vdso_maps[] = {
 	[AA32_MAP_VECTORS] = {
 		.name	= "[vectors]", /* ABI */
@@ -174,7 +199,7 @@ static struct vm_special_mapping aarch32_vdso_maps[] = {
 	},
 	[AA32_MAP_VDSO] = {
 		.name = "[vdso]",
-		.mremap = vdso_mremap,
+		.mremap = aarch32_mremap,
 	},
 };
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
  2026-08-21 21:50 [PATCH v8 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
  2026-08-21 21:50 ` [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support André Almeida
@ 2026-08-21 21:50 ` André Almeida
  2026-09-16 14:27   ` Mark Rutland
  2026-08-21 21:50 ` [PATCH v8 3/4] arm64: vdso32: Bring vdso32-offsets.h back André Almeida
  2026-08-21 21:50 ` [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock() André Almeida
  3 siblings, 1 reply; 16+ messages in thread
From: André Almeida @ 2026-08-21 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida

The futex's robust list uAPI has a struct robust_list_head::list_op_pending
pointer used by userspace as a temporary variable while the mutex unlock is
happening. User sets it to the futex address that's about to be released
and removed from the robust list, and list_op_pending is cleared after.
After a thread dies, the kernel checks it's list_op_pending and wakes the
mutex in that address, to prevent starvation, and flip a bit in the mutex
word (FUTEX_OWNER_DIED).

However, there's a critical section where the user thread dies after the
mutex is released but before list_op_pending is cleared. If that happens,
another thread can wake up, use the lock, release it, and free its
memory. Now, if the robust list cleanup happens after this, the
killed thread's list_op_pending becomes a dandling pointer. The
kernel wrongly treats this address as a mutex, calls a futex_wake()
on it and flips a bit, causing a memory corruption.

To avoid using the dangling pointer, implement
__vdso_futex_robust_try_unlock() for arm64. Make the VDSO release the mutex
and clear the list_op_pending fields, just as is done in userspace right
now. But having it in a VDSO means that, in the case of a killed user
thread, the kernel can know exactly in which part of the release process
the thread was interrupt, check the registers for the operation success and
clears the list_op_pending on behalf of the user thread to prevent the
use-after-free bug.

The need for checking the instructions addresses and the register makes
this mechanism arch-dependent. Implement it using LL/SC semantics. If the
user instruction pointer is between the labels
__futex_list64_try_unlock_cs_start and __futex_list64_try_unlock_cs_end,
the critical section was interrupted. The kernel checks for the result
register (always w3) of the stlxr instruction used for atomically releasing
the mutex. If it's 0, the release happened and the kernel should clear the
list_op_pending field (always stored at x2).

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
v7:
 - Typo in message: success result for stlex is 0, not 1
 - pop_reg is read afterwards so define it as an output parameter "+Q"

v6:
 - Complete reword of commit message to make it clear
 - Better commit split, only the specific aarch64 things here
 - Use explicity labels instead of macros

v4:
 - Guard makefile for vfutex.o with ifdef
 - Moved _start label one instruction above
 - Use results register (w3) to check for store success instead of using zero
   flag

v3:
 - Managed to get pop to always be stored at x2
---
 arch/arm64/Kconfig                |  1 +
 arch/arm64/kernel/vdso.c          | 17 +++++++++++++++--
 arch/arm64/kernel/vdso/Makefile   | 10 ++++++++++
 arch/arm64/kernel/vdso/vdso.lds.S |  9 +++++++++
 arch/arm64/kernel/vdso/vfutex.c   | 35 +++++++++++++++++++++++++++++++++++
 5 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index a269f73b7653..55932c0cd109 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -222,6 +222,7 @@ config ARM64
 	select HAVE_RELIABLE_STACKTRACE
 	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
 	select HAVE_FUNCTION_ARG_ACCESS_API
+	select HAVE_FUTEX_ROBUST_UNLOCK
 	select MMU_GATHER_RCU_TABLE_FREE
 	select HAVE_RSEQ
 	select HAVE_RUST if RUSTC_SUPPORTS_ARM64
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 3ef331b5b240..dc6b582736d0 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -69,16 +69,27 @@ static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit,
 	futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);
 }
 
+static inline void vdso_futex_update_ips(struct mm_struct *mm)
+{
+	unsigned long vdso = (unsigned long) mm->context.vdso;
+
+	__vdso_futex_update_ips(mm, false,
+				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_start),
+				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_end));
+}
+
 #else
-static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
-					   void *endp)
+static inline void vdso_futex_update_ips(struct mm_struct *mm) {}
 #endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
 
+
 static int vdso_mremap(const struct vm_special_mapping *sm,
 		struct vm_area_struct *new_vma)
 {
 	current->mm->context.vdso = (void *)new_vma->vm_start;
 
+	vdso_futex_update_ips(current->mm);
+
 	return 0;
 }
 
@@ -366,5 +377,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	ret = __setup_additional_pages(VDSO_ABI_AA64, mm, bprm, uses_interp);
 	mmap_write_unlock(mm);
 
+	vdso_futex_update_ips(mm);
+
 	return ret;
 }
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index 7dec05dd33b7..985346c7a0bb 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -11,6 +11,10 @@ include $(srctree)/lib/vdso/Makefile.include
 
 obj-vdso := vgettimeofday.o note.o sigreturn.o vgetrandom.o vgetrandom-chacha.o
 
+ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+  obj-vdso += vfutex.o
+endif
+
 # Build rules
 targets := $(obj-vdso) vdso.so vdso.so.dbg
 obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
@@ -45,9 +49,11 @@ CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
 
 CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
 CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
+CFLAGS_REMOVE_vfutex.o = $(CC_FLAGS_REMOVE_VDSO)
 
 CFLAGS_vgettimeofday.o = $(CC_FLAGS_ADD_VDSO)
 CFLAGS_vgetrandom.o = $(CC_FLAGS_ADD_VDSO)
+CFLAGS_vfutex.o = $(CC_FLAGS_ADD_VDSO)
 
 ifneq ($(c-gettimeofday-y),)
   CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
@@ -57,6 +63,10 @@ ifneq ($(c-getrandom-y),)
   CFLAGS_vgetrandom.o += -include $(c-getrandom-y)
 endif
 
+ifneq ($(c-futex-y),)
+  CFLAGS_vfutex.o += -include $(c-futex-y)
+endif
+
 targets += vdso.lds
 CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
 
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index 52314be29191..225f59bb81d1 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -104,6 +104,9 @@ VERSION
 		__kernel_clock_gettime;
 		__kernel_clock_getres;
 		__kernel_getrandom;
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+		__vdso_futex_robust_list64_try_unlock;
+#endif
 	local: *;
 	};
 }
@@ -112,3 +115,9 @@ VERSION
  * Make the sigreturn code visible to the kernel.
  */
 VDSO_sigtramp		= __kernel_rt_sigreturn;
+
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+VDSO_futex_list64_try_unlock_cs_start = __futex_list64_try_unlock_cs_start;
+VDSO_futex_list64_try_unlock_cs_success = __futex_list64_try_unlock_cs_success;
+VDSO_futex_list64_try_unlock_cs_end = __futex_list64_try_unlock_cs_end;
+#endif
diff --git a/arch/arm64/kernel/vdso/vfutex.c b/arch/arm64/kernel/vdso/vfutex.c
new file mode 100644
index 000000000000..ae7b653c1554
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vfutex.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/stringify.h>
+#include <vdso/futex.h>
+
+__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
+{
+	register __u64 *pop_reg asm("x2") = pop;
+	register __u32 result_reg asm("w3") = 0;
+	__u32 val;
+
+	asm volatile (
+		".globl						  "
+		"__futex_list64_try_unlock_cs_start,		  "
+		"__futex_list64_try_unlock_cs_success,		  "
+		"__futex_list64_try_unlock_cs_end		\n"
+
+		"	prfm pstl1strm, %[lock]			\n"
+		"retry:						\n"
+		"	ldxr %w[val], %[lock]			\n"
+		"	cmp %w[tid], %w[val]			\n"
+		"	bne __futex_list64_try_unlock_cs_end	\n"
+		"	stlxr %w[result], wzr, %[lock]		\n"
+		"__futex_list64_try_unlock_cs_start:		\n"
+		"	cbnz %w[result], retry			\n"
+		"__futex_list64_try_unlock_cs_success:		\n"
+		"	str xzr, %[pop_reg]			\n"
+		"__futex_list64_try_unlock_cs_end:		\n"
+
+		: [val] "=&r" (val), [result] "=&r" (result_reg), [pop_reg] "+Q" (*pop_reg)
+		: [tid] "r" (tid), [lock] "Q" (*lock)
+		: "cc", "memory"
+	);
+
+	return val;
+}

-- 
2.55.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v8 3/4] arm64: vdso32: Bring vdso32-offsets.h back
  2026-08-21 21:50 [PATCH v8 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
  2026-08-21 21:50 ` [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support André Almeida
  2026-08-21 21:50 ` [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
@ 2026-08-21 21:50 ` André Almeida
  2026-08-21 21:50 ` [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock() André Almeida
  3 siblings, 0 replies; 16+ messages in thread
From: André Almeida @ 2026-08-21 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida

Commit c7767f5c43df ("arm64: vdso32: Remove unused vdso32-offsets.h")
removed vdso32-offsets.h because it was empty and therefore useless.

With the introduction of __vdso_futex_robust_try_unlock(), there is the
need to expose offsets again.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
 arch/arm64/Makefile               | 2 +-
 arch/arm64/include/asm/vdso.h     | 3 +++
 arch/arm64/kernel/vdso32/Makefile | 8 ++++++++
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 6b005c8fef70..265716644193 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -211,7 +211,7 @@ vdso_prepare: prepare0
 	include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so
 ifdef CONFIG_COMPAT_VDSO
 	$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \
-	arch/arm64/kernel/vdso32/vdso.so
+	include/generated/vdso32-offsets.h arch/arm64/kernel/vdso32/vdso.so
 endif
 endif
 
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 232b46969088..43a214b93524 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -10,6 +10,9 @@
 #ifndef __ASSEMBLER__
 
 #include <generated/vdso-offsets.h>
+#ifdef CONFIG_COMPAT_VDSO
+#include <generated/vdso32-offsets.h>
+#endif
 
 #define VDSO_SYMBOL(base, name)						   \
 ({									   \
diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
index bea3675fa668..4bd60f059f4a 100644
--- a/arch/arm64/kernel/vdso32/Makefile
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -135,6 +135,14 @@ $(c-obj-vdso-gettimeofday): %.o: %.c FORCE
 $(asm-obj-vdso): %.o: %.S FORCE
 	$(call if_changed_dep,vdsoas)
 
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE
+	$(call if_changed,vdsosym)
+
 # Actual build commands
 quiet_cmd_vdsold_and_vdso_check = LD32    $@
       cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
  2026-08-21 21:50 [PATCH v8 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
                   ` (2 preceding siblings ...)
  2026-08-21 21:50 ` [PATCH v8 3/4] arm64: vdso32: Bring vdso32-offsets.h back André Almeida
@ 2026-08-21 21:50 ` André Almeida
  2026-09-16 14:28   ` Mark Rutland
  3 siblings, 1 reply; 16+ messages in thread
From: André Almeida @ 2026-08-21 21:50 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida

Based on aarch64 implementation, provide a 32 bit entry point for
this vDSO.

In order to keep compatibility with arm64_futex_robust_unlock_get_pop(),
make sure to store the pop address at r2 and the compare result value
at r3.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
v7:
 - The store needs to be a release store, so s/strex/stlex/
 - result reg clobber modified to "=&r" to make sure the compiler don't use
 the r3 reg for something else
 - pop_reg will be read after the execution so it should be an output
 parameter with "+Q"
---
 arch/arm64/kernel/vdso.c            | 15 ++++++++++++++-
 arch/arm64/kernel/vdso32/Makefile   |  4 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S |  9 +++++++++
 arch/arm64/kernel/vdso32/vfutex.c   | 34 ++++++++++++++++++++++++++++++++++
 4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index dc6b582736d0..5cae9c17ec72 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -78,11 +78,19 @@ static inline void vdso_futex_update_ips(struct mm_struct *mm)
 				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_end));
 }
 
+static inline void aarch32_vdso_futex_update_ips(struct mm_struct *mm)
+{
+	unsigned long vdso = (unsigned long) mm->context.vdso;
+
+	__vdso_futex_update_ips(mm, true,
+				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_start),
+				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_end));
+}
 #else
 static inline void vdso_futex_update_ips(struct mm_struct *mm) {}
+static inline void aarch32_vdso_futex_update_ips(struct mm_struct *mm) {}
 #endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
 
-
 static int vdso_mremap(const struct vm_special_mapping *sm,
 		struct vm_area_struct *new_vma)
 {
@@ -195,6 +203,8 @@ static int aarch32_mremap(const struct vm_special_mapping *sm,
 {
 	current->mm->context.vdso = (void *)new_vma->vm_start;
 
+	aarch32_vdso_futex_update_ips(current->mm);
+
 	return 0;
 }
 
@@ -327,6 +337,7 @@ static int aarch32_sigreturn_setup(struct mm_struct *mm)
 	return PTR_ERR_OR_ZERO(ret);
 }
 
+
 int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
@@ -347,6 +358,8 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	}
 
 	ret = aarch32_sigreturn_setup(mm);
+
+	aarch32_vdso_futex_update_ips(mm);
 out:
 	mmap_write_unlock(mm);
 	return ret;
diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
index 4bd60f059f4a..f3190125c68b 100644
--- a/arch/arm64/kernel/vdso32/Makefile
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -97,6 +97,10 @@ munge := ../../../arm/vdso/vdsomunge
 hostprogs := $(munge)
 
 c-obj-vdso := note.o
+ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+  c-obj-vdso += vfutex.o
+endif
+
 c-obj-vdso-gettimeofday := vgettimeofday.o
 
 ifneq ($(c-gettimeofday-y),)
diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
index 12bfc39e8aab..52ced27d6045 100644
--- a/arch/arm64/kernel/vdso32/vdso.lds.S
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -89,6 +89,15 @@ VERSION
 #endif /* CONFIG_COMPAT_32BIT_TIME */
 		__vdso_clock_gettime64;
 		__vdso_clock_getres_time64;
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+		__vdso_futex_robust_list32_try_unlock;
+#endif
 	local: *;
 	};
 }
+
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+VDSO_futex_list32_try_unlock_cs_success = __futex_list32_try_unlock_cs_success;
+VDSO_futex_list32_try_unlock_cs_start = __futex_list32_try_unlock_cs_start;
+VDSO_futex_list32_try_unlock_cs_end = __futex_list32_try_unlock_cs_end;
+#endif
diff --git a/arch/arm64/kernel/vdso32/vfutex.c b/arch/arm64/kernel/vdso32/vfutex.c
new file mode 100644
index 000000000000..0d9080b17965
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vfutex.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/stringify.h>
+#include <vdso/futex.h>
+
+__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
+{
+	register __u32 *pop_reg asm("r2") = pop, result_reg asm("r3") = 0;
+	__u32 val, zero = 0;
+
+	asm volatile (
+		".globl						  "
+		"__futex_list32_try_unlock_cs_start,		  "
+		"__futex_list32_try_unlock_cs_success,		  "
+		"__futex_list32_try_unlock_cs_end		\n"
+
+		"retry:						\n"
+		"	ldrex %[val], %[lock]			\n"
+		"	cmp %[tid], %[val]			\n"
+		"	bne __futex_list32_try_unlock_cs_end	\n"
+		"	stlex %[result], %[zero], %[lock]	\n"
+		"__futex_list32_try_unlock_cs_start:		\n"
+		"	cmp %[result], #0			\n"
+		"	bne retry				\n"
+		"__futex_list32_try_unlock_cs_success:		\n"
+		"	str %[zero], %[pop_reg]			\n"
+		"__futex_list32_try_unlock_cs_end:		\n"
+
+		: [val] "=&r" (val), [result] "=&r" (result_reg), [pop_reg] "+Q" (*pop_reg)
+		: [tid] "r" (tid), [lock] "Q" (*lock), [zero] "r" (zero)
+		: "cc", "memory"
+	);
+
+	return val;
+}

-- 
2.55.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support
  2026-08-21 21:50 ` [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support André Almeida
@ 2026-09-16 14:24   ` Mark Rutland
  2026-09-17  1:05     ` André Almeida
  0 siblings, 1 reply; 16+ messages in thread
From: Mark Rutland @ 2026-09-16 14:24 UTC (permalink / raw)
  To: André Almeida
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

Hi André,

I have a few comments here; mostly minor nits.

On Fri, Aug 21, 2026 at 06:50:42PM -0300, André Almeida wrote:
> To solve the robust futex's list_pending_op clearing race condition,
> prepare for implement __vdso_futex_robust_try_unlock() for arm64 with the
> following steps:
> 
> - Create a helper function that sets the struct futex_mm_data with the
> VDSO's labels addresses. The robust futex fixup mechanism needs to
> compare the current instruction pointer to the VDSO instructions range.
> 
> - Split vdso_mremap() in vdso_mremap() and aarch32_mremap(), this allows
> the VDSO to be setup correctly regarding the instructions addresses for
> both ABIs when a mremap happens.

When I commented back on v5, I'd meant that the mremap changes should be
a separate patch. I've included a patch for that below; are you're happy
to take that as a prefix of this series?

> - Implement arch_futex_robust_unlock_get_pop() for arm64, checking for r2
> and r3 registers values for the fixup function. The role of this registers
> is explained in the commit that implement the assembly portion of the VDSO.
> 
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> v6:
>  - Restructured this commit. Move the arch bits away, kept just the
>  generic/helper functions.
> 
> v4:
> - Guard symbols from vdso.lds.S with ifdef
> - drop update_ips() from sigpage remap function
> 
> v3:
>  - Fix adding vdso base addr twice
>  - Call vdso_futex_robust_unlock_update_ips() on remap as well
> v2:
>  - Fixed linker not finding VDSO symbols
> ---
> ---
>  arch/arm64/include/asm/futex_robust.h | 19 +++++++++++++++++++
>  arch/arm64/kernel/vdso.c              | 27 ++++++++++++++++++++++++++-
>  2 files changed, 45 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/futex_robust.h b/arch/arm64/include/asm/futex_robust.h
> new file mode 100644
> index 000000000000..4ff783bb2dc3
> --- /dev/null
> +++ b/arch/arm64/include/asm/futex_robust.h
> @@ -0,0 +1,19 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_ARM64_FUTEX_ROBUST_H
> +#define _ASM_ARM64_FUTEX_ROBUST_H
> +
> +#include <asm/ptrace.h>
> +
> +static __always_inline void __user *arm64_futex_robust_unlock_get_pop(struct pt_regs *regs)
> +{
> +	/*
> +	 * w3 stores the result of the stlxr instruction. If it's zero, the then
> +	 * the ll/sc cmpxchg succeeded and the pending op pointer needs to be cleared.
> +	 */

It would be good if the comment could refer to the functions with the
critical sections, e.g.

	/*
	 * In the asm for __vdso_futex_robust_list{64,32}_try_unlock(), ...
	 */

That way it will be easier for folk to cross-reference this later.

> +	return (regs->user_regs.regs[3]) ? NULL : (void __user *) regs->user_regs.regs[2];

You can use 'regs->regs[n]' in place of 'regs->user_regs.regs[n]' here,
which will make this a bit shorter and easier to read.

I reckon this might also be clearer as:

| 	if (regs->regs[3])
| 		return NULL;
| 	
| 	return (void __user *)regs->regs[2];

Do we need a __force cast here, or is sparse happy without that?

> +}
> +
> +#define arch_futex_robust_unlock_get_pop(regs) \
> +	arm64_futex_robust_unlock_get_pop(regs)
> +
> +#endif /* _ASM_ARM64_FUTEX_ROBUST_H */
> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
> index 592dd8668de4..3ef331b5b240 100644
> --- a/arch/arm64/kernel/vdso.c
> +++ b/arch/arm64/kernel/vdso.c
> @@ -11,6 +11,7 @@
>  #include <linux/clocksource.h>
>  #include <linux/elf.h>
>  #include <linux/err.h>
> +#include <linux/futex.h>
>  #include <linux/errno.h>
>  #include <linux/gfp.h>
>  #include <linux/kernel.h>
> @@ -57,6 +58,22 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
>  #endif /* CONFIG_COMPAT_VDSO */
>  };
>  
> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
> +static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
> +					   void *endp)
> +{
> +	unsigned long start = (unsigned long) startp;
> +	unsigned long end = (unsigned long) endp;

Nit: there shouldn't be a space between the cast and the expression:

	unsigned long start = (unsigned long)startp;
	unsigned long end = (unsigned long)endp;

> +	struct futex_mm_data *fd = &mm->futex;
> +
> +	futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);

On arm64 (and every architecture other than x86, AFAICT), the
native/compat VDSOs are mutually exclusive, and a single mm can only
have one of them.

Given that, I think we can make this:

	futex_set_vdso_cs_range(fd, 0, start, end, is_32bit);

That way we'll avoid confusing/bikesheeding over 'is_32bit ? 1 : 0',
without having to add mnemnonics for the native/compat CS indices.

That said, what's the plan for 32-bit robust lists on a 64-bit host?
IIUC you wanted that for emulation, and AFAICT you have no way to call
__vdso_futex_robust_list32_try_unlock() from a native task.

> +}
> +
> +#else
> +static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
> +					   void *endp)
> +#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
> +
>  static int vdso_mremap(const struct vm_special_mapping *sm,
>  		struct vm_area_struct *new_vma)
>  {
> @@ -162,6 +179,14 @@ static int aarch32_sigpage_mremap(const struct vm_special_mapping *sm,
>  	return 0;
>  }
>  
> +static int aarch32_mremap(const struct vm_special_mapping *sm,
> +		struct vm_area_struct *new_vma)
> +{
> +	current->mm->context.vdso = (void *)new_vma->vm_start;
> +
> +	return 0;
> +}
> +
>  static struct vm_special_mapping aarch32_vdso_maps[] = {
>  	[AA32_MAP_VECTORS] = {
>  		.name	= "[vectors]", /* ABI */
> @@ -174,7 +199,7 @@ static struct vm_special_mapping aarch32_vdso_maps[] = {
>  	},
>  	[AA32_MAP_VDSO] = {
>  		.name = "[vdso]",
> -		.mremap = vdso_mremap,
> +		.mremap = aarch32_mremap,
>  	},
>  };

As above, I'd prefer if the mremap changes were a separate patch, e.g.
as below.

Mark.

---->8----
From 39029dfea82a54bd7b511cc036d10ef8e8ee4ccd Mon Sep 17 00:00:00 2001
From: Mark Rutland <mark.rutland@arm.com>
Date: Wed, 16 Sep 2026 11:03:32 +0100
Subject: [PATCH] arm64: vdso: Split native/compat mremap callbacks

Currently the native and compat VDSOs share a common vdso_mremap()
function which is used as their vm_special_mapping::mremap callback.

In subsequent patches the native and compat VDSOs will need distinct
mremap logic, which will be easier to manage with separate functions.

Give the compat VDSO its own aarch32_vdso_mremap() function. For now
this is identical to vdso_mremap().

At the same time, fix the odd whitespace in the vdso_mremap() prototype.

There should be no functional change as a result of this patch.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/kernel/vdso.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 592dd8668de46..089a70d962204 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -58,7 +58,7 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
 };
 
 static int vdso_mremap(const struct vm_special_mapping *sm,
-		struct vm_area_struct *new_vma)
+		       struct vm_area_struct *new_vma)
 {
 	current->mm->context.vdso = (void *)new_vma->vm_start;
 
@@ -162,6 +162,14 @@ static int aarch32_sigpage_mremap(const struct vm_special_mapping *sm,
 	return 0;
 }
 
+static int aarch32_vdso_mremap(const struct vm_special_mapping *sm,
+			       struct vm_area_struct *new_vma)
+{
+	current->mm->context.vdso = (void *)new_vma->vm_start;
+
+	return 0;
+}
+
 static struct vm_special_mapping aarch32_vdso_maps[] = {
 	[AA32_MAP_VECTORS] = {
 		.name	= "[vectors]", /* ABI */
@@ -174,7 +182,7 @@ static struct vm_special_mapping aarch32_vdso_maps[] = {
 	},
 	[AA32_MAP_VDSO] = {
 		.name = "[vdso]",
-		.mremap = vdso_mremap,
+		.mremap = aarch32_vdso_mremap,
 	},
 };
 
-- 
2.30.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
  2026-08-21 21:50 ` [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
@ 2026-09-16 14:27   ` Mark Rutland
  2026-09-17  1:06     ` André Almeida
  0 siblings, 1 reply; 16+ messages in thread
From: Mark Rutland @ 2026-09-16 14:27 UTC (permalink / raw)
  To: André Almeida
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

Hi André,

I have a few comments below. I'm not sure what the plan is for 32-bit
robust lists, and I think there are a few problems with the assembly.

On Fri, Aug 21, 2026 at 06:50:43PM -0300, André Almeida wrote:
> The futex's robust list uAPI has a struct robust_list_head::list_op_pending
> pointer used by userspace as a temporary variable while the mutex unlock is
> happening. User sets it to the futex address that's about to be released
> and removed from the robust list, and list_op_pending is cleared after.
> After a thread dies, the kernel checks it's list_op_pending and wakes the
> mutex in that address, to prevent starvation, and flip a bit in the mutex
> word (FUTEX_OWNER_DIED).
> 
> However, there's a critical section where the user thread dies after the
> mutex is released but before list_op_pending is cleared. If that happens,
> another thread can wake up, use the lock, release it, and free its
> memory. Now, if the robust list cleanup happens after this, the
> killed thread's list_op_pending becomes a dandling pointer. The
> kernel wrongly treats this address as a mutex, calls a futex_wake()
> on it and flips a bit, causing a memory corruption.
> 
> To avoid using the dangling pointer, implement
> __vdso_futex_robust_try_unlock() for arm64. Make the VDSO release the mutex
> and clear the list_op_pending fields, just as is done in userspace right
> now. But having it in a VDSO means that, in the case of a killed user
> thread, the kernel can know exactly in which part of the release process
> the thread was interrupt, check the registers for the operation success and
> clears the list_op_pending on behalf of the user thread to prevent the
> use-after-free bug.
> 
> The need for checking the instructions addresses and the register makes
> this mechanism arch-dependent. Implement it using LL/SC semantics. If the
> user instruction pointer is between the labels
> __futex_list64_try_unlock_cs_start and __futex_list64_try_unlock_cs_end,
> the critical section was interrupted. The kernel checks for the result
> register (always w3) of the stlxr instruction used for atomically releasing
> the mutex. If it's 0, the release happened and the kernel should clear the
> list_op_pending field (always stored at x2).
> 
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> v7:
>  - Typo in message: success result for stlex is 0, not 1
>  - pop_reg is read afterwards so define it as an output parameter "+Q"
> 
> v6:
>  - Complete reword of commit message to make it clear
>  - Better commit split, only the specific aarch64 things here
>  - Use explicity labels instead of macros
> 
> v4:
>  - Guard makefile for vfutex.o with ifdef
>  - Moved _start label one instruction above
>  - Use results register (w3) to check for store success instead of using zero
>    flag
> 
> v3:
>  - Managed to get pop to always be stored at x2
> ---
>  arch/arm64/Kconfig                |  1 +
>  arch/arm64/kernel/vdso.c          | 17 +++++++++++++++--
>  arch/arm64/kernel/vdso/Makefile   | 10 ++++++++++
>  arch/arm64/kernel/vdso/vdso.lds.S |  9 +++++++++
>  arch/arm64/kernel/vdso/vfutex.c   | 35 +++++++++++++++++++++++++++++++++++
>  5 files changed, 70 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index a269f73b7653..55932c0cd109 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -222,6 +222,7 @@ config ARM64
>  	select HAVE_RELIABLE_STACKTRACE
>  	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
>  	select HAVE_FUNCTION_ARG_ACCESS_API
> +	select HAVE_FUTEX_ROBUST_UNLOCK
>  	select MMU_GATHER_RCU_TABLE_FREE
>  	select HAVE_RSEQ
>  	select HAVE_RUST if RUSTC_SUPPORTS_ARM64
> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
> index 3ef331b5b240..dc6b582736d0 100644
> --- a/arch/arm64/kernel/vdso.c
> +++ b/arch/arm64/kernel/vdso.c
> @@ -69,16 +69,27 @@ static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit,
>  	futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);
>  }
>  
> +static inline void vdso_futex_update_ips(struct mm_struct *mm)
> +{
> +	unsigned long vdso = (unsigned long) mm->context.vdso;

Nit: no space for the cast, please.

> +
> +	__vdso_futex_update_ips(mm, false,
> +				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_start),
> +				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_end));
> +}
> +
>  #else
> -static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
> -					   void *endp)
> +static inline void vdso_futex_update_ips(struct mm_struct *mm) {}
>  #endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
>  
> +
>  static int vdso_mremap(const struct vm_special_mapping *sm,
>  		struct vm_area_struct *new_vma)
>  {
>  	current->mm->context.vdso = (void *)new_vma->vm_start;
>  
> +	vdso_futex_update_ips(current->mm);
> +
>  	return 0;
>  }
>  
> @@ -366,5 +377,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
>  	ret = __setup_additional_pages(VDSO_ABI_AA64, mm, bprm, uses_interp);
>  	mmap_write_unlock(mm);
>  
> +	vdso_futex_update_ips(mm);
> +
>  	return ret;
>  }
> diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
> index 7dec05dd33b7..985346c7a0bb 100644
> --- a/arch/arm64/kernel/vdso/Makefile
> +++ b/arch/arm64/kernel/vdso/Makefile
> @@ -11,6 +11,10 @@ include $(srctree)/lib/vdso/Makefile.include
>  
>  obj-vdso := vgettimeofday.o note.o sigreturn.o vgetrandom.o vgetrandom-chacha.o
>  
> +ifdef CONFIG_FUTEX_ROBUST_UNLOCK
> +  obj-vdso += vfutex.o
> +endif
> +
>  # Build rules
>  targets := $(obj-vdso) vdso.so vdso.so.dbg
>  obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
> @@ -45,9 +49,11 @@ CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
>  
>  CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
>  CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
> +CFLAGS_REMOVE_vfutex.o = $(CC_FLAGS_REMOVE_VDSO)
>  
>  CFLAGS_vgettimeofday.o = $(CC_FLAGS_ADD_VDSO)
>  CFLAGS_vgetrandom.o = $(CC_FLAGS_ADD_VDSO)
> +CFLAGS_vfutex.o = $(CC_FLAGS_ADD_VDSO)
>  
>  ifneq ($(c-gettimeofday-y),)
>    CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
> @@ -57,6 +63,10 @@ ifneq ($(c-getrandom-y),)
>    CFLAGS_vgetrandom.o += -include $(c-getrandom-y)
>  endif
>  
> +ifneq ($(c-futex-y),)
> +  CFLAGS_vfutex.o += -include $(c-futex-y)
> +endif
> +
>  targets += vdso.lds
>  CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
>  
> diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
> index 52314be29191..225f59bb81d1 100644
> --- a/arch/arm64/kernel/vdso/vdso.lds.S
 +++ b/arch/arm64/kernel/vdso/vdso.lds.S
> @@ -104,6 +104,9 @@ VERSION
>  		__kernel_clock_gettime;
>  		__kernel_clock_getres;
>  		__kernel_getrandom;
> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
> +		__vdso_futex_robust_list64_try_unlock;
> +#endif
>  	local: *;
>  	};
>  }
> @@ -112,3 +115,9 @@ VERSION
>   * Make the sigreturn code visible to the kernel.
>   */
>  VDSO_sigtramp		= __kernel_rt_sigreturn;
> +
> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
> +VDSO_futex_list64_try_unlock_cs_start = __futex_list64_try_unlock_cs_start;
> +VDSO_futex_list64_try_unlock_cs_success = __futex_list64_try_unlock_cs_success;
> +VDSO_futex_list64_try_unlock_cs_end = __futex_list64_try_unlock_cs_end;
> +#endif

I was under the impression that you wanted to be able to use a 32-bit
list on arm64 for emulated 32-bit code. Am I mistaken, or missing
something? On arm64, you won't be able to call the 32-bit VDSO as you
could on x86-64.

> diff --git a/arch/arm64/kernel/vdso/vfutex.c b/arch/arm64/kernel/vdso/vfutex.c
> new file mode 100644
> index 000000000000..ae7b653c1554
> --- /dev/null
> +++ b/arch/arm64/kernel/vdso/vfutex.c
> @@ -0,0 +1,35 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include <linux/stringify.h>
> +#include <vdso/futex.h>
> +
> +__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
> +{

It would be good to have a comment here saying that
arm64_futex_robust_unlock_get_pop() depends on these register
allocations.

> +	register __u64 *pop_reg asm("x2") = pop;
> +	register __u32 result_reg asm("w3") = 0;
> +	__u32 val;
> +
> +	asm volatile (
> +		".globl						  "
> +		"__futex_list64_try_unlock_cs_start,		  "
> +		"__futex_list64_try_unlock_cs_success,		  "
> +		"__futex_list64_try_unlock_cs_end		\n"

Sorry, when I mentioned putting these within the assembly, I meant doing
something like:

| #define LABEL(l)						\
| 	"	.globl " #l "\n"				\
| 	#l ":\n"

... and within the asssembly, having:

| 	"	insn1					\n"
| 	"	insn2					\n"
| 	LABEL(__futex_list64_try_unlock_cs_start)
| 	"	insn2					\n"
| 	LABEL(__futex_list64_try_unlock_cs_start)
| 	"	insn4					\n"
| 	LABEL(__futex_list64_try_unlock_cs_success)
| 	"	insn5					\n"

That way we use the full strings, which are easy to grep for, and we
only have to define each label string once.

> +
> +		"	prfm pstl1strm, %[lock]			\n"
> +		"retry:						\n"
> +		"	ldxr %w[val], %[lock]			\n"
> +		"	cmp %w[tid], %w[val]			\n"
> +		"	bne __futex_list64_try_unlock_cs_end	\n"

The 'bne' here should be 'b.ne'. IIUC assemblers accept the former by
historical accident, and 'b.<cond>' is the architecturally defined
mnemonic.

As general thing, we format assembly with a tab between the instruction
and first operand, so the above should be:

| 	"	prfm	pstl1strm, %[lock]			\n"
| 	"retry:							\n"
| 	"	ldxr	%w[val], %[lock]			\n"
| 	"	cmp	%w[tid], %w[val]			\n"
| 	"	b.ne	__futex_list64_try_unlock_cs_end	\n"

> +		"	stlxr %w[result], wzr, %[lock]		\n"
> +		"__futex_list64_try_unlock_cs_start:		\n"
> +		"	cbnz %w[result], retry			\n"
> +		"__futex_list64_try_unlock_cs_success:		\n"
> +		"	str xzr, %[pop_reg]			\n"
> +		"__futex_list64_try_unlock_cs_end:		\n"
> +
> +		: [val] "=&r" (val), [result] "=&r" (result_reg), [pop_reg] "+Q" (*pop_reg)
> +		: [tid] "r" (tid), [lock] "Q" (*lock)
> +		: "cc", "memory"
> +	);

As a general note, for assembly constaints, please put each constraint
on its own line, e.g.

	: [val] "=&r" (val),
	  [result] "=&r" (result_reg),
	  [pop_reg] "+Q" (*pop_reg)
	: [tid] "r" (tid),
	  [lock] "Q" (*lock)
	: "cc", "memory"

That formatting makes it much easier to read each constraint
individually, and it makes it easier to review changes to individual
constaints.

Generally, for asm we have a preferred style:

	asm volatile(
	"	// string starts aligned with 'asm'	\n"
	"	// with 1 tab indend within that.	\n"
	"						\n"
	"	insn	operand1, operand2		\n"
	"label:						\n"
	"	insn	operand1, operand2		\n"
	: [output1] "=r" (...),
	  [output2] "=r" (...)
	: [input1] "r" (...).
	  [input2] "r" (...)
	: "clobbers"
	);

I see a couple of problems with the constraints as-is.

Firstly, the constraints for [pop_reg] doesn't guarantee that x2 is
used. The "+Q" constraint takes a memory operand (in this case the
location pointed to by 'pop_reg', and limits the addressing mode to a
single base register with no offset. The operand is the memroy location,
not the register holding the memory location, so this constraint won't
necessarily use x2. Unless 'pop_reg' itself is passed into a register
constraint, the compiler might not ensure that 'x2' is populated.

For example:

| [mark@gravadlaks:~/tests/asm-operands-q-reg]% cat test.c
| unsigned long foo(unsigned long *ptr)
| {
|         register unsigned long *ptr_reg asm("x2") = ptr;
|         unsigned long val;
| 
|         asm volatile(
|         "       ldr     %[val], %[qptr]\n"
|         : [val] "=&r" (val)
|         : [qptr] "Q" (*ptr_reg)
|         );
| 
|         return val;
| }
| [mark@gravadlaks:~/tests/asm-operands-q-reg]% usekorg 16.2.0 aarch64-linux-gcc -c test.c -O2
| [mark@gravadlaks:~/tests/asm-operands-q-reg]% usekorg 16.2.0 aarch64-linux-objdump -d test.o
| 
| test.o:     file format elf64-littleaarch64
| 
| 
| Disassembly of section .text:
| 
| 0000000000000000 <foo>:
|    0:   f9400001        ldr     x1, [x0]
|    4:   aa0103e0        mov     x0, x1
|    8:   d65f03c0        ret

We will need an "r" input constraint for 'pop_reg' to ensure that x2 is
allocated. Either in addition to an "=Q" output constraint for the
actual memory write, or we rely on the memory clobber to hazaard against
other memory accesses.

Secondly, the "Q" input constaint for 'lock' looks inaccurate, given
that we both read and write to 'lock'. Either that should be a "+Q"
output constraint, or we rely on the memory clobber to hazard against
other memory accesses.

Mark.

> +
> +	return val;
> +}
> 
> -- 
> 2.55.0
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
  2026-08-21 21:50 ` [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock() André Almeida
@ 2026-09-16 14:28   ` Mark Rutland
  2026-09-17  1:11     ` André Almeida
  0 siblings, 1 reply; 16+ messages in thread
From: Mark Rutland @ 2026-09-16 14:28 UTC (permalink / raw)
  To: André Almeida
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

On Fri, Aug 21, 2026 at 06:50:45PM -0300, André Almeida wrote:
> Based on aarch64 implementation, provide a 32 bit entry point for
> this vDSO.
> 
> In order to keep compatibility with arm64_futex_robust_unlock_get_pop(),
> make sure to store the pop address at r2 and the compare result value
> at r3.

Before we add this to the compat vdso, we'll need to implement this on
arch/arm/.

Otherwise, my comments on the patch for the native vdso functions apply
here too.

Mark.

> 
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> v7:
>  - The store needs to be a release store, so s/strex/stlex/
>  - result reg clobber modified to "=&r" to make sure the compiler don't use
>  the r3 reg for something else
>  - pop_reg will be read after the execution so it should be an output
>  parameter with "+Q"
> ---
>  arch/arm64/kernel/vdso.c            | 15 ++++++++++++++-
>  arch/arm64/kernel/vdso32/Makefile   |  4 ++++
>  arch/arm64/kernel/vdso32/vdso.lds.S |  9 +++++++++
>  arch/arm64/kernel/vdso32/vfutex.c   | 34 ++++++++++++++++++++++++++++++++++
>  4 files changed, 61 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
> index dc6b582736d0..5cae9c17ec72 100644
> --- a/arch/arm64/kernel/vdso.c
> +++ b/arch/arm64/kernel/vdso.c
> @@ -78,11 +78,19 @@ static inline void vdso_futex_update_ips(struct mm_struct *mm)
>  				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_end));
>  }
>  
> +static inline void aarch32_vdso_futex_update_ips(struct mm_struct *mm)
> +{
> +	unsigned long vdso = (unsigned long) mm->context.vdso;
> +
> +	__vdso_futex_update_ips(mm, true,
> +				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_start),
> +				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_end));
> +}
>  #else
>  static inline void vdso_futex_update_ips(struct mm_struct *mm) {}
> +static inline void aarch32_vdso_futex_update_ips(struct mm_struct *mm) {}
>  #endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
>  
> -
>  static int vdso_mremap(const struct vm_special_mapping *sm,
>  		struct vm_area_struct *new_vma)
>  {
> @@ -195,6 +203,8 @@ static int aarch32_mremap(const struct vm_special_mapping *sm,
>  {
>  	current->mm->context.vdso = (void *)new_vma->vm_start;
>  
> +	aarch32_vdso_futex_update_ips(current->mm);
> +
>  	return 0;
>  }
>  
> @@ -327,6 +337,7 @@ static int aarch32_sigreturn_setup(struct mm_struct *mm)
>  	return PTR_ERR_OR_ZERO(ret);
>  }
>  
> +
>  int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
>  {
>  	struct mm_struct *mm = current->mm;
> @@ -347,6 +358,8 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
>  	}
>  
>  	ret = aarch32_sigreturn_setup(mm);
> +
> +	aarch32_vdso_futex_update_ips(mm);
>  out:
>  	mmap_write_unlock(mm);
>  	return ret;
> diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
> index 4bd60f059f4a..f3190125c68b 100644
> --- a/arch/arm64/kernel/vdso32/Makefile
> +++ b/arch/arm64/kernel/vdso32/Makefile
> @@ -97,6 +97,10 @@ munge := ../../../arm/vdso/vdsomunge
>  hostprogs := $(munge)
>  
>  c-obj-vdso := note.o
> +ifdef CONFIG_FUTEX_ROBUST_UNLOCK
> +  c-obj-vdso += vfutex.o
> +endif
> +
>  c-obj-vdso-gettimeofday := vgettimeofday.o
>  
>  ifneq ($(c-gettimeofday-y),)
> diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
> index 12bfc39e8aab..52ced27d6045 100644
> --- a/arch/arm64/kernel/vdso32/vdso.lds.S
> +++ b/arch/arm64/kernel/vdso32/vdso.lds.S
> @@ -89,6 +89,15 @@ VERSION
>  #endif /* CONFIG_COMPAT_32BIT_TIME */
>  		__vdso_clock_gettime64;
>  		__vdso_clock_getres_time64;
> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
> +		__vdso_futex_robust_list32_try_unlock;
> +#endif
>  	local: *;
>  	};
>  }
> +
> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
> +VDSO_futex_list32_try_unlock_cs_success = __futex_list32_try_unlock_cs_success;
> +VDSO_futex_list32_try_unlock_cs_start = __futex_list32_try_unlock_cs_start;
> +VDSO_futex_list32_try_unlock_cs_end = __futex_list32_try_unlock_cs_end;
> +#endif
> diff --git a/arch/arm64/kernel/vdso32/vfutex.c b/arch/arm64/kernel/vdso32/vfutex.c
> new file mode 100644
> index 000000000000..0d9080b17965
> --- /dev/null
> +++ b/arch/arm64/kernel/vdso32/vfutex.c
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include <linux/stringify.h>
> +#include <vdso/futex.h>
> +
> +__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
> +{
> +	register __u32 *pop_reg asm("r2") = pop, result_reg asm("r3") = 0;
> +	__u32 val, zero = 0;
> +
> +	asm volatile (
> +		".globl						  "
> +		"__futex_list32_try_unlock_cs_start,		  "
> +		"__futex_list32_try_unlock_cs_success,		  "
> +		"__futex_list32_try_unlock_cs_end		\n"
> +
> +		"retry:						\n"
> +		"	ldrex %[val], %[lock]			\n"
> +		"	cmp %[tid], %[val]			\n"
> +		"	bne __futex_list32_try_unlock_cs_end	\n"
> +		"	stlex %[result], %[zero], %[lock]	\n"
> +		"__futex_list32_try_unlock_cs_start:		\n"
> +		"	cmp %[result], #0			\n"
> +		"	bne retry				\n"
> +		"__futex_list32_try_unlock_cs_success:		\n"
> +		"	str %[zero], %[pop_reg]			\n"
> +		"__futex_list32_try_unlock_cs_end:		\n"
> +
> +		: [val] "=&r" (val), [result] "=&r" (result_reg), [pop_reg] "+Q" (*pop_reg)
> +		: [tid] "r" (tid), [lock] "Q" (*lock), [zero] "r" (zero)
> +		: "cc", "memory"
> +	);
> +
> +	return val;
> +}
> 
> -- 
> 2.55.0
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support
  2026-09-16 14:24   ` Mark Rutland
@ 2026-09-17  1:05     ` André Almeida
  2026-09-17 10:01       ` Mark Rutland
  0 siblings, 1 reply; 16+ messages in thread
From: André Almeida @ 2026-09-17  1:05 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

Em 16/09/2026 11:24, Mark Rutland escreveu:
> Hi André,
> 
> I have a few comments here; mostly minor nits.
> 

Thanks for the review!

> On Fri, Aug 21, 2026 at 06:50:42PM -0300, André Almeida wrote:
>> To solve the robust futex's list_pending_op clearing race condition,
>> prepare for implement __vdso_futex_robust_try_unlock() for arm64 with the
>> following steps:
>>
>> - Create a helper function that sets the struct futex_mm_data with the
>> VDSO's labels addresses. The robust futex fixup mechanism needs to
>> compare the current instruction pointer to the VDSO instructions range.
>>
>> - Split vdso_mremap() in vdso_mremap() and aarch32_mremap(), this allows
>> the VDSO to be setup correctly regarding the instructions addresses for
>> both ABIs when a mremap happens.
> 
> When I commented back on v5, I'd meant that the mremap changes should be
> a separate patch. I've included a patch for that below; are you're happy
> to take that as a prefix of this series?
> 

Sure thing, thanks for the patch :)

>> - Implement arch_futex_robust_unlock_get_pop() for arm64, checking for r2
>> and r3 registers values for the fixup function. The role of this registers
>> is explained in the commit that implement the assembly portion of the VDSO.
>>
>> Signed-off-by: André Almeida <andrealmeid@igalia.com>
>> ---
>> v6:
>>   - Restructured this commit. Move the arch bits away, kept just the
>>   generic/helper functions.
>>
>> v4:
>> - Guard symbols from vdso.lds.S with ifdef
>> - drop update_ips() from sigpage remap function
>>
>> v3:
>>   - Fix adding vdso base addr twice
>>   - Call vdso_futex_robust_unlock_update_ips() on remap as well
>> v2:
>>   - Fixed linker not finding VDSO symbols
>> ---
>> ---
>>   arch/arm64/include/asm/futex_robust.h | 19 +++++++++++++++++++
>>   arch/arm64/kernel/vdso.c              | 27 ++++++++++++++++++++++++++-
>>   2 files changed, 45 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/futex_robust.h b/arch/arm64/include/asm/futex_robust.h
>> new file mode 100644
>> index 000000000000..4ff783bb2dc3
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/futex_robust.h
>> @@ -0,0 +1,19 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +#ifndef _ASM_ARM64_FUTEX_ROBUST_H
>> +#define _ASM_ARM64_FUTEX_ROBUST_H
>> +
>> +#include <asm/ptrace.h>
>> +
>> +static __always_inline void __user *arm64_futex_robust_unlock_get_pop(struct pt_regs *regs)
>> +{
>> +	/*
>> +	 * w3 stores the result of the stlxr instruction. If it's zero, the then
>> +	 * the ll/sc cmpxchg succeeded and the pending op pointer needs to be cleared.
>> +	 */
> 
> It would be good if the comment could refer to the functions with the
> critical sections, e.g.
> 
> 	/*
> 	 * In the asm for __vdso_futex_robust_list{64,32}_try_unlock(), ...
> 	 */
> 
> That way it will be easier for folk to cross-reference this later.
> 
>> +	return (regs->user_regs.regs[3]) ? NULL : (void __user *) regs->user_regs.regs[2];
> 
> You can use 'regs->regs[n]' in place of 'regs->user_regs.regs[n]' here,
> which will make this a bit shorter and easier to read.
> 
> I reckon this might also be clearer as:
> 
> | 	if (regs->regs[3])
> | 		return NULL;
> | 	
> | 	return (void __user *)regs->regs[2];
> 
> Do we need a __force cast here, or is sparse happy without that?

I've just re-compiled those patches with C=1, and didn't find any 
warning for this.

> 
>> +}
>> +
>> +#define arch_futex_robust_unlock_get_pop(regs) \
>> +	arm64_futex_robust_unlock_get_pop(regs)
>> +
>> +#endif /* _ASM_ARM64_FUTEX_ROBUST_H */
>> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
>> index 592dd8668de4..3ef331b5b240 100644
>> --- a/arch/arm64/kernel/vdso.c
>> +++ b/arch/arm64/kernel/vdso.c
>> @@ -11,6 +11,7 @@
>>   #include <linux/clocksource.h>
>>   #include <linux/elf.h>
>>   #include <linux/err.h>
>> +#include <linux/futex.h>
>>   #include <linux/errno.h>
>>   #include <linux/gfp.h>
>>   #include <linux/kernel.h>
>> @@ -57,6 +58,22 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
>>   #endif /* CONFIG_COMPAT_VDSO */
>>   };
>>   
>> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
>> +static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
>> +					   void *endp)
>> +{
>> +	unsigned long start = (unsigned long) startp;
>> +	unsigned long end = (unsigned long) endp;
> 
> Nit: there shouldn't be a space between the cast and the expression:
> 
> 	unsigned long start = (unsigned long)startp;
> 	unsigned long end = (unsigned long)endp;
> 
>> +	struct futex_mm_data *fd = &mm->futex;
>> +
>> +	futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);
> 
> On arm64 (and every architecture other than x86, AFAICT), the
> native/compat VDSOs are mutually exclusive, and a single mm can only
> have one of them.
> 
> Given that, I think we can make this:
> 
> 	futex_set_vdso_cs_range(fd, 0, start, end, is_32bit);
> 
> That way we'll avoid confusing/bikesheeding over 'is_32bit ? 1 : 0',
> without having to add mnemnonics for the native/compat CS indices.

Perfect, I will simplify that then.

> 
> That said, what's the plan for 32-bit robust lists on a 64-bit host?
> IIUC you wanted that for emulation, and AFAICT you have no way to call
> __vdso_futex_robust_list32_try_unlock() from a native task.

Yes, the plan is to be able to use the 32-bit robust lists on a 64-bit 
hosts, with a new interface (set/get_robust_list2[1]). That means that a 
64-bit kernel will be able to process an user robust list made of 32-bit 
pointers. So the emulator will call set_robust_list2() one time for it's 
own list, and another time for the emulated app list.

However, what we have agreed for the moment is that, while there's no 
support for that, we will not expose the 32-bit functions yet [2]:

"...that requires also the ability to register a 32-bit robust list for 
a 64-bit process, which is not supported right now. So no, we are not 
exposing something half functional..."

So yes, in the near future I will need to expose 
__vdso_futex_robust_list32_try_unlock() to 64-bit apps as well, to be 
able to do this handling with 32-bit pointers, but we are not doing it 
right now.

[1] 
https://lore.kernel.org/lkml/20251122-tonyk-robust_futex-v6-0-05fea005a0fd@igalia.com/

[2] https://lore.kernel.org/lkml/878q9vwote.ffs@tglx/


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
  2026-09-16 14:27   ` Mark Rutland
@ 2026-09-17  1:06     ` André Almeida
  2026-09-17 10:45       ` Mark Rutland
  0 siblings, 1 reply; 16+ messages in thread
From: André Almeida @ 2026-09-17  1:06 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

Em 16/09/2026 11:27, Mark Rutland escreveu:
> Hi André,
> 
> I have a few comments below. I'm not sure what the plan is for 32-bit
> robust lists, and I think there are a few problems with the assembly.
> 
> On Fri, Aug 21, 2026 at 06:50:43PM -0300, André Almeida wrote:

[...]

> 
>> +	register __u64 *pop_reg asm("x2") = pop;
>> +	register __u32 result_reg asm("w3") = 0;
>> +	__u32 val;
>> +
>> +	asm volatile (
>> +		".globl						  "
>> +		"__futex_list64_try_unlock_cs_start,		  "
>> +		"__futex_list64_try_unlock_cs_success,		  "
>> +		"__futex_list64_try_unlock_cs_end		\n"
> 
> Sorry, when I mentioned putting these within the assembly, I meant doing
> something like:
> 
> | #define LABEL(l)						\
> | 	"	.globl " #l "\n"				\
> | 	#l ":\n"
> 
> ... and within the asssembly, having:
> 
> | 	"	insn1					\n"
> | 	"	insn2					\n"
> | 	LABEL(__futex_list64_try_unlock_cs_start)
> | 	"	insn2					\n"
> | 	LABEL(__futex_list64_try_unlock_cs_start)
> | 	"	insn4					\n"
> | 	LABEL(__futex_list64_try_unlock_cs_success)
> | 	"	insn5					\n"
> 
> That way we use the full strings, which are easy to grep for, and we
> only have to define each label string once.

Oh, I see, thanks! I will change that for the next version.

> 
>> +
>> +		"	prfm pstl1strm, %[lock]			\n"
>> +		"retry:						\n"
>> +		"	ldxr %w[val], %[lock]			\n"
>> +		"	cmp %w[tid], %w[val]			\n"
>> +		"	bne __futex_list64_try_unlock_cs_end	\n"
> 
> The 'bne' here should be 'b.ne'. IIUC assemblers accept the former by
> historical accident, and 'b.<cond>' is the architecturally defined
> mnemonic.
> 
> As general thing, we format assembly with a tab between the instruction
> and first operand, so the above should be:
> 
> | 	"	prfm	pstl1strm, %[lock]			\n"
> | 	"retry:							\n"
> | 	"	ldxr	%w[val], %[lock]			\n"
> | 	"	cmp	%w[tid], %w[val]			\n"
> | 	"	b.ne	__futex_list64_try_unlock_cs_end	\n"
> 
>> +		"	stlxr %w[result], wzr, %[lock]		\n"
>> +		"__futex_list64_try_unlock_cs_start:		\n"
>> +		"	cbnz %w[result], retry			\n"
>> +		"__futex_list64_try_unlock_cs_success:		\n"
>> +		"	str xzr, %[pop_reg]			\n"
>> +		"__futex_list64_try_unlock_cs_end:		\n"
>> +
>> +		: [val] "=&r" (val), [result] "=&r" (result_reg), [pop_reg] "+Q" (*pop_reg)
>> +		: [tid] "r" (tid), [lock] "Q" (*lock)
>> +		: "cc", "memory"
>> +	);
> 
> As a general note, for assembly constaints, please put each constraint
> on its own line, e.g.
> 
> 	: [val] "=&r" (val),
> 	  [result] "=&r" (result_reg),
> 	  [pop_reg] "+Q" (*pop_reg)
> 	: [tid] "r" (tid),
> 	  [lock] "Q" (*lock)
> 	: "cc", "memory"
> 
> That formatting makes it much easier to read each constraint
> individually, and it makes it easier to review changes to individual
> constaints.
> 
> Generally, for asm we have a preferred style:
> 
> 	asm volatile(
> 	"	// string starts aligned with 'asm'	\n"
> 	"	// with 1 tab indend within that.	\n"
> 	"						\n"
> 	"	insn	operand1, operand2		\n"
> 	"label:						\n"
> 	"	insn	operand1, operand2		\n"
> 	: [output1] "=r" (...),
> 	  [output2] "=r" (...)
> 	: [input1] "r" (...).
> 	  [input2] "r" (...)
> 	: "clobbers"
> 	);
> 
> I see a couple of problems with the constraints as-is.
> 
> Firstly, the constraints for [pop_reg] doesn't guarantee that x2 is
> used. The "+Q" constraint takes a memory operand (in this case the
> location pointed to by 'pop_reg', and limits the addressing mode to a
> single base register with no offset. The operand is the memroy location,
> not the register holding the memory location, so this constraint won't
> necessarily use x2. Unless 'pop_reg' itself is passed into a register
> constraint, the compiler might not ensure that 'x2' is populated.
> 
> For example:
> 
> | [mark@gravadlaks:~/tests/asm-operands-q-reg]% cat test.c
> | unsigned long foo(unsigned long *ptr)
> | {
> |         register unsigned long *ptr_reg asm("x2") = ptr;
> |         unsigned long val;
> |
> |         asm volatile(
> |         "       ldr     %[val], %[qptr]\n"
> |         : [val] "=&r" (val)
> |         : [qptr] "Q" (*ptr_reg)
> |         );
> |
> |         return val;
> | }
> | [mark@gravadlaks:~/tests/asm-operands-q-reg]% usekorg 16.2.0 aarch64-linux-gcc -c test.c -O2
> | [mark@gravadlaks:~/tests/asm-operands-q-reg]% usekorg 16.2.0 aarch64-linux-objdump -d test.o
> |
> | test.o:     file format elf64-littleaarch64
> |
> |
> | Disassembly of section .text:
> |
> | 0000000000000000 <foo>:
> |    0:   f9400001        ldr     x1, [x0]
> |    4:   aa0103e0        mov     x0, x1
> |    8:   d65f03c0        ret
> 
> We will need an "r" input constraint for 'pop_reg' to ensure that x2 is
> allocated. Either in addition to an "=Q" output constraint for the
> actual memory write, or we rely on the memory clobber to hazaard against
> other memory accesses.
> 
> Secondly, the "Q" input constaint for 'lock' looks inaccurate, given
> that we both read and write to 'lock'. Either that should be a "+Q"
> output constraint, or we rely on the memory clobber to hazard against
> other memory accesses.
> 

Thank you very much Mark, that is a lot of good information about 
writing arm64 asm!

If I understood correctly, the correct approach here would be to use 
pop_reg as an input operand, making sure that we store the address hold 
by *pop on x2 register right? So something along the lines:

__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, 
__u64 *pop)
{
	register __u64 pop_reg asm("x2") = (__u64) pop;

...

		"	str 	xzr, [%x[pop_reg]]		\n"
...

		: [val] "=&r" (val),
		  [result] "=&r" (result_reg),
		  [lock] "+Q" (*lock)
		: [tid] "r" (tid),
		  [pop_reg] "r" (pop_reg)
		: "cc", "memory"

Does that looks right?

Thanks again for the help


> Mark.
> 
>> +
>> +	return val;
>> +}
>>
>> -- 
>> 2.55.0
>>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
  2026-09-16 14:28   ` Mark Rutland
@ 2026-09-17  1:11     ` André Almeida
  2026-09-17 10:50       ` Mark Rutland
  0 siblings, 1 reply; 16+ messages in thread
From: André Almeida @ 2026-09-17  1:11 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

Em 16/09/2026 11:28, Mark Rutland escreveu:
> On Fri, Aug 21, 2026 at 06:50:45PM -0300, André Almeida wrote:
>> Based on aarch64 implementation, provide a 32 bit entry point for
>> this vDSO.
>>
>> In order to keep compatibility with arm64_futex_robust_unlock_get_pop(),
>> make sure to store the pop address at r2 and the compare result value
>> at r3.
> 
> Before we add this to the compat vdso, we'll need to implement this on
> arch/arm/.
> 
> Otherwise, my comments on the patch for the native vdso functions apply
> here too.
> 

Right, and the compat entry point at arch/arm64/ would point to the 
__vdso_futex_robust_list32_try_unlock implementation at arch/arm/?

> Mark.
> 
>>
>> Signed-off-by: André Almeida <andrealmeid@igalia.com>
>> ---
>> v7:
>>   - The store needs to be a release store, so s/strex/stlex/
>>   - result reg clobber modified to "=&r" to make sure the compiler don't use
>>   the r3 reg for something else
>>   - pop_reg will be read after the execution so it should be an output
>>   parameter with "+Q"
>> ---
>>   arch/arm64/kernel/vdso.c            | 15 ++++++++++++++-
>>   arch/arm64/kernel/vdso32/Makefile   |  4 ++++
>>   arch/arm64/kernel/vdso32/vdso.lds.S |  9 +++++++++
>>   arch/arm64/kernel/vdso32/vfutex.c   | 34 ++++++++++++++++++++++++++++++++++
>>   4 files changed, 61 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
>> index dc6b582736d0..5cae9c17ec72 100644
>> --- a/arch/arm64/kernel/vdso.c
>> +++ b/arch/arm64/kernel/vdso.c
>> @@ -78,11 +78,19 @@ static inline void vdso_futex_update_ips(struct mm_struct *mm)
>>   				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_end));
>>   }
>>   
>> +static inline void aarch32_vdso_futex_update_ips(struct mm_struct *mm)
>> +{
>> +	unsigned long vdso = (unsigned long) mm->context.vdso;
>> +
>> +	__vdso_futex_update_ips(mm, true,
>> +				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_start),
>> +				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_end));
>> +}
>>   #else
>>   static inline void vdso_futex_update_ips(struct mm_struct *mm) {}
>> +static inline void aarch32_vdso_futex_update_ips(struct mm_struct *mm) {}
>>   #endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
>>   
>> -
>>   static int vdso_mremap(const struct vm_special_mapping *sm,
>>   		struct vm_area_struct *new_vma)
>>   {
>> @@ -195,6 +203,8 @@ static int aarch32_mremap(const struct vm_special_mapping *sm,
>>   {
>>   	current->mm->context.vdso = (void *)new_vma->vm_start;
>>   
>> +	aarch32_vdso_futex_update_ips(current->mm);
>> +
>>   	return 0;
>>   }
>>   
>> @@ -327,6 +337,7 @@ static int aarch32_sigreturn_setup(struct mm_struct *mm)
>>   	return PTR_ERR_OR_ZERO(ret);
>>   }
>>   
>> +
>>   int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
>>   {
>>   	struct mm_struct *mm = current->mm;
>> @@ -347,6 +358,8 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
>>   	}
>>   
>>   	ret = aarch32_sigreturn_setup(mm);
>> +
>> +	aarch32_vdso_futex_update_ips(mm);
>>   out:
>>   	mmap_write_unlock(mm);
>>   	return ret;
>> diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
>> index 4bd60f059f4a..f3190125c68b 100644
>> --- a/arch/arm64/kernel/vdso32/Makefile
>> +++ b/arch/arm64/kernel/vdso32/Makefile
>> @@ -97,6 +97,10 @@ munge := ../../../arm/vdso/vdsomunge
>>   hostprogs := $(munge)
>>   
>>   c-obj-vdso := note.o
>> +ifdef CONFIG_FUTEX_ROBUST_UNLOCK
>> +  c-obj-vdso += vfutex.o
>> +endif
>> +
>>   c-obj-vdso-gettimeofday := vgettimeofday.o
>>   
>>   ifneq ($(c-gettimeofday-y),)
>> diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
>> index 12bfc39e8aab..52ced27d6045 100644
>> --- a/arch/arm64/kernel/vdso32/vdso.lds.S
>> +++ b/arch/arm64/kernel/vdso32/vdso.lds.S
>> @@ -89,6 +89,15 @@ VERSION
>>   #endif /* CONFIG_COMPAT_32BIT_TIME */
>>   		__vdso_clock_gettime64;
>>   		__vdso_clock_getres_time64;
>> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
>> +		__vdso_futex_robust_list32_try_unlock;
>> +#endif
>>   	local: *;
>>   	};
>>   }
>> +
>> +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
>> +VDSO_futex_list32_try_unlock_cs_success = __futex_list32_try_unlock_cs_success;
>> +VDSO_futex_list32_try_unlock_cs_start = __futex_list32_try_unlock_cs_start;
>> +VDSO_futex_list32_try_unlock_cs_end = __futex_list32_try_unlock_cs_end;
>> +#endif
>> diff --git a/arch/arm64/kernel/vdso32/vfutex.c b/arch/arm64/kernel/vdso32/vfutex.c
>> new file mode 100644
>> index 000000000000..0d9080b17965
>> --- /dev/null
>> +++ b/arch/arm64/kernel/vdso32/vfutex.c
>> @@ -0,0 +1,34 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +#include <linux/stringify.h>
>> +#include <vdso/futex.h>
>> +
>> +__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
>> +{
>> +	register __u32 *pop_reg asm("r2") = pop, result_reg asm("r3") = 0;
>> +	__u32 val, zero = 0;
>> +
>> +	asm volatile (
>> +		".globl						  "
>> +		"__futex_list32_try_unlock_cs_start,		  "
>> +		"__futex_list32_try_unlock_cs_success,		  "
>> +		"__futex_list32_try_unlock_cs_end		\n"
>> +
>> +		"retry:						\n"
>> +		"	ldrex %[val], %[lock]			\n"
>> +		"	cmp %[tid], %[val]			\n"
>> +		"	bne __futex_list32_try_unlock_cs_end	\n"
>> +		"	stlex %[result], %[zero], %[lock]	\n"
>> +		"__futex_list32_try_unlock_cs_start:		\n"
>> +		"	cmp %[result], #0			\n"
>> +		"	bne retry				\n"
>> +		"__futex_list32_try_unlock_cs_success:		\n"
>> +		"	str %[zero], %[pop_reg]			\n"
>> +		"__futex_list32_try_unlock_cs_end:		\n"
>> +
>> +		: [val] "=&r" (val), [result] "=&r" (result_reg), [pop_reg] "+Q" (*pop_reg)
>> +		: [tid] "r" (tid), [lock] "Q" (*lock), [zero] "r" (zero)
>> +		: "cc", "memory"
>> +	);
>> +
>> +	return val;
>> +}
>>
>> -- 
>> 2.55.0
>>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support
  2026-09-17  1:05     ` André Almeida
@ 2026-09-17 10:01       ` Mark Rutland
  2026-09-17 14:40         ` André Almeida
  0 siblings, 1 reply; 16+ messages in thread
From: Mark Rutland @ 2026-09-17 10:01 UTC (permalink / raw)
  To: André Almeida
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

On Wed, Sep 16, 2026 at 10:05:38PM -0300, André Almeida wrote:
> Em 16/09/2026 11:24, Mark Rutland escreveu:
> > I reckon this might also be clearer as:
> > 
> > | 	if (regs->regs[3])
> > | 		return NULL;
> > | 	
> > | 	return (void __user *)regs->regs[2];
> > 
> > Do we need a __force cast here, or is sparse happy without that?
> 
> I've just re-compiled those patches with C=1, and didn't find any warning
> for this.

Perfect, thanks for confirming!

[...]

> > > +	futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);
> > 
> > On arm64 (and every architecture other than x86, AFAICT), the
> > native/compat VDSOs are mutually exclusive, and a single mm can only
> > have one of them.
> > 
> > Given that, I think we can make this:
> > 
> > 	futex_set_vdso_cs_range(fd, 0, start, end, is_32bit);
> > 
> > That way we'll avoid confusing/bikesheeding over 'is_32bit ? 1 : 0',
> > without having to add mnemnonics for the native/compat CS indices.
> 
> Perfect, I will simplify that then.
> 
> > That said, what's the plan for 32-bit robust lists on a 64-bit host?
> > IIUC you wanted that for emulation, and AFAICT you have no way to call
> > __vdso_futex_robust_list32_try_unlock() from a native task.
> 
> Yes, the plan is to be able to use the 32-bit robust lists on a 64-bit
> hosts, with a new interface (set/get_robust_list2[1]). That means that a
> 64-bit kernel will be able to process an user robust list made of 32-bit
> pointers. So the emulator will call set_robust_list2() one time for it's own
> list, and another time for the emulated app list.
> 
> However, what we have agreed for the moment is that, while there's no
> support for that, we will not expose the 32-bit functions yet [2]:

Ah, thanks for the pointer! I had mistakenly assumed that some of
that had already happened.

I guess the common logic for futex_set_vdso_cs_range() will need to
change at that point I guess if/when that happens, you'd expect to add
__vdso_futex_robust_list32_try_unlock() into the 64-bit VDSO, regardless
of compat?

Mark.

> "...that requires also the ability to register a 32-bit robust list for a
> 64-bit process, which is not supported right now. So no, we are not exposing
> something half functional..."
> 
> So yes, in the near future I will need to expose
> __vdso_futex_robust_list32_try_unlock() to 64-bit apps as well, to be able
> to do this handling with 32-bit pointers, but we are not doing it right now.
> 
> [1] https://lore.kernel.org/lkml/20251122-tonyk-robust_futex-v6-0-05fea005a0fd@igalia.com/
> 
> [2] https://lore.kernel.org/lkml/878q9vwote.ffs@tglx/
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
  2026-09-17  1:06     ` André Almeida
@ 2026-09-17 10:45       ` Mark Rutland
  0 siblings, 0 replies; 16+ messages in thread
From: Mark Rutland @ 2026-09-17 10:45 UTC (permalink / raw)
  To: André Almeida
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

On Wed, Sep 16, 2026 at 10:06:25PM -0300, André Almeida wrote:
> If I understood correctly, the correct approach here would be to use pop_reg
> as an input operand, making sure that we store the address hold by *pop on
> x2 register right? So something along the lines:
> 
> __u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64
> *pop)
> {
> 	register __u64 pop_reg asm("x2") = (__u64) pop;
> 
> ...
> 
> 		"	str 	xzr, [%x[pop_reg]]		\n"
> ...
> 
> 		: [val] "=&r" (val),
> 		  [result] "=&r" (result_reg),
> 		  [lock] "+Q" (*lock)
> 		: [tid] "r" (tid),
> 		  [pop_reg] "r" (pop_reg)
> 		: "cc", "memory"
> 
> Does that looks right?

Yep; that should work!

Just for completeness: another option would be to drop the memory
clobber, and have separate constraints for the "pop" memory location and
the "pop_reg" register. I think your suggestion above is simpler, so
let's go with that.

Mark.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
  2026-09-17  1:11     ` André Almeida
@ 2026-09-17 10:50       ` Mark Rutland
  2026-09-17 14:41         ` André Almeida
  0 siblings, 1 reply; 16+ messages in thread
From: Mark Rutland @ 2026-09-17 10:50 UTC (permalink / raw)
  To: André Almeida
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

On Wed, Sep 16, 2026 at 10:11:01PM -0300, André Almeida wrote:
> Em 16/09/2026 11:28, Mark Rutland escreveu:
> > On Fri, Aug 21, 2026 at 06:50:45PM -0300, André Almeida wrote:
> > > Based on aarch64 implementation, provide a 32 bit entry point for
> > > this vDSO.
> > > 
> > > In order to keep compatibility with arm64_futex_robust_unlock_get_pop(),
> > > make sure to store the pop address at r2 and the compare result value
> > > at r3.
> > 
> > Before we add this to the compat vdso, we'll need to implement this on
> > arch/arm/.
> > 
> > Otherwise, my comments on the patch for the native vdso functions apply
> > here too.
> 
> Right, and the compat entry point at arch/arm64/ would point to the
> __vdso_futex_robust_list32_try_unlock implementation at arch/arm/?

So far we've had arm64 provide its own copy (which e.g. might use
sequences relying on ARMv8+ instructions), so I think we'd do the same
here.

The key thing is that 32-bit tasks on arm64 should see the same ABI as
native tasks on 32-bit arm. As there's a risk that 32-bit arm might have
some ABI quirks (e.g. due to older processors), we don't want to enable
features for compat tasks on arm64 before that's been implemented on
32-bit arm.

Mark.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support
  2026-09-17 10:01       ` Mark Rutland
@ 2026-09-17 14:40         ` André Almeida
  0 siblings, 0 replies; 16+ messages in thread
From: André Almeida @ 2026-09-17 14:40 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

Em 17/09/2026 07:01, Mark Rutland escreveu:
> On Wed, Sep 16, 2026 at 10:05:38PM -0300, André Almeida wrote:
>> Em 16/09/2026 11:24, Mark Rutland escreveu:
>>> I reckon this might also be clearer as:
>>>
>>> | 	if (regs->regs[3])
>>> | 		return NULL;
>>> | 	
>>> | 	return (void __user *)regs->regs[2];
>>>
>>> Do we need a __force cast here, or is sparse happy without that?
>>
>> I've just re-compiled those patches with C=1, and didn't find any warning
>> for this.
> 
> Perfect, thanks for confirming!
> 
> [...]
> 
>>>> +	futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);
>>>
>>> On arm64 (and every architecture other than x86, AFAICT), the
>>> native/compat VDSOs are mutually exclusive, and a single mm can only
>>> have one of them.
>>>
>>> Given that, I think we can make this:
>>>
>>> 	futex_set_vdso_cs_range(fd, 0, start, end, is_32bit);
>>>
>>> That way we'll avoid confusing/bikesheeding over 'is_32bit ? 1 : 0',
>>> without having to add mnemnonics for the native/compat CS indices.
>>
>> Perfect, I will simplify that then.
>>
>>> That said, what's the plan for 32-bit robust lists on a 64-bit host?
>>> IIUC you wanted that for emulation, and AFAICT you have no way to call
>>> __vdso_futex_robust_list32_try_unlock() from a native task.
>>
>> Yes, the plan is to be able to use the 32-bit robust lists on a 64-bit
>> hosts, with a new interface (set/get_robust_list2[1]). That means that a
>> 64-bit kernel will be able to process an user robust list made of 32-bit
>> pointers. So the emulator will call set_robust_list2() one time for it's own
>> list, and another time for the emulated app list.
>>
>> However, what we have agreed for the moment is that, while there's no
>> support for that, we will not expose the 32-bit functions yet [2]:
> 
> Ah, thanks for the pointer! I had mistakenly assumed that some of
> that had already happened.
> 
> I guess the common logic for futex_set_vdso_cs_range() will need to
> change at that point I guess if/when that happens, you'd expect to add
> __vdso_futex_robust_list32_try_unlock() into the 64-bit VDSO, regardless
> of compat?
> 

Yes, given __vdso_futex_robust_list64_try_unlock() would write a 64-bit 
zero word in a 32-bit pointer, I probably need someway to expose 
__vdso_futex_robust_list32_try_unlock().

However, this will be need when a x86-32 bit app is running on top of 
the emulator, where the 32-bit glibc would eventually call the x86-32 
version of the VDSO. I will check what the emulator does with the other 
VDSOs, if they redirect to the native arm versions or what.

> Mark.
> 
>> "...that requires also the ability to register a 32-bit robust list for a
>> 64-bit process, which is not supported right now. So no, we are not exposing
>> something half functional..."
>>
>> So yes, in the near future I will need to expose
>> __vdso_futex_robust_list32_try_unlock() to 64-bit apps as well, to be able
>> to do this handling with 32-bit pointers, but we are not doing it right now.
>>
>> [1] https://lore.kernel.org/lkml/20251122-tonyk-robust_futex-v6-0-05fea005a0fd@igalia.com/
>>
>> [2] https://lore.kernel.org/lkml/878q9vwote.ffs@tglx/
>>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
  2026-09-17 10:50       ` Mark Rutland
@ 2026-09-17 14:41         ` André Almeida
  0 siblings, 0 replies; 16+ messages in thread
From: André Almeida @ 2026-09-17 14:41 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mathieu Desnoyers,
	Sebastian Andrzej Siewior, Peter Zijlstra, Florian Weimer,
	Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
	Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
	linux-kernel, linux-arch, kernel-dev

Em 17/09/2026 07:50, Mark Rutland escreveu:
> On Wed, Sep 16, 2026 at 10:11:01PM -0300, André Almeida wrote:
>> Em 16/09/2026 11:28, Mark Rutland escreveu:
>>> On Fri, Aug 21, 2026 at 06:50:45PM -0300, André Almeida wrote:
>>>> Based on aarch64 implementation, provide a 32 bit entry point for
>>>> this vDSO.
>>>>
>>>> In order to keep compatibility with arm64_futex_robust_unlock_get_pop(),
>>>> make sure to store the pop address at r2 and the compare result value
>>>> at r3.
>>>
>>> Before we add this to the compat vdso, we'll need to implement this on
>>> arch/arm/.
>>>
>>> Otherwise, my comments on the patch for the native vdso functions apply
>>> here too.
>>
>> Right, and the compat entry point at arch/arm64/ would point to the
>> __vdso_futex_robust_list32_try_unlock implementation at arch/arm/?
> 
> So far we've had arm64 provide its own copy (which e.g. might use
> sequences relying on ARMv8+ instructions), so I think we'd do the same
> here.
> 
> The key thing is that 32-bit tasks on arm64 should see the same ABI as
> native tasks on 32-bit arm. As there's a risk that 32-bit arm might have
> some ABI quirks (e.g. due to older processors), we don't want to enable
> features for compat tasks on arm64 before that's been implemented on
> 32-bit arm.
Gotcha, makes perfect sense.

Thanks!
	André

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-09-17 14:41 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-21 21:50 [PATCH v8 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
2026-08-21 21:50 ` [PATCH v8 1/4] arm64: vdso: Prepare for robust futex unlock support André Almeida
2026-09-16 14:24   ` Mark Rutland
2026-09-17  1:05     ` André Almeida
2026-09-17 10:01       ` Mark Rutland
2026-09-17 14:40         ` André Almeida
2026-08-21 21:50 ` [PATCH v8 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
2026-09-16 14:27   ` Mark Rutland
2026-09-17  1:06     ` André Almeida
2026-09-17 10:45       ` Mark Rutland
2026-08-21 21:50 ` [PATCH v8 3/4] arm64: vdso32: Bring vdso32-offsets.h back André Almeida
2026-08-21 21:50 ` [PATCH v8 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock() André Almeida
2026-09-16 14:28   ` Mark Rutland
2026-09-17  1:11     ` André Almeida
2026-09-17 10:50       ` Mark Rutland
2026-09-17 14:41         ` André Almeida

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®