From 231129e4dc083d9f63cf1876cc1695f7f8c03f25 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 8 Mar 2019 12:06:16 +0100 Subject: [PATCH] rootless: fix pod stop|rm if uid in the container != 0 join the user namespace where the pod is running, so that we can both manage the storage and correctly send the kill signal to a process which is not running as root in the namespace. Closes: https://github.com/containers/libpod/issues/2577 Signed-off-by: Giuseppe Scrivano --- cmd/podman/main.go | 2 ++ cmd/podman/pod.go | 47 +++++++++++++++++++++++++++++++++++ cmd/podman/pod_rm.go | 14 +++++++++++ cmd/podman/pod_stop.go | 14 +++++++++++ pkg/adapter/runtime.go | 40 +++++++++++++++++++++++++++++ pkg/adapter/runtime_remote.go | 7 ++++++ 6 files changed, 124 insertions(+) diff --git a/cmd/podman/main.go b/cmd/podman/main.go index c347a922d8..1c6217dac6 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -70,8 +70,10 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{ _mountCommand: true, _killCommand: true, _pauseCommand: true, + _podRmCommand: true, _podKillCommand: true, _podStatsCommand: true, + _podStopCommand: true, _restartCommand: true, _rmCommand: true, _runCommand: true, diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go index 2d9bca21de..9a9c7a7021 100644 --- a/cmd/podman/pod.go +++ b/cmd/podman/pod.go @@ -1,7 +1,12 @@ package main import ( + "os" + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/rootless" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -34,6 +39,48 @@ var podSubCommands = []*cobra.Command{ _podUnpauseCommand, } +func joinPodNS(runtime *adapter.LocalRuntime, all, latest bool, inputArgs []string) ([]string, bool, bool, error) { + if rootless.IsRootless() { + if os.Geteuid() == 0 { + return []string{rootless.Argument()}, false, false, nil + } else { + var err error + var pods []*adapter.Pod + if all { + pods, err = runtime.GetAllPods() + if err != nil { + return nil, false, false, errors.Wrapf(err, "unable to get pods") + } + } else if latest { + pod, err := runtime.GetLatestPod() + if err != nil { + return nil, false, false, errors.Wrapf(err, "unable to get latest pod") + } + pods = append(pods, pod) + } else { + for _, i := range inputArgs { + pod, err := runtime.LookupPod(i) + if err != nil { + return nil, false, false, errors.Wrapf(err, "unable to lookup pod %s", i) + } + pods = append(pods, pod) + } + } + for _, p := range pods { + _, ret, err := runtime.JoinOrCreateRootlessPod(p) + if err != nil { + return nil, false, false, err + } + if ret != 0 { + os.Exit(ret) + } + } + os.Exit(0) + } + } + return inputArgs, all, latest, nil +} + func init() { podCommand.AddCommand(podSubCommands...) podCommand.SetHelpTemplate(HelpTemplate()) diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go index a409928182..735676f8a5 100644 --- a/cmd/podman/pod_rm.go +++ b/cmd/podman/pod_rm.go @@ -2,9 +2,11 @@ package main import ( "fmt" + "os" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -46,11 +48,23 @@ func init() { // podRmCmd deletes pods func podRmCmd(c *cliconfig.PodRmValues) error { + if os.Geteuid() != 0 { + rootless.SetSkipStorageSetup(true) + } runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } defer runtime.Shutdown(false) + + if rootless.IsRootless() { + var err error + c.InputArgs, c.All, c.Latest, err = joinPodNS(runtime, c.All, c.Latest, c.InputArgs) + if err != nil { + return err + } + } + podRmIds, podRmErrors := runtime.RemovePods(getContext(), c) for _, p := range podRmIds { fmt.Println(p) diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go index f1b0ac51fd..754a3a7db5 100644 --- a/cmd/podman/pod_stop.go +++ b/cmd/podman/pod_stop.go @@ -2,9 +2,11 @@ package main import ( "fmt" + "os" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -46,12 +48,24 @@ func init() { } func podStopCmd(c *cliconfig.PodStopValues) error { + if os.Geteuid() != 0 { + rootless.SetSkipStorageSetup(true) + } + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } defer runtime.Shutdown(false) + if rootless.IsRootless() { + var err error + c.InputArgs, c.All, c.Latest, err = joinPodNS(runtime, c.All, c.Latest, c.InputArgs) + if err != nil { + return err + } + } + podStopIds, podStopErrors := runtime.StopPods(getContext(), c) for _, p := range podStopIds { fmt.Println(p) diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 732b895306..482b6119a5 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -337,3 +337,43 @@ func IsImageNotFound(err error) bool { func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.HealthCheckStatus, error) { return r.Runtime.HealthCheck(c.InputArgs[0]) } + +// JoinOrCreateRootlessPod joins the specified pod if it is running or it creates a new user namespace +// if the pod is stopped +func (r *LocalRuntime) JoinOrCreateRootlessPod(pod *Pod) (bool, int, error) { + if os.Geteuid() == 0 { + return false, 0, nil + } + opts := rootless.Opts{ + Argument: pod.ID(), + } + + inspect, err := pod.Inspect() + if err != nil { + return false, 0, err + } + for _, ctr := range inspect.Containers { + prevCtr, err := r.LookupContainer(ctr.ID) + if err != nil { + return false, -1, err + } + s, err := prevCtr.State() + if err != nil { + return false, -1, err + } + if s != libpod.ContainerStateRunning && s != libpod.ContainerStatePaused { + continue + } + data, err := ioutil.ReadFile(prevCtr.Config().ConmonPidFile) + if err != nil { + return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", prevCtr.Config().ConmonPidFile) + } + conmonPid, err := strconv.Atoi(string(data)) + if err != nil { + return false, -1, errors.Wrapf(err, "cannot parse PID %q", data) + } + return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts) + } + + return rootless.BecomeRootInUserNSWithOpts(&opts) +} diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index 10c25c3f34..9ca4e245f7 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -751,3 +751,10 @@ func IsImageNotFound(err error) bool { func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.HealthCheckStatus, error) { return -1, libpod.ErrNotImplemented } + +// JoinOrCreateRootlessPod joins the specified pod if it is running or it creates a new user namespace +// if the pod is stopped +func (r *LocalRuntime) JoinOrCreateRootlessPod(pod *Pod) (bool, int, error) { + // Nothing to do in the remote case + return true, 0, nil +}