summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe Scrivano <gscrivan@redhat.com>2018-09-19 14:09:46 +0200
committerAtomic Bot <atomic-devel@projectatomic.io>2018-09-21 10:13:39 +0000
commit6d1eecf7cf10fe736d86479dbb0ac0377fc89488 (patch)
tree7914da853909e46f43b49bcaa124edc529c89341
parent1c73404fe142e7ac09200ea26945dddff8f44431 (diff)
downloadpodman-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.go7
-rw-r--r--pkg/rootless/rootless_linux.go70
-rw-r--r--pkg/rootless/rootless_unsupported.go6
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")
+}