From 1a26b1686c9c62830029440a6b13ee4c8dcc5434 Mon Sep 17 00:00:00 2001 From: Gabi Beyer Date: Tue, 25 Jun 2019 17:29:08 +0000 Subject: [PATCH] Add rootless package from containers/libpod Add rootless package to kata in order to include some rootless functionalities including: 1. Determining whether an exectution is being ran rootless or not, 2. Get the rootless UID of a process, and 3. Get the rootless runtime directory for nonroot users. Signed-off-by: Gabi Beyer --- pkg/rootless/rootless.c | 18 ++++++++ pkg/rootless/rootless.go | 98 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 pkg/rootless/rootless.c create mode 100644 pkg/rootless/rootless.go diff --git a/pkg/rootless/rootless.c b/pkg/rootless/rootless.c new file mode 100644 index 0000000000..da917b1830 --- /dev/null +++ b/pkg/rootless/rootless.c @@ -0,0 +1,18 @@ +#define _GNU_SOURCE +#include + +static uid_t rootless_uid_init; +static gid_t rootless_gid_init; + +uid_t +rootless_uid () +{ + return rootless_uid_init; +} + +uid_t +rootless_gid () +{ + return rootless_gid_init; +} + diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go new file mode 100644 index 0000000000..a61af58f11 --- /dev/null +++ b/pkg/rootless/rootless.go @@ -0,0 +1,98 @@ +package rootless + +import ( + "fmt" + "os" + "path/filepath" + "strconv" + "sync" + "syscall" + + "github.com/pkg/errors" +) + +/* +#include +extern uid_t rootless_uid(); +extern uid_t rootless_gid(); +*/ +import "C" + +var ( + isRootlessOnce sync.Once + isRootless bool + + rootlessRuntimeDirOnce sync.Once + rootlessRuntimeDir string +) + +// IsRootless tells us if we are running in rootless mode +func IsRootless() bool { + isRootlessOnce.Do(func() { + rootlessUIDInit := int(C.rootless_uid()) + rootlessGIDInit := int(C.rootless_gid()) + if rootlessUIDInit != 0 { + // This happens if we joined the user+mount namespace as part of + os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done") + os.Setenv("_CONTAINERS_ROOTLESS_UID", fmt.Sprintf("%d", rootlessUIDInit)) + os.Setenv("_CONTAINERS_ROOTLESS_GID", fmt.Sprintf("%d", rootlessGIDInit)) + } + isRootless = os.Geteuid() != 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" + }) + return isRootless +} + +// GetRootlessUID returns the UID of the user in the parent userNS +func GetRootlessUID() int { + uidEnv := os.Getenv("_CONTAINERS_ROOTLESS_UID") + if uidEnv != "" { + u, _ := strconv.Atoi(uidEnv) + return u + } + return os.Geteuid() +} + +// GetRootlessRuntimeDir returns the runtime directory when running as non root +func GetRootlessRuntimeDir() (string, error) { + var rootlessRuntimeDirError error + + rootlessRuntimeDirOnce.Do(func() { + runtimeDir := os.Getenv("XDG_RUNTIME_DIR") + uid := fmt.Sprintf("%d", GetRootlessUID()) + if runtimeDir == "" { + tmpDir := filepath.Join("/run", "user", uid) + os.MkdirAll(tmpDir, 0700) + st, err := os.Stat(tmpDir) + if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 { + runtimeDir = tmpDir + } + } + if runtimeDir == "" { + tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("run-%s", uid)) + os.MkdirAll(tmpDir, 0700) + st, err := os.Stat(tmpDir) + if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 { + runtimeDir = tmpDir + } + } + if runtimeDir == "" { + home := os.Getenv("HOME") + if home == "" { + rootlessRuntimeDirError = fmt.Errorf("neither XDG_RUNTIME_DIR nor HOME was set non-empty") + return + } + resolvedHome, err := filepath.EvalSymlinks(home) + if err != nil { + rootlessRuntimeDirError = errors.Wrapf(err, "cannot resolve %s", home) + return + } + runtimeDir = filepath.Join(resolvedHome, "rundir") + } + rootlessRuntimeDir = runtimeDir + }) + + if rootlessRuntimeDirError != nil { + return "", rootlessRuntimeDirError + } + return rootlessRuntimeDir, nil +}