From 0e231729fdfbea0b137c9622c03f98c92fa56942 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sat, 4 Apr 2026 18:00:13 +0000 Subject: [PATCH] machined: skip leader ownership check for user scope When registering a machine, machined verifies that the leader process is owned by the calling user via process_is_owned_by_uid(). This check fails for user scope machined when the leader is inside a user namespace: after the leader calls setns(CLONE_NEWUSER), it becomes non-dumpable, and the subsequent ptrace_may_access() check in the kernel denies access to the process's user namespace, since the calling user lacks CAP_SYS_PTRACE in the mm's user namespace (the host namespace), even though the user owns the child user namespace. Skip this check when running in user scope. For system scope, the check is important because multiple users share the same machined instance, so one user must not be able to claim another user's process as a machine leader. For user scope this is unnecessary: the varlink socket lives under $XDG_RUNTIME_DIR (mode 0700), so only the owning user can connect, and the user machined instance can only perform operations bounded by that user's own privileges. Registering a foreign PID does not escalate capabilities. --- src/machine/machine-varlink.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index dfc7020fc9..07a860f6c1 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -192,8 +192,10 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink if (r < 0) return r; - /* Ensure an unprivileged user cannot claim any process they don't control as their own machine */ - if (machine->uid != 0) { + /* In system scope, ensure an unprivileged user cannot claim any process they don't + * control as their own machine. In user scope the varlink socket is already + * protected by $XDG_RUNTIME_DIR permissions. */ + if (manager->runtime_scope != RUNTIME_SCOPE_USER && machine->uid != 0) { r = process_is_owned_by_uid(&machine->leader, machine->uid); if (r < 0) return r;