From 62e48e5b71abe3002361bbf018961f8031fba03e Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 11 Jul 2018 09:49:30 +0200 Subject: rootless: correctly propagate the exit status from the container Signed-off-by: Giuseppe Scrivano --- cmd/podman/main.go | 4 ++-- pkg/rootless/rootless_linux.c | 6 +++--- pkg/rootless/rootless_linux.go | 31 +++++++++++++++++-------------- pkg/rootless/rootless_unsupported.go | 4 ++-- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/cmd/podman/main.go b/cmd/podman/main.go index fefd8fdad..4d841e0f2 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -27,13 +27,13 @@ func main() { debug := false cpuProfile := false - became, err := rootless.BecomeRootInUserNS() + became, ret, err := rootless.BecomeRootInUserNS() if err != nil { logrus.Errorf(err.Error()) os.Exit(1) } if became { - os.Exit(0) + os.Exit(ret) } if reexec.Init() { diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index f2684f75f..d08c6c875 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -105,16 +105,16 @@ reexec_in_user_namespace(int ready) ret = read (ready, &b, 1) < 0; while (ret < 0 && errno == EINTR); if (ret < 0) - _exit (1); + _exit (EXIT_FAILURE); close (ready); if (setresgid (0, 0, 0) < 0 || setresuid (0, 0, 0) < 0) - _exit (1); + _exit (EXIT_FAILURE); execvp (argv[0], argv); - _exit (1); + _exit (EXIT_FAILURE); } int diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 55a55bbc6..6089ad73a 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -67,14 +67,16 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) return cmd.Run() } -// BecomeRootInUserNS re-exec podman in a new userNS -func BecomeRootInUserNS() (bool, error) { - +// 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 +// process. +func BecomeRootInUserNS() (bool, int, error) { if os.Getuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" { if os.Getenv("_LIBPOD_USERNS_CONFIGURED") == "init" { - return false, runInUser() + return false, 0, runInUser() } - return false, nil + return false, 0, nil } runtime.LockOSThread() @@ -82,7 +84,7 @@ func BecomeRootInUserNS() (bool, error) { r, w, err := os.Pipe() if err != nil { - return false, err + return false, -1, err } defer r.Close() defer w.Close() @@ -90,13 +92,13 @@ func BecomeRootInUserNS() (bool, error) { pidC := C.reexec_in_user_namespace(C.int(r.Fd())) pid := int(pidC) if pid < 0 { - return false, errors.Errorf("cannot re-exec process") + return false, -1, errors.Errorf("cannot re-exec process") } setgroups := fmt.Sprintf("/proc/%d/setgroups", pid) err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666) if err != nil { - return false, errors.Wrapf(err, "cannot write setgroups file") + return false, -1, errors.Wrapf(err, "cannot write setgroups file") } var uids, gids []idtools.IDMap @@ -115,7 +117,7 @@ func BecomeRootInUserNS() (bool, error) { uidMap := fmt.Sprintf("/proc/%d/uid_map", pid) err = ioutil.WriteFile(uidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getuid())), 0666) if err != nil { - return false, errors.Wrapf(err, "cannot write uid_map") + return false, -1, errors.Wrapf(err, "cannot write uid_map") } } @@ -127,13 +129,13 @@ func BecomeRootInUserNS() (bool, error) { gidMap := fmt.Sprintf("/proc/%d/gid_map", pid) err = ioutil.WriteFile(gidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getgid())), 0666) if err != nil { - return false, errors.Wrapf(err, "cannot write gid_map") + return false, -1, errors.Wrapf(err, "cannot write gid_map") } } _, err = w.Write([]byte("1")) if err != nil { - return false, errors.Wrapf(err, "write to sync pipe") + return false, -1, errors.Wrapf(err, "write to sync pipe") } c := make(chan os.Signal, 1) @@ -150,9 +152,10 @@ func BecomeRootInUserNS() (bool, error) { } }() - if C.reexec_in_user_namespace_wait(pidC) < 0 { - return false, errors.Wrapf(err, "error waiting for the re-exec process") + 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 true, nil + return true, int(ret), nil } diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go index a6efa73f5..b1f075045 100644 --- a/pkg/rootless/rootless_unsupported.go +++ b/pkg/rootless/rootless_unsupported.go @@ -13,8 +13,8 @@ func IsRootless() bool { // BecomeRootInUserNS is a stub function that always returns false and an // error on unsupported OS's -func BecomeRootInUserNS() (bool, error) { - return false, errors.New("this function is not supported on this os") +func BecomeRootInUserNS() (bool, int, error) { + return false, -1, errors.New("this function is not supported on this os") } // GetRootlessUID returns the UID of the user in the parent userNS -- cgit v1.2.3-54-g00ecf