From 1789242933ddbc3e4a29662f5218b5b94ee30863 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 29 Aug 2018 10:01:45 +0200 Subject: rootless: add new function to join existing namespace Signed-off-by: Giuseppe Scrivano Closes: #1371 Approved by: rhatdan --- pkg/rootless/rootless_linux.c | 32 +++++++++++++++++++++++++++++++- pkg/rootless/rootless_linux.go | 29 ++++++++++++++++++++++++++++- pkg/rootless/rootless_unsupported.go | 6 ++++++ 3 files changed, 65 insertions(+), 2 deletions(-) (limited to 'pkg/rootless') diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 1b98f76eb..e894328ce 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -83,7 +83,37 @@ get_cmd_line_args (pid_t pid) } int -reexec_in_user_namespace(int ready) +reexec_userns_join (int userns) +{ + pid_t ppid = getpid (); + char uid[16]; + char **argv; + int pid; + + sprintf (uid, "%d", geteuid ()); + + argv = get_cmd_line_args (ppid); + if (argv == NULL) + _exit (EXIT_FAILURE); + + pid = fork (); + if (pid) + return pid; + + setenv ("_LIBPOD_USERNS_CONFIGURED", "init", 1); + setenv ("_LIBPOD_ROOTLESS_UID", uid, 1); + + if (setns (userns, 0) < 0) + _exit (EXIT_FAILURE); + close (userns); + + execvp (argv[0], argv); + + _exit (EXIT_FAILURE); +} + +int +reexec_in_user_namespace (int ready) { int ret; pid_t pid; diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 904d22ee2..e218dede0 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -23,6 +23,7 @@ import ( /* extern int reexec_in_user_namespace(int ready); extern int reexec_in_user_namespace_wait(int pid); +extern int reexec_userns_join(int userns); */ import "C" @@ -84,6 +85,32 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) return cmd.Run() } +// JoinNS re-exec podman in a new userNS and join the user namespace of the specified +// PID. +func JoinNS(pid uint) (bool, int, error) { + if os.Getuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" { + return false, -1, nil + } + + userNS, err := GetUserNSForPid(pid) + if err != nil { + return false, -1, err + } + defer userNS.Close() + + pidC := C.reexec_userns_join(C.int(userNS.Fd())) + if int(pidC) < 0 { + return false, -1, errors.Errorf("cannot re-exec process") + } + + ret := C.reexec_in_user_namespace_wait(pidC) + if ret < 0 { + return false, -1, errors.New("error waiting for the re-exec process") + } + + return true, int(ret), nil +} + // BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed // into a new user namespace and the return code from the re-executed podman process. // If podman was re-executed the caller needs to propagate the error code returned by the child @@ -183,7 +210,7 @@ func BecomeRootInUserNS() (bool, int, error) { ret := C.reexec_in_user_namespace_wait(pidC) if ret < 0 { - return false, -1, errors.Wrapf(err, "error waiting for the re-exec process") + return false, -1, errors.New("error waiting for the re-exec process") } return true, int(ret), nil diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go index 93b04adfd..e0adb3453 100644 --- a/pkg/rootless/rootless_unsupported.go +++ b/pkg/rootless/rootless_unsupported.go @@ -33,6 +33,12 @@ func SkipStorageSetup() bool { return false } +// JoinNS re-exec podman in a new userNS and join the user namespace of the specified +// PID. +func JoinNS(pid uint) (bool, int, error) { + return false, -1, errors.New("this function is not supported on this os") +} + // GetUserNSForPid returns an open FD for the first direct child user namespace that created the process func GetUserNSForPid(pid uint) (*os.File, error) { return nil, errors.New("this function is not supported on this os") -- cgit v1.2.3-54-g00ecf