From 4a0fb35335bd9b0f78bb63d13da6a46d6b8843d8 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 8 Mar 2019 19:36:58 +0100 Subject: rootless: do not create automatically a userns for pod kill Signed-off-by: Giuseppe Scrivano --- cmd/podman/main.go | 1 + 1 file changed, 1 insertion(+) (limited to 'cmd') diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 7d4b650a9..ef68ebb2e 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -70,6 +70,7 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{ _mountCommand: true, _killCommand: true, _pauseCommand: true, + _podKillCommand: true, _restartCommand: true, _runCommand: true, _unpauseCommand: true, -- cgit v1.2.3-54-g00ecf From d6ebccf7c2cc2d337de497bb8388895aa8320b1d Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 8 Mar 2019 12:10:40 +0100 Subject: rootless: disable pod stats Signed-off-by: Giuseppe Scrivano --- cmd/podman/main.go | 27 ++++++++++++++------------- cmd/podman/pod_stats.go | 5 +++++ 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/main.go b/cmd/podman/main.go index ef68ebb2e..1d3db70eb 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -65,19 +65,20 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{ _exportCommand: true, //// `info` must be executed in an user namespace. //// If this change, please also update libpod.refreshRootless() - _loginCommand: true, - _logoutCommand: true, - _mountCommand: true, - _killCommand: true, - _pauseCommand: true, - _podKillCommand: true, - _restartCommand: true, - _runCommand: true, - _unpauseCommand: true, - _searchCommand: true, - _statsCommand: true, - _stopCommand: true, - _topCommand: true, + _loginCommand: true, + _logoutCommand: true, + _mountCommand: true, + _killCommand: true, + _pauseCommand: true, + _podKillCommand: true, + _podStatsCommand: true, + _restartCommand: true, + _runCommand: true, + _unpauseCommand: true, + _searchCommand: true, + _statsCommand: true, + _stopCommand: true, + _topCommand: true, } var rootCmd = &cobra.Command{ diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go index 7dbd84525..5c30e0595 100644 --- a/cmd/podman/pod_stats.go +++ b/cmd/podman/pod_stats.go @@ -53,6 +53,11 @@ func init() { } func podStatsCmd(c *cliconfig.PodStatsValues) error { + + if os.Geteuid() != 0 { + return errors.New("stats is not supported in rootless mode") + } + format := c.Format all := c.All latest := c.Latest -- cgit v1.2.3-54-g00ecf From 35432ecaae4a8372a6f40a6cac476f0140094c7c Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 8 Mar 2019 12:40:43 +0100 Subject: rootless: fix rm when uid in the container != 0 Signed-off-by: Giuseppe Scrivano --- cmd/podman/main.go | 1 + cmd/podman/rm.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) (limited to 'cmd') diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 1d3db70eb..c347a922d 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -73,6 +73,7 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{ _podKillCommand: true, _podStatsCommand: true, _restartCommand: true, + _rmCommand: true, _runCommand: true, _unpauseCommand: true, _searchCommand: true, diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index 4230bb396..56aaae9eb 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -2,12 +2,16 @@ package main import ( "fmt" + "io/ioutil" + "os" + "strconv" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -48,11 +52,39 @@ func init() { markFlagHiddenForRemoteClient("latest", flags) } +func joinContainerOrCreateRootlessUserNS(runtime *libpod.Runtime, ctr *libpod.Container) (bool, int, error) { + if os.Geteuid() == 0 { + return false, 0, nil + } + s, err := ctr.State() + if err != nil { + return false, -1, err + } + opts := rootless.Opts{ + Argument: ctr.ID(), + } + if s == libpod.ContainerStateRunning || s == libpod.ContainerStatePaused { + data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile) + if err != nil { + return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", ctr.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) +} + // saveCmd saves the image to either docker-archive or oci func rmCmd(c *cliconfig.RmValues) error { var ( deleteFuncs []shared.ParallelWorkerInput ) + if os.Geteuid() != 0 { + rootless.SetSkipStorageSetup(true) + } ctx := getContext() runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) @@ -61,6 +93,53 @@ func rmCmd(c *cliconfig.RmValues) error { } defer runtime.Shutdown(false) + if rootless.IsRootless() { + // When running in rootless mode we cannot manage different containers and + // user namespaces from the same context, so be sure to re-exec once for each + // container we are dealing with. + // What we do is to first collect all the containers we want to delete, then + // we re-exec in each of the container namespaces and from there remove the single + // container. + var container *libpod.Container + if os.Geteuid() == 0 { + // We are in the namespace, override InputArgs with the single + // argument that was passed down to us. + c.All = false + c.Latest = false + c.InputArgs = []string{rootless.Argument()} + } else { + var containers []*libpod.Container + if c.All { + containers, err = runtime.GetContainers() + } else if c.Latest { + container, err = runtime.GetLatestContainer() + if err != nil { + return errors.Wrapf(err, "unable to get latest pod") + } + containers = append(containers, container) + } else { + for _, c := range c.InputArgs { + container, err = runtime.LookupContainer(c) + if err != nil { + return err + } + containers = append(containers, container) + } + } + // Now we really delete the containers. + for _, c := range containers { + _, ret, err := joinContainerOrCreateRootlessUserNS(runtime, c) + if err != nil { + return err + } + if ret != 0 { + os.Exit(ret) + } + } + os.Exit(0) + } + } + failureCnt := 0 delContainers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all") if err != nil { -- cgit v1.2.3-54-g00ecf From 231129e4dc083d9f63cf1876cc1695f7f8c03f25 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 8 Mar 2019 12:06:16 +0100 Subject: 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(+) (limited to 'cmd') diff --git a/cmd/podman/main.go b/cmd/podman/main.go index c347a922d..1c6217dac 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 2d9bca21d..9a9c7a702 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 a40992818..735676f8a 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 f1b0ac51f..754a3a7db 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 732b89530..482b6119a 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 10c25c3f3..9ca4e245f 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 +} -- cgit v1.2.3-54-g00ecf