From 966eeb811b64e55a6fd72c55b36100027b3be747 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 24 Aug 2022 23:15:37 +0200 Subject: [PATCH] unshare: improve rootless detection in addition to check the UID of the user that launched the command, also check whether the process has CAP_SYS_ADMIN (in the same way as podman/pkg/rootless does) and also check that the current user namespace has all the IDs available. Closes: https://github.com/containers/storage/issues/1311 After this change, podman/pkg/rootless can use the function directly instead of defining another version with similar functionalities. Signed-off-by: Giuseppe Scrivano --- pkg/unshare/unshare_linux.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pkg/unshare/unshare_linux.go b/pkg/unshare/unshare_linux.go index c86390bd38..8793b4a8b2 100644 --- a/pkg/unshare/unshare_linux.go +++ b/pkg/unshare/unshare_linux.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "io" + "io/ioutil" "os" "os/exec" "os/signal" @@ -387,10 +388,42 @@ const ( UsernsEnvName = "_CONTAINERS_USERNS_CONFIGURED" ) +// hasFullUsersMappings checks whether the current user namespace has all the IDs mapped. +// current user namespace +func hasFullUsersMappings() (bool, error) { + content, err := ioutil.ReadFile("/proc/self/uid_map") + if err != nil { + return false, err + } + // Both runc and crun check whether the current process is in a user namespace + // by looking up 4294967295 in /proc/self/uid_map. If the mappings would be + // copied as they are, the check in the OCI runtimes would fail. So just split + // it in two different ranges. + return bytes.Contains(content, []byte("4294967295")), nil +} + // IsRootless tells us if we are running in rootless mode func IsRootless() bool { isRootlessOnce.Do(func() { isRootless = getRootlessUID() != 0 || getenv(UsernsEnvName) != "" + if !isRootless { + hasCapSysAdmin, err := HasCapSysAdmin() + if err != nil { + logrus.Warnf("Failed to read CAP_SYS_ADMIN presence for the current process") + } + if err == nil && !hasCapSysAdmin { + isRootless = true + } + } + if !isRootless { + hasMappings, err := hasFullUsersMappings() + if err != nil { + logrus.Warnf("Failed to read current user namespace mappings") + } + if err == nil && !hasMappings { + isRootless = true + } + } }) return isRootless }