mirror of
https://github.com/containers/podman.git
synced 2025-08-01 07:40:22 +08:00
create, rootless: join the userns of ns:PATH
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> Closes: #1507 Approved by: rhatdan
This commit is contained in:

committed by
Atomic Bot

parent
1c73404fe1
commit
6d1eecf7cf
@ -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() {
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
}
|
||||
|
Reference in New Issue
Block a user