diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/domain/infra/abi/system.go | 7 | ||||
-rw-r--r-- | pkg/machine/ignition.go | 16 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 65 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 33 |
4 files changed, 111 insertions, 10 deletions
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 6319c1ab1..9bba0fa6c 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -21,6 +21,7 @@ import ( "github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/utils" "github.com/containers/storage" + "github.com/containers/storage/pkg/unshare" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -58,7 +59,11 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) { func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error { // do it only after podman has already re-execed and running with uid==0. - if os.Geteuid() == 0 { + hasCapSysAdmin, err := unshare.HasCapSysAdmin() + if err != nil { + return err + } + if hasCapSysAdmin { ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup() if err != nil { logrus.Infof("Failed to detect the owner for the current cgroup: %v", err) diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index cc5c01de6..00068a136 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -168,6 +168,22 @@ func getFiles(usrName string) []File { }, FileEmbedded1: FileEmbedded1{Mode: intToPtr(420)}, }) + + // Set machine_enabled to true to indicate we're in a VM + files = append(files, File{ + Node: Node{ + Group: getNodeGrp("root"), + Path: "/etc/containers/containers.conf", + User: getNodeUsr("root"), + }, + FileEmbedded1: FileEmbedded1{ + Append: nil, + Contents: Resource{ + Source: strToPtr("data:,%5Bengine%5D%0Amachine_enabled%3Dtrue%0A"), + }, + Mode: intToPtr(420), + }, + }) return files } diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index dda230dbc..fdfeed854 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -4,6 +4,7 @@ package rootless import ( "bufio" + "bytes" "fmt" "io" "io/ioutil" @@ -18,6 +19,7 @@ import ( "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/storage/pkg/idtools" + "github.com/containers/storage/pkg/unshare" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -67,6 +69,15 @@ func IsRootless() bool { } } 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 } @@ -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 // the conmon process. func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) { - if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" { - return false, -1, nil + hasCapSysAdmin, err := unshare.HasCapSysAdmin() + if err != nil { + return false, 0, err + } + if hasCapSysAdmin || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" { + return false, 0, nil } cPausePid := C.CString(pausePid) @@ -180,8 +195,11 @@ func GetConfiguredMappings() ([]idtools.IDMap, []idtools.IDMap, error) { } mappings, err := idtools.NewIDMappings(username, username) if err != nil { - logrus.Errorf( - "cannot find UID/GID for user %s: %v - check rootless mode in man pages.", username, err) + logLevel := logrus.ErrorLevel + if os.Geteuid() == 0 && GetRootlessUID() == 0 { + logLevel = logrus.DebugLevel + } + logrus.StandardLogger().Logf(logLevel, "cannot find UID/GID for user %s: %v - check rootless mode in man pages.", username, err) } else { uids = mappings.UIDs() gids = mappings.GIDs() @@ -189,8 +207,28 @@ func GetConfiguredMappings() ([]idtools.IDMap, []idtools.IDMap, error) { 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) { - 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" { return false, 0, runInUser() } @@ -247,8 +285,16 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo return false, -1, err } + uidMap := fmt.Sprintf("/proc/%d/uid_map", pid) + gidMap := fmt.Sprintf("/proc/%d/gid_map", pid) + 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) // If some mappings were specified, do not ignore the error if err != nil && len(uids) > 0 { @@ -265,7 +311,6 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo } 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) if err != nil { return false, -1, errors.Wrapf(err, "cannot write uid_map") @@ -274,7 +319,10 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo } 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) // If some mappings were specified, do not ignore the error if err != nil && len(gids) > 0 { @@ -283,7 +331,6 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo gidsMapped = err == nil } 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) if err != nil { return false, -1, errors.Wrapf(err, "cannot write gid_map") diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 13d4b4926..2f623bf10 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -6,12 +6,14 @@ import ( "path/filepath" "strings" + cdi "github.com/container-orchestrated-devices/container-device-interface/pkg" "github.com/containers/common/pkg/config" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/image" "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/util" "github.com/containers/storage/types" + spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -136,6 +138,11 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener options = append(options, libpod.WithNetworkAliases(s.Aliases)) } + if len(s.Devices) > 0 { + opts = extractCDIDevices(s) + options = append(options, opts...) + } + runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command) if err != nil { return nil, err @@ -143,6 +150,32 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener return rt.NewContainer(ctx, runtimeSpec, options...) } +func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption { + devs := make([]spec.LinuxDevice, 0, len(s.Devices)) + var cdiDevs []string + var options []libpod.CtrCreateOption + + for _, device := range s.Devices { + isCDIDevice, err := cdi.HasDevice(device.Path) + if err != nil { + logrus.Debugf("CDI HasDevice Error: %v", err) + } + if err == nil && isCDIDevice { + cdiDevs = append(cdiDevs, device.Path) + continue + } + + devs = append(devs, device) + } + + s.Devices = devs + if len(cdiDevs) > 0 { + options = append(options, libpod.WithCDI(cdiDevs)) + } + + return options +} + func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) { var options []libpod.CtrCreateOption var err error |