[PATCH v6 9/9] futex: Use new robust list API internally

André Almeida
2025-11-22T05:51:39Z

The new robust list API internals can handle any kind of robust list, so
to simplify the code, reuse the same mechanisms for the original API and
when calling the original set syscall, set the head in the array of
lists. The first two indexes of the array of robust lists are reserved
for the original API lists, the native robust list and the compat robust
list.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
include/linux/futex.h | 4 ----
include/linux/sched.h | 5 -----
kernel/futex/core.c | 12 ------------
kernel/futex/syscalls.c | 52 ++++++++++++++++++++++++-------------------------
4 files changed, 25 insertions(+), 48 deletions(-)

diff --git a/include/linux/futex.h b/include/linux/futex.h
index 3dba249bcd32..ce27f6307c60 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -87,10 +87,6 @@ static inline bool futex_in_32bit_syscall(void)

static inline void futex_init_task(struct task_struct *tsk)
{
- tsk->robust_list = NULL;
-#ifdef CONFIG_COMPAT
- tsk->robust_list32 = NULL;
-#endif
tsk->futex_robust_lists = NULL;
INIT_LIST_HEAD(&tsk->pi_state_list);
tsk->pi_state_cache = NULL;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index de2f3cbe4953..e0f28e7f0a2d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -75,7 +75,6 @@ struct pid_namespace;
struct pipe_inode_info;
struct rcu_node;
struct reclaim_state;
-struct robust_list_head;
struct root_domain;
struct rq;
struct sched_attr;
@@ -1330,11 +1329,7 @@ struct task_struct {
u32 rmid;
#endif
#ifdef CONFIG_FUTEX
- struct robust_list_head __user *robust_list;
uintptr_t *futex_robust_lists;
-#ifdef CONFIG_COMPAT
- struct robust_list_head32 __user *robust_list32;
-#endif
struct list_head pi_state_list;
struct futex_pi_state *pi_state_cache;
struct mutex futex_exit_mutex;
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index 14d8a7176367..f91df175033d 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -1500,18 +1500,6 @@ static void exit_robust_lists(struct task_struct *tsk)

static void futex_cleanup(struct task_struct *tsk)
{
- if (unlikely(tsk->robust_list)) {
- exit_robust_list(tsk, tsk->robust_list);
- tsk->robust_list = NULL;
- }
-
-#ifdef CONFIG_64BIT
- if (unlikely(tsk->robust_list32)) {
- exit_robust_list32(tsk, tsk->robust_list32);
- tsk->robust_list32 = NULL;
- }
-#endif
-
if (unlikely(tsk->futex_robust_lists))
exit_robust_lists(tsk);

diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c
index f730d16632fc..2a44791db37a 100644
--- a/kernel/futex/syscalls.c
+++ b/kernel/futex/syscalls.c
@@ -28,32 +28,29 @@
SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head,
size_t, len)
{
+ enum robust_list2_cmd cmd;
/*
* The kernel knows only one size for now:
*/
if (unlikely(len != sizeof(*head)))
return -EINVAL;

- current->robust_list = head;
+ cmd = IS_ENABLED(CONFIG_64BIT) ? FUTEX_ROBUST_LIST_CMD_SET_64 :
+ FUTEX_ROBUST_LIST_CMD_SET_32;

- return 0;
+ return futex_robust_list_set((uintptr_t) head, cmd,
+ FUTEX_ROBUST_LIST_NATIVE_IDX);
}

-static inline void __user *futex_task_robust_list(struct task_struct *p, bool compat)
-{
-#ifdef CONFIG_COMPAT
- if (compat)
- return p->robust_list32;
-#endif
- return p->robust_list;
-}
-
-static void __user *futex_get_robust_list_common(int pid, bool compat, int index)
+static void __user *futex_get_robust_list_common(int pid, unsigned int index)
{
struct task_struct *p = current;
void __user *head;
int ret;

+ if (index >= FUTEX_ROBUST_LIST2_MAX_IDX)
+ return (void __user *)ERR_PTR(-EINVAL);
+
scoped_guard(rcu) {
if (pid) {
p = find_task_by_vpid(pid);
@@ -75,14 +72,10 @@ static void __user *futex_get_robust_list_common(int pid, bool compat, int index
if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
goto err_unlock;

- if (index >= 0) {
- scoped_guard(mutex, &p->futex_exit_mutex) {
- uintptr_t *rl = p->futex_robust_lists;
+ scoped_guard(mutex, &p->futex_exit_mutex) {
+ uintptr_t *rl = p->futex_robust_lists;

- head = rl ? (void __user *) rl[index] : NULL;
- }
- } else {
- head = futex_task_robust_list(p, compat);
+ head = rl ? (void __user *) rl[index] : NULL;
}

up_read(&p->signal->exec_update_lock);
@@ -107,7 +100,11 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
struct robust_list_head __user * __user *, head_ptr,
size_t __user *, len_ptr)
{
- struct robust_list_head __user *head = futex_get_robust_list_common(pid, false, -1);
+ struct robust_list_head __user *head =
+ futex_get_robust_list_common(pid, FUTEX_ROBUST_LIST_NATIVE_IDX);
+
+ head = (struct robust_list_head __user *)
+ ((uintptr_t) head & FUTEX_ROBUST_LIST_ENTRY_MASK);

if (IS_ERR(head))
return PTR_ERR(head);
@@ -180,7 +177,7 @@ SYSCALL_DEFINE4(get_robust_list2, int, pid,
*/
index += FUTEX_ROBUST_LIST2_IDX;

- entry_ptr = futex_get_robust_list_common(pid, false, index);
+ entry_ptr = futex_get_robust_list_common(pid, index);
if (IS_ERR(entry_ptr))
return PTR_ERR(entry_ptr);

@@ -568,22 +565,23 @@ COMPAT_SYSCALL_DEFINE2(set_robust_list,
if (unlikely(len != sizeof(*head)))
return -EINVAL;

- current->robust_list32 = head;
-
- return 0;
+ return futex_robust_list_set((uintptr_t) head, FUTEX_ROBUST_LIST_CMD_SET_32,
+ FUTEX_ROBUST_LIST_COMPAT_IDX);
}

COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
compat_uptr_t __user *, head_ptr,
compat_size_t __user *, len_ptr)
{
- struct robust_list_head32 __user *head = futex_get_robust_list_common(pid, true, -1);
+ struct robust_list_head32 __user *head =
+ futex_get_robust_list_common(pid, FUTEX_ROBUST_LIST_COMPAT_IDX);

- if (IS_ERR(head))
- return PTR_ERR(head);
+ head = (struct robust_list_head32 __user *)
+ ((uintptr_t) head & FUTEX_ROBUST_LIST_ENTRY_MASK);

if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
+
return put_user(ptr_to_compat(head), head_ptr);
}
#endif /* CONFIG_COMPAT */

--
2.52.0