From 35432ecaae4a8372a6f40a6cac476f0140094c7c Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <gscrivan@redhat.com>
Date: Fri, 8 Mar 2019 12:40:43 +0100
Subject: [PATCH] rootless: fix rm when uid in the container != 0

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
---
 cmd/podman/main.go |  1 +
 cmd/podman/rm.go   | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 1d3db70eb8..c347a922d8 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 4230bb396d..56aaae9ebf 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 {