From 9e253545ca4a449ef67eaaddc57b3f94101a5423 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 8 Oct 2026 23:22:44 -0700 Subject: [PATCH] systemd: DetectUID: use $ROOTLESSKIT_PARENT_EUID if set When running in a user namespace, DetectUID uses `busctl --user status` to get the OwnerUID. This fails when /proc is mounted with hidepid=2, as busctl can't read /proc/ of the bus peer. In such case runc (which uses DetectUID to decide whether to use rootless cgroup manager) assumes the UID is 0, and so it fails to start a container under RootlessKit with systemd cgroup driver: unable to start unit "runc-xxx.scope" (properties [... {Name:Slice Value:"system.slice"} ...]): ... read unix @->/run/systemd/private: read: connection reset by peer RootlessKit sets $ROOTLESSKIT_PARENT_EUID (documented since RootlessKit v0.8.0) for its child process, so use it if set. Fixes https://github.com/opencontainers/runc/issues/3124. Signed-off-by: Kir Kolyshkin --- systemd/user.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/systemd/user.go b/systemd/user.go index 4a4348e..6befb1e 100644 --- a/systemd/user.go +++ b/systemd/user.go @@ -48,12 +48,24 @@ func newUserSystemdDbus() (*systemdDbus.Conn, error) { // DetectUID detects UID from the OwnerUID field of `busctl --user status` // if running in userNS. The value corresponds to sd_bus_creds_get_owner_uid(3) . +// If running under RootlessKit, the value of $ROOTLESSKIT_PARENT_EUID is +// used instead. // // Otherwise returns os.Getuid() . func DetectUID() (int, error) { if !userns.RunningInUserNS() { return os.Getuid(), nil } + // RootlessKit sets $ROOTLESSKIT_PARENT_EUID for its child process. + // Prefer it to busctl, which fails to obtain the OwnerUID when + // /proc is mounted with hidepid=2 (or hidepid=invisible). + if env := os.Getenv("ROOTLESSKIT_PARENT_EUID"); env != "" { + uid, err := strconv.Atoi(env) + if err != nil { + return -1, fmt.Errorf("invalid $ROOTLESSKIT_PARENT_EUID value %q: %w", env, err) + } + return uid, nil + } b, err := exec.Command("busctl", "--user", "--no-pager", "status").CombinedOutput() if err != nil { return -1, fmt.Errorf("could not execute `busctl --user --no-pager status` (output: %q): %w", string(b), err)