mirror of https://github.com/containers/podman.git
rootless: attempt to copy current mappings first
when creating a user namespace, attempt to create it first by copying the current mappings and then fallback to the other methods: 1) use newidmap tools and ... 2) create a user namespace with a single user mapped. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
parent
24f00e4695
commit
e4c269e2d0
|
@ -4,6 +4,7 @@ package rootless
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/pkg/errorhandling"
|
"github.com/containers/podman/v3/pkg/errorhandling"
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
|
"github.com/containers/storage/pkg/unshare"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
@ -67,6 +69,15 @@ func IsRootless() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isRootless = os.Geteuid() != 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != ""
|
isRootless = os.Geteuid() != 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != ""
|
||||||
|
if !isRootless {
|
||||||
|
hasCapSysAdmin, err := unshare.HasCapSysAdmin()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("failed to read CAP_SYS_ADMIN presence for the current process")
|
||||||
|
}
|
||||||
|
if err == nil && !hasCapSysAdmin {
|
||||||
|
isRootless = true
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return isRootless
|
return isRootless
|
||||||
}
|
}
|
||||||
|
@ -142,8 +153,12 @@ func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) err
|
||||||
// namespace of the specified PID without looking up its parent. Useful to join directly
|
// namespace of the specified PID without looking up its parent. Useful to join directly
|
||||||
// the conmon process.
|
// the conmon process.
|
||||||
func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
|
func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
|
||||||
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
|
hasCapSysAdmin, err := unshare.HasCapSysAdmin()
|
||||||
return false, -1, nil
|
if err != nil {
|
||||||
|
return false, 0, err
|
||||||
|
}
|
||||||
|
if hasCapSysAdmin || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
|
||||||
|
return false, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cPausePid := C.CString(pausePid)
|
cPausePid := C.CString(pausePid)
|
||||||
|
@ -192,8 +207,28 @@ func GetConfiguredMappings() ([]idtools.IDMap, []idtools.IDMap, error) {
|
||||||
return uids, gids, nil
|
return uids, gids, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyMappings(from, to string) error {
|
||||||
|
content, err := ioutil.ReadFile(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Both runc and crun check whether the current process is in a user namespace
|
||||||
|
// by looking up 4294967295 in /proc/self/uid_map. If the mappings would be
|
||||||
|
// copied as they are, the check in the OCI runtimes would fail. So just split
|
||||||
|
// it in two different ranges.
|
||||||
|
if bytes.Contains(content, []byte("4294967295")) {
|
||||||
|
content = []byte("0 0 1\n1 1 4294967294\n")
|
||||||
|
}
|
||||||
|
return ioutil.WriteFile(to, content, 0600)
|
||||||
|
}
|
||||||
|
|
||||||
func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ bool, _ int, retErr error) {
|
func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ bool, _ int, retErr error) {
|
||||||
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
|
hasCapSysAdmin, err := unshare.HasCapSysAdmin()
|
||||||
|
if err != nil {
|
||||||
|
return false, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasCapSysAdmin || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
|
||||||
if os.Getenv("_CONTAINERS_USERNS_CONFIGURED") == "init" {
|
if os.Getenv("_CONTAINERS_USERNS_CONFIGURED") == "init" {
|
||||||
return false, 0, runInUser()
|
return false, 0, runInUser()
|
||||||
}
|
}
|
||||||
|
@ -250,8 +285,16 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
|
||||||
return false, -1, err
|
return false, -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uidMap := fmt.Sprintf("/proc/%d/uid_map", pid)
|
||||||
|
gidMap := fmt.Sprintf("/proc/%d/gid_map", pid)
|
||||||
|
|
||||||
uidsMapped := false
|
uidsMapped := false
|
||||||
if uids != nil {
|
|
||||||
|
if err := copyMappings("/proc/self/uid_map", uidMap); err == nil {
|
||||||
|
uidsMapped = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if uids != nil && !uidsMapped {
|
||||||
err := tryMappingTool(true, pid, os.Geteuid(), uids)
|
err := tryMappingTool(true, pid, os.Geteuid(), uids)
|
||||||
// If some mappings were specified, do not ignore the error
|
// If some mappings were specified, do not ignore the error
|
||||||
if err != nil && len(uids) > 0 {
|
if err != nil && len(uids) > 0 {
|
||||||
|
@ -268,7 +311,6 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
|
||||||
}
|
}
|
||||||
logrus.Debugf("write setgroups file exited with 0")
|
logrus.Debugf("write setgroups file exited with 0")
|
||||||
|
|
||||||
uidMap := fmt.Sprintf("/proc/%d/uid_map", pid)
|
|
||||||
err = ioutil.WriteFile(uidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Geteuid())), 0666)
|
err = ioutil.WriteFile(uidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Geteuid())), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, -1, errors.Wrapf(err, "cannot write uid_map")
|
return false, -1, errors.Wrapf(err, "cannot write uid_map")
|
||||||
|
@ -277,7 +319,10 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
|
||||||
}
|
}
|
||||||
|
|
||||||
gidsMapped := false
|
gidsMapped := false
|
||||||
if gids != nil {
|
if err := copyMappings("/proc/self/gid_map", gidMap); err == nil {
|
||||||
|
gidsMapped = true
|
||||||
|
}
|
||||||
|
if gids != nil && !gidsMapped {
|
||||||
err := tryMappingTool(false, pid, os.Getegid(), gids)
|
err := tryMappingTool(false, pid, os.Getegid(), gids)
|
||||||
// If some mappings were specified, do not ignore the error
|
// If some mappings were specified, do not ignore the error
|
||||||
if err != nil && len(gids) > 0 {
|
if err != nil && len(gids) > 0 {
|
||||||
|
@ -286,7 +331,6 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
|
||||||
gidsMapped = err == nil
|
gidsMapped = err == nil
|
||||||
}
|
}
|
||||||
if !gidsMapped {
|
if !gidsMapped {
|
||||||
gidMap := fmt.Sprintf("/proc/%d/gid_map", pid)
|
|
||||||
err = ioutil.WriteFile(gidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getegid())), 0666)
|
err = ioutil.WriteFile(gidMap, []byte(fmt.Sprintf("%d %d 1\n", 0, os.Getegid())), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, -1, errors.Wrapf(err, "cannot write gid_map")
|
return false, -1, errors.Wrapf(err, "cannot write gid_map")
|
||||||
|
|
Loading…
Reference in New Issue