rootless: correctly propagate the exit status from the container

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano
2018-07-11 09:49:30 +02:00
parent 0066374fc3
commit 62e48e5b71
4 changed files with 24 additions and 21 deletions

View File

@@ -27,13 +27,13 @@ func main() {
debug := false debug := false
cpuProfile := false cpuProfile := false
became, err := rootless.BecomeRootInUserNS() became, ret, err := rootless.BecomeRootInUserNS()
if err != nil { if err != nil {
logrus.Errorf(err.Error()) logrus.Errorf(err.Error())
os.Exit(1) os.Exit(1)
} }
if became { if became {
os.Exit(0) os.Exit(ret)
} }
if reexec.Init() { if reexec.Init() {

View File

@@ -105,16 +105,16 @@ reexec_in_user_namespace(int ready)
ret = read (ready, &b, 1) < 0; ret = read (ready, &b, 1) < 0;
while (ret < 0 && errno == EINTR); while (ret < 0 && errno == EINTR);
if (ret < 0) if (ret < 0)
_exit (1); _exit (EXIT_FAILURE);
close (ready); close (ready);
if (setresgid (0, 0, 0) < 0 || if (setresgid (0, 0, 0) < 0 ||
setresuid (0, 0, 0) < 0) setresuid (0, 0, 0) < 0)
_exit (1); _exit (EXIT_FAILURE);
execvp (argv[0], argv); execvp (argv[0], argv);
_exit (1); _exit (EXIT_FAILURE);
} }
int int

View File

@@ -67,14 +67,16 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
return cmd.Run() return cmd.Run()
} }
// BecomeRootInUserNS re-exec podman in a new userNS // BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed
func BecomeRootInUserNS() (bool, error) { // 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.Getuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" {
if os.Getenv("_LIBPOD_USERNS_CONFIGURED") == "init" { if os.Getenv("_LIBPOD_USERNS_CONFIGURED") == "init" {
return false, runInUser() return false, 0, runInUser()
} }
return false, nil return false, 0, nil
} }
runtime.LockOSThread() runtime.LockOSThread()
@@ -82,7 +84,7 @@ func BecomeRootInUserNS() (bool, error) {
r, w, err := os.Pipe() r, w, err := os.Pipe()
if err != nil { if err != nil {
return false, err return false, -1, err
} }
defer r.Close() defer r.Close()
defer w.Close() defer w.Close()
@@ -90,13 +92,13 @@ func BecomeRootInUserNS() (bool, error) {
pidC := C.reexec_in_user_namespace(C.int(r.Fd())) pidC := C.reexec_in_user_namespace(C.int(r.Fd()))
pid := int(pidC) pid := int(pidC)
if pid < 0 { 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) setgroups := fmt.Sprintf("/proc/%d/setgroups", pid)
err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666) err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666)
if err != nil { 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 var uids, gids []idtools.IDMap
@@ -115,7 +117,7 @@ func BecomeRootInUserNS() (bool, error) {
uidMap := fmt.Sprintf("/proc/%d/uid_map", pid) uidMap := fmt.Sprintf("/proc/%d/uid_map", pid)
err = ioutil.WriteFile(uidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getuid())), 0666) err = ioutil.WriteFile(uidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getuid())), 0666)
if err != nil { 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) gidMap := fmt.Sprintf("/proc/%d/gid_map", pid)
err = ioutil.WriteFile(gidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getgid())), 0666) err = ioutil.WriteFile(gidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getgid())), 0666)
if err != nil { 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")) _, err = w.Write([]byte("1"))
if err != nil { 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) c := make(chan os.Signal, 1)
@@ -150,9 +152,10 @@ func BecomeRootInUserNS() (bool, error) {
} }
}() }()
if C.reexec_in_user_namespace_wait(pidC) < 0 { ret := C.reexec_in_user_namespace_wait(pidC)
return false, errors.Wrapf(err, "error waiting for the re-exec process") if ret < 0 {
return false, -1, errors.Wrapf(err, "error waiting for the re-exec process")
} }
return true, nil return true, int(ret), nil
} }

View File

@@ -13,8 +13,8 @@ func IsRootless() bool {
// BecomeRootInUserNS is a stub function that always returns false and an // BecomeRootInUserNS is a stub function that always returns false and an
// error on unsupported OS's // error on unsupported OS's
func BecomeRootInUserNS() (bool, error) { func BecomeRootInUserNS() (bool, int, error) {
return false, errors.New("this function is not supported on this os") return false, -1, errors.New("this function is not supported on this os")
} }
// GetRootlessUID returns the UID of the user in the parent userNS // GetRootlessUID returns the UID of the user in the parent userNS