From 1faf91187b86bf4ea1c4bc3688d847b1a32c0e62 Mon Sep 17 00:00:00 2001 From: Ievgen Bondarenko Date: Thu, 21 May 2026 19:00:30 -0700 Subject: [PATCH] futex: gate get_robust_list behind a ptrace access check get_robust_list(2) resolves a caller-supplied tid and copies out that task's robust-list head pointer with no permission check, so a task can read the robust-list head of any other task in its PID namespace, including a task owned by a different user. Linux gates this in kernel/futex/syscalls.c:do_get_robust_list(), which returns EPERM unless ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS) passes. process_vm_readv(2) already applies the equivalent Task.CanTrace check. Apply the same check before reading another task's robust-list head. --- pkg/sentry/syscalls/linux/sys_futex.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/sentry/syscalls/linux/sys_futex.go b/pkg/sentry/syscalls/linux/sys_futex.go index f406359bfe..6bffa6c4fd 100644 --- a/pkg/sentry/syscalls/linux/sys_futex.go +++ b/pkg/sentry/syscalls/linux/sys_futex.go @@ -306,6 +306,12 @@ func GetRobustList(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (u } } + // Inspecting another task's robust list requires ptrace read access, + // matching Linux's ptrace_may_access(PTRACE_MODE_READ_REALCREDS) check. + if ot != t && !t.CanTrace(ot, false /* attach */) { + return 0, nil, linuxerr.EPERM + } + // Copy out head pointer. head := t.Arch().Native(uintptr(ot.GetRobustList())) if _, err := head.CopyOut(t, headAddr); err != nil {