diff options
Diffstat (limited to 'libpod/runtime.go')
-rw-r--r-- | libpod/runtime.go | 125 |
1 files changed, 122 insertions, 3 deletions
diff --git a/libpod/runtime.go b/libpod/runtime.go index 98ca2d5a4..3518ed25a 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -2,10 +2,14 @@ package libpod import ( "bufio" + "bytes" "context" "fmt" "os" + "os/exec" "path/filepath" + "regexp" + "strconv" "strings" "sync" "syscall" @@ -25,6 +29,7 @@ import ( "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/util" "github.com/containers/storage" + "github.com/containers/storage/pkg/unshare" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/docker/docker/pkg/namesgenerator" spec "github.com/opencontainers/runtime-spec/specs-go" @@ -32,6 +37,17 @@ import ( "github.com/sirupsen/logrus" ) +const ( + // conmonMinMajorVersion is the major version required for conmon. + conmonMinMajorVersion = 2 + + // conmonMinMinorVersion is the minor version required for conmon. + conmonMinMinorVersion = 0 + + // conmonMinPatchVersion is the sub-minor version required for conmon. + conmonMinPatchVersion = 24 +) + // A RuntimeOption is a functional option which alters the Runtime created by // NewRuntime type RuntimeOption func(*Runtime) error @@ -260,7 +276,7 @@ func getLockManager(runtime *Runtime) (lock.Manager, error) { // Sets up containers/storage, state store, OCI runtime func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { // Find a working conmon binary - cPath, err := runtime.config.FindConmon() + cPath, err := findConmon(runtime.config.Engine.ConmonPath) if err != nil { return err } @@ -323,9 +339,16 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { } logrus.Debugf("Set libpod namespace to %q", runtime.config.Engine.Namespace) + hasCapSysAdmin, err := unshare.HasCapSysAdmin() + if err != nil { + return err + } + + needsUserns := !hasCapSysAdmin + // Set up containers/storage var store storage.Store - if os.Geteuid() != 0 { + if needsUserns { logrus.Debug("Not configuring container store") } else if runtime.noStore { logrus.Debug("No store required. Not opening container store.") @@ -465,7 +488,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { // If we need to refresh, then it is safe to assume there are // no containers running. Create immediately a namespace, as // we will need to access the storage. - if os.Geteuid() != 0 { + if needsUserns { aliveLock.Unlock() // Unlock to avoid deadlock as BecomeRootInUserNS will reexec. pausePid, err := util.GetRootlessPauseProcessPidPathGivenDir(runtime.config.Engine.TmpDir) if err != nil { @@ -532,6 +555,102 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { return nil } +// findConmon iterates over conmonPaths and returns the path +// to the first conmon binary with a new enough version. If none is found, +// we try to do a path lookup of "conmon". +func findConmon(conmonPaths []string) (string, error) { + foundOutdatedConmon := false + for _, path := range conmonPaths { + stat, err := os.Stat(path) + if err != nil { + continue + } + if stat.IsDir() { + continue + } + if err := probeConmon(path); err != nil { + logrus.Warnf("Conmon at %s invalid: %v", path, err) + foundOutdatedConmon = true + continue + } + logrus.Debugf("Using conmon: %q", path) + return path, nil + } + + // Search the $PATH as last fallback + if path, err := exec.LookPath("conmon"); err == nil { + if err := probeConmon(path); err != nil { + logrus.Warnf("Conmon at %s is invalid: %v", path, err) + foundOutdatedConmon = true + } else { + logrus.Debugf("Using conmon from $PATH: %q", path) + return path, nil + } + } + + if foundOutdatedConmon { + return "", errors.Wrapf(define.ErrConmonOutdated, + "please update to v%d.%d.%d or later", + conmonMinMajorVersion, conmonMinMinorVersion, conmonMinPatchVersion) + } + + return "", errors.Wrapf(define.ErrInvalidArg, + "could not find a working conmon binary (configured options: %v)", + conmonPaths) +} + +// probeConmon calls conmon --version and verifies it is a new enough version for +// the runtime expectations the container engine currently has. +func probeConmon(conmonBinary string) error { + cmd := exec.Command(conmonBinary, "--version") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return err + } + r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`) + + matches := r.FindStringSubmatch(out.String()) + if len(matches) != 4 { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + major, err := strconv.Atoi(matches[1]) + if err != nil { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + if major < conmonMinMajorVersion { + return define.ErrConmonOutdated + } + if major > conmonMinMajorVersion { + return nil + } + + minor, err := strconv.Atoi(matches[2]) + if err != nil { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + if minor < conmonMinMinorVersion { + return define.ErrConmonOutdated + } + if minor > conmonMinMinorVersion { + return nil + } + + patch, err := strconv.Atoi(matches[3]) + if err != nil { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + if patch < conmonMinPatchVersion { + return define.ErrConmonOutdated + } + if patch > conmonMinPatchVersion { + return nil + } + + return nil +} + // TmpDir gets the current Libpod temporary files directory. func (r *Runtime) TmpDir() (string, error) { if !r.valid { |