diff options
author | Giuseppe Scrivano <gscrivan@redhat.com> | 2018-09-19 14:09:46 +0200 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-09-21 10:13:39 +0000 |
commit | 6d1eecf7cf10fe736d86479dbb0ac0377fc89488 (patch) | |
tree | 7914da853909e46f43b49bcaa124edc529c89341 | |
parent | 1c73404fe142e7ac09200ea26945dddff8f44431 (diff) | |
download | podman-6d1eecf7cf10fe736d86479dbb0ac0377fc89488.tar.gz podman-6d1eecf7cf10fe736d86479dbb0ac0377fc89488.tar.bz2 podman-6d1eecf7cf10fe736d86479dbb0ac0377fc89488.zip |
create, rootless: join the userns of ns:PATH
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Closes: #1507
Approved by: rhatdan
-rw-r--r-- | cmd/podman/create.go | 7 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 70 | ||||
-rw-r--r-- | pkg/rootless/rootless_unsupported.go | 6 |
3 files changed, 74 insertions, 9 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 134752f88..07e75ad3a 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -838,6 +838,13 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l } } + namespacesStr := []string{string(createConfig.IpcMode), string(createConfig.NetMode), string(createConfig.UsernsMode), string(createConfig.PidMode), string(createConfig.UtsMode)} + for _, i := range namespacesStr { + if cc.IsNS(i) { + return rootless.JoinNSPath(cc.NS(i)) + } + } + namespaces := []namespace{createConfig.IpcMode, createConfig.NetMode, createConfig.UsernsMode, createConfig.PidMode, createConfig.UtsMode} for _, i := range namespaces { if i.IsContainer() { diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 92020cf1c..a9a914a62 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -111,6 +111,32 @@ func JoinNS(pid uint) (bool, int, error) { return true, int(ret), nil } +// JoinNSPath re-exec podman in a new userNS and join the owner user namespace of the +// specified path. +func JoinNSPath(path string) (bool, int, error) { + if os.Geteuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" { + return false, -1, nil + } + + userNS, err := getUserNSForPath(path) + 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 @@ -229,6 +255,15 @@ func readUserNsFd(fd uintptr) (string, error) { return readUserNs(filepath.Join("/proc/self/fd", fmt.Sprintf("%d", fd))) } +func getOwner(fd uintptr) (uintptr, error) { + const nsGetUserns = 0xb701 + ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetUserns), 0) + if errno != 0 { + return 0, errno + } + return (uintptr)(unsafe.Pointer(ret)), nil +} + func getParentUserNs(fd uintptr) (uintptr, error) { const nsGetParent = 0xb702 ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetParent), 0) @@ -238,7 +273,31 @@ func getParentUserNs(fd uintptr) (uintptr, error) { return (uintptr)(unsafe.Pointer(ret)), nil } -// getUserNSForPid returns an open FD for the first direct child user namespace that created the process +func getUserNSForPath(path string) (*os.File, error) { + u, err := os.Open(path) + if err != nil { + return nil, errors.Wrapf(err, "cannot open %s", path) + } + defer u.Close() + fd, err := getOwner(u.Fd()) + if err != nil { + return nil, err + } + + return getUserNSFirstChild(fd) +} + +func getUserNSForPid(pid uint) (*os.File, error) { + path := filepath.Join("/proc", fmt.Sprintf("%d", pid), "ns/user") + u, err := os.Open(path) + if err != nil { + return nil, errors.Wrapf(err, "cannot open %s", path) + } + + return getUserNSFirstChild(u.Fd()) +} + +// getUserNSFirstChild returns an open FD for the first direct child user namespace that created the process // Each container creates a new user namespace where the runtime runs. The current process in the container // might have created new user namespaces that are child of the initial namespace we created. // This function finds the initial namespace created for the container that is a child of the current namespace. @@ -250,19 +309,12 @@ func getParentUserNs(fd uintptr) (uintptr, error) { // b // / // NS READ USING THE PID -> c -func getUserNSForPid(pid uint) (*os.File, error) { +func getUserNSFirstChild(fd uintptr) (*os.File, error) { currentNS, err := readUserNs("/proc/self/ns/user") if err != nil { return nil, err } - path := filepath.Join("/proc", fmt.Sprintf("%d", pid), "ns/user") - u, err := os.Open(path) - if err != nil { - return nil, errors.Wrapf(err, "cannot open %s", path) - } - - fd := u.Fd() ns, err := readUserNsFd(fd) if err != nil { return nil, errors.Wrapf(err, "cannot read user namespace") diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go index 31728e5c2..d72402c9f 100644 --- a/pkg/rootless/rootless_unsupported.go +++ b/pkg/rootless/rootless_unsupported.go @@ -36,3 +36,9 @@ func SkipStorageSetup() bool { func JoinNS(pid uint) (bool, int, error) { return false, -1, errors.New("this function is not supported on this os") } + +// JoinNSPath re-exec podman in a new userNS and join the owner user namespace of the +// specified path. +func JoinNSPath(path string) (bool, int, error) { + return false, -1, errors.New("this function is not supported on this os") +} |