summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/cp.go31
-rw-r--r--cmd/podman/exec.go27
-rw-r--r--cmd/podman/main.go87
-rw-r--r--cmd/podman/pod.go47
-rw-r--r--cmd/podman/pod_restart.go10
-rw-r--r--cmd/podman/pod_rm.go9
-rw-r--r--cmd/podman/pod_stop.go9
-rw-r--r--cmd/podman/pod_top.go20
-rw-r--r--cmd/podman/restart.go27
-rw-r--r--cmd/podman/rm.go81
-rw-r--r--cmd/podman/shared/create.go73
-rw-r--r--cmd/podman/top.go13
-rw-r--r--libpod/runtime.go28
-rw-r--r--libpod/runtime_ctr.go33
-rw-r--r--pkg/adapter/runtime.go73
-rw-r--r--pkg/adapter/runtime_remote.go7
-rw-r--r--pkg/rootless/rootless.go9
-rw-r--r--pkg/rootless/rootless_linux.c41
-rw-r--r--pkg/rootless/rootless_linux.go263
-rw-r--r--pkg/rootless/rootless_unsupported.go36
20 files changed, 163 insertions, 761 deletions
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index d809fec6b..a0dd46260 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -1,10 +1,8 @@
package main
import (
- "io/ioutil"
"os"
"path/filepath"
- "strconv"
"strings"
"github.com/containers/buildah/pkg/chrootuser"
@@ -12,7 +10,6 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
@@ -87,34 +84,6 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
ctr = destCtr
}
- if os.Geteuid() != 0 {
- s, err := ctr.State()
- if err != nil {
- return err
- }
- var became bool
- var ret int
- if s == libpod.ContainerStateRunning || s == libpod.ContainerStatePaused {
- data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
- if err != nil {
- return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
- }
- conmonPid, err := strconv.Atoi(string(data))
- if err != nil {
- return errors.Wrapf(err, "cannot parse PID %q", data)
- }
- became, ret, err = rootless.JoinDirectUserAndMountNS(uint(conmonPid))
- } else {
- became, ret, err = rootless.BecomeRootInUserNS()
- }
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- }
-
mountPoint, err := ctr.Mount()
if err != nil {
return err
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index b8510f09a..f720a9aff 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -10,7 +10,6 @@ import (
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -106,32 +105,6 @@ func execCmd(c *cliconfig.ExecValues) error {
}
- if os.Geteuid() != 0 {
- var became bool
- var ret int
-
- data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
- if err == nil {
- conmonPid, err := strconv.Atoi(string(data))
- if err != nil {
- return errors.Wrapf(err, "cannot parse PID %q", data)
- }
- became, ret, err = rootless.JoinDirectUserAndMountNS(uint(conmonPid))
- } else {
- pid, err := ctr.PID()
- if err != nil {
- return err
- }
- became, ret, err = rootless.JoinNS(uint(pid), c.PreserveFDs)
- }
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- }
-
// ENVIRONMENT VARIABLES
env := map[string]string{}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 1ea7f74bf..4b1acd5a9 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -3,13 +3,16 @@ package main
import (
"context"
"io"
+ "io/ioutil"
"log/syslog"
"os"
"runtime/pprof"
+ "strconv"
"strings"
"syscall"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
_ "github.com/containers/libpod/pkg/hooks/0.1.0"
"github.com/containers/libpod/pkg/rootless"
@@ -59,36 +62,6 @@ var mainCommands = []*cobra.Command{
systemCommand.Command,
}
-var cmdsNotRequiringRootless = map[*cobra.Command]bool{
- _versionCommand: true,
- _createCommand: true,
- _execCommand: true,
- _cpCommand: true,
- _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,
- _podRmCommand: true,
- _podKillCommand: true,
- _podRestartCommand: true,
- _podStatsCommand: true,
- _podStopCommand: true,
- _podTopCommand: true,
- _restartCommand: true,
- &_psCommand: true,
- _rmCommand: true,
- _runCommand: true,
- _unpauseCommand: true,
- _searchCommand: true,
- _statsCommand: true,
- _stopCommand: true,
- _topCommand: true,
-}
-
var rootCmd = &cobra.Command{
Use: "podman",
Long: "manage pods and images",
@@ -152,18 +125,52 @@ func before(cmd *cobra.Command, args []string) error {
logrus.Errorf(err.Error())
os.Exit(1)
}
- if rootless.IsRootless() {
- notRequireRootless := cmdsNotRequiringRootless[cmd]
- if !notRequireRootless && !strings.HasPrefix(cmd.Use, "help") {
- became, ret, err := rootless.BecomeRootInUserNS()
- if err != nil {
- logrus.Errorf(err.Error())
- os.Exit(1)
- }
- if became {
- os.Exit(ret)
+ if os.Geteuid() != 0 && cmd != _searchCommand && cmd != _versionCommand && !strings.HasPrefix(cmd.Use, "help") {
+ podmanCmd := cliconfig.PodmanCommand{
+ cmd,
+ args,
+ MainGlobalOpts,
+ }
+ runtime, err := libpodruntime.GetRuntime(&podmanCmd)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ ctrs, err := runtime.GetRunningContainers()
+ if err != nil {
+ logrus.Errorf(err.Error())
+ os.Exit(1)
+ }
+ var became bool
+ var ret int
+ if len(ctrs) == 0 {
+ became, ret, err = rootless.BecomeRootInUserNS()
+ } else {
+ for _, ctr := range ctrs {
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ logrus.Errorf(err.Error())
+ os.Exit(1)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ logrus.Errorf(err.Error())
+ os.Exit(1)
+ }
+ became, ret, err = rootless.JoinUserAndMountNS(uint(conmonPid))
+ if err == nil {
+ break
+ }
}
}
+ if err != nil {
+ logrus.Errorf(err.Error())
+ os.Exit(1)
+ }
+ if became {
+ os.Exit(ret)
+ }
}
if MainGlobalOpts.Syslog {
diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go
index 9a9c7a702..2d9bca21d 100644
--- a/cmd/podman/pod.go
+++ b/cmd/podman/pod.go
@@ -1,12 +1,7 @@
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"
)
@@ -39,48 +34,6 @@ 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_restart.go b/cmd/podman/pod_restart.go
index f54c4b640..0765b98db 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -5,7 +5,6 @@ import (
"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"
@@ -53,15 +52,6 @@ func podRestartCmd(c *cliconfig.PodRestartValues) error {
}
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
- }
- }
-
restartIDs, conErrors, restartErrors := runtime.RestartPods(getContext(), c)
for _, p := range restartIDs {
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index 401073674..cd9f23fe1 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -5,7 +5,6 @@ import (
"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"
@@ -53,14 +52,6 @@ func podRmCmd(c *cliconfig.PodRmValues) error {
}
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 2b9f6ae0f..f1b0ac51f 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -5,7 +5,6 @@ import (
"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"
@@ -53,14 +52,6 @@ func podStopCmd(c *cliconfig.PodStopValues) error {
}
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/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index f15cf945d..0d74dc3d6 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -78,26 +78,6 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
descriptors = args[1:]
}
- if os.Geteuid() != 0 {
- var pod *adapter.Pod
- var err error
- if c.Latest {
- pod, err = runtime.GetLatestPod()
- } else {
- pod, err = runtime.LookupPod(c.InputArgs[0])
- }
- if err != nil {
- return errors.Wrapf(err, "unable to lookup requested container")
- }
- became, ret, err := runtime.JoinOrCreateRootlessPod(pod)
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- }
-
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
psOutput, err := runtime.PodTop(c, descriptors)
if err != nil {
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
index 8a034bdbc..1553ab805 100644
--- a/cmd/podman/restart.go
+++ b/cmd/podman/restart.go
@@ -1,13 +1,10 @@
package main
import (
- "os"
-
"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/pkg/rootless"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -57,16 +54,6 @@ func restartCmd(c *cliconfig.RestartValues) error {
restartContainers []*libpod.Container
)
- if rootless.IsRootless() {
- // If we are in the re-execed rootless environment,
- // override the arg to deal only with one container.
- if os.Geteuid() == 0 {
- c.All = false
- c.Latest = false
- c.InputArgs = []string{rootless.Argument()}
- }
- }
-
args := c.InputArgs
runOnly := c.Running
all := c.All
@@ -112,20 +99,6 @@ func restartCmd(c *cliconfig.RestartValues) error {
}
}
- if os.Geteuid() != 0 {
- // In rootless mode we can deal with one container at at time.
- for _, c := range restartContainers {
- _, ret, err := joinContainerOrCreateRootlessUserNS(runtime, c)
- if err != nil {
- return err
- }
- if ret != 0 {
- os.Exit(ret)
- }
- }
- os.Exit(0)
- }
-
maxWorkers := shared.Parallelize("restart")
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalFlags.MaxWorks
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index 4d1e0c768..52e281402 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -2,16 +2,12 @@ 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"
@@ -52,31 +48,6 @@ 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 (
@@ -90,58 +61,6 @@ 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 {
- exitCode = 0
- 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 {
- if errors.Cause(err) == libpod.ErrNoSuchCtr {
- exitCode = 1
- continue
- }
- 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(exitCode)
- }
- }
-
failureCnt := 0
delContainers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all")
if err != nil {
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 32ab088b4..cd82e4f1c 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"io"
- "io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -759,71 +758,6 @@ type namespace interface {
Container() string
}
-func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *libpod.Runtime) (bool, int, error) {
- if os.Geteuid() == 0 {
- return false, 0, nil
- }
-
- if createConfig.Pod != "" {
- pod, err := runtime.LookupPod(createConfig.Pod)
- if err != nil {
- return false, -1, err
- }
- inspect, err := pod.Inspect()
- for _, ctr := range inspect.Containers {
- prevCtr, err := runtime.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.JoinDirectUserAndMountNS(uint(conmonPid))
- }
- }
-
- namespacesStr := []string{string(createConfig.IpcMode), string(createConfig.NetMode), string(createConfig.UsernsMode), string(createConfig.PidMode), string(createConfig.UtsMode)}
- for _, i := range namespacesStr {
- if cc.IsNS(i) {
- return rootless.JoinNSPath(cc.NS(i))
- }
- }
-
- namespaces := []namespace{createConfig.IpcMode, createConfig.NetMode, createConfig.UsernsMode, createConfig.PidMode, createConfig.UtsMode}
- for _, i := range namespaces {
- if i.IsContainer() {
- ctr, err := runtime.LookupContainer(i.Container())
- if err != nil {
- return false, -1, err
- }
- pid, err := ctr.PID()
- if err != nil {
- return false, -1, err
- }
- if pid == 0 {
- if createConfig.Pod != "" {
- continue
- }
- return false, -1, errors.Errorf("dependency container %s is not running", ctr.ID())
- }
- return rootless.JoinNS(uint(pid), 0)
- }
- }
- return rootless.BecomeRootInUserNS()
-}
-
func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateConfig, ctx context.Context, pod *libpod.Pod) (*libpod.Container, error) {
runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig)
if err != nil {
@@ -834,13 +768,6 @@ func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateC
if err != nil {
return nil, err
}
- became, ret, err := joinOrCreateRootlessUserNamespace(createConfig, r)
- if err != nil {
- return nil, err
- }
- if became {
- os.Exit(ret)
- }
ctr, err := r.NewContainer(ctx, runtimeSpec, options...)
if err != nil {
diff --git a/cmd/podman/top.go b/cmd/podman/top.go
index 400d54072..5d394d2d6 100644
--- a/cmd/podman/top.go
+++ b/cmd/podman/top.go
@@ -9,7 +9,6 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -103,18 +102,6 @@ func topCmd(c *cliconfig.TopValues) error {
if conStat != libpod.ContainerStateRunning {
return errors.Errorf("top can only be used on running containers")
}
-
- pid, err := container.PID()
- if err != nil {
- return err
- }
- became, ret, err := rootless.JoinNS(uint(pid), 0)
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
psOutput, err := container.GetContainerPidInformation(descriptors)
if err != nil {
return err
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 6fb325c51..4dd2707e8 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -4,7 +4,6 @@ import (
"fmt"
"io/ioutil"
"os"
- "os/exec"
"path/filepath"
"sync"
"syscall"
@@ -926,16 +925,8 @@ func makeRuntime(runtime *Runtime) (err error) {
// If we need to refresh the state, do it now - things are guaranteed to
// be set up by now.
if doRefresh {
- if os.Geteuid() != 0 {
- aliveLock.Unlock()
- locked = false
- if err2 := runtime.refreshRootless(); err2 != nil {
- return err2
- }
- } else {
- if err2 := runtime.refresh(runtimeAliveFile); err2 != nil {
- return err2
- }
+ if err2 := runtime.refresh(runtimeAliveFile); err2 != nil {
+ return err2
}
}
@@ -1009,21 +1000,6 @@ func (r *Runtime) Shutdown(force bool) error {
return lastError
}
-// Reconfigures the runtime after a reboot for a rootless process
-func (r *Runtime) refreshRootless() error {
- // Take advantage of a command that requires a new userns
- // so that we are running as the root user and able to use refresh()
- cmd := exec.Command(os.Args[0], "info")
-
- if output, err := cmd.CombinedOutput(); err != nil {
- if _, ok := err.(*exec.ExitError); !ok {
- return errors.Wrapf(err, "Error waiting for info while refreshing state: %s", os.Args[0])
- }
- return errors.Wrapf(err, "Error running %s info while refreshing state: %s", os.Args[0], output)
- }
- return nil
-}
-
// Reconfigures the runtime after a reboot
// Refreshes the state, recreating temporary files
// Does not check validity as the runtime is not valid until after this has run
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 506aee477..da2399685 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -2,11 +2,9 @@ package libpod
import (
"context"
- "io/ioutil"
"os"
"path"
"path/filepath"
- "strconv"
"strings"
"time"
@@ -564,37 +562,6 @@ func (r *Runtime) Export(name string, path string) error {
if err != nil {
return err
}
- if os.Geteuid() != 0 {
- state, err := ctr.State()
- if err != nil {
- return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
- }
- if state == ContainerStateRunning || state == ContainerStatePaused {
- data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
- if err != nil {
- return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
- }
- conmonPid, err := strconv.Atoi(string(data))
- if err != nil {
- return errors.Wrapf(err, "cannot parse PID %q", data)
- }
- became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- } else {
- became, ret, err := rootless.BecomeRootInUserNS()
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- }
- }
return ctr.Export(path)
}
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 6a68a3aea..f4d564cf8 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -8,7 +8,6 @@ import (
"io"
"io/ioutil"
"os"
- "strconv"
"text/template"
"github.com/containers/buildah"
@@ -123,38 +122,6 @@ func (r *LocalRuntime) Export(name string, path string) error {
if err != nil {
return errors.Wrapf(err, "error looking up container %q", name)
}
- if os.Geteuid() != 0 {
- state, err := ctr.State()
- if err != nil {
- return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
- }
- if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
- data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
- if err != nil {
- return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
- }
- conmonPid, err := strconv.Atoi(string(data))
- if err != nil {
- return errors.Wrapf(err, "cannot parse PID %q", data)
- }
- became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- } else {
- became, ret, err := rootless.BecomeRootInUserNS()
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- }
- }
-
return ctr.Export(path)
}
@@ -342,46 +309,6 @@ func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.Healt
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)
-}
-
// Events is a wrapper to libpod to obtain libpod/podman events
func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
var (
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index dcc2d5aa6..48d7eb986 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -755,13 +755,6 @@ func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.Healt
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
-}
-
// Events monitors libpod/podman events over a varlink connection
func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
var more uint64
diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go
deleted file mode 100644
index a531e43ce..000000000
--- a/pkg/rootless/rootless.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package rootless
-
-// Opts allows to customize how re-execing to a rootless process is done
-type Opts struct {
- // Argument overrides the arguments on the command line
- // for the re-execed process. The process in the namespace
- // must use rootless.Argument() to read its value.
- Argument string
-}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 2e2c3acac..9cb79ed4d 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -13,10 +13,36 @@
#include <sys/wait.h>
#include <string.h>
#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <dirent.h>
static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces";
static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone";
+static int n_files;
+
+static void __attribute__((constructor)) init()
+{
+ DIR *d;
+
+ /* Store how many FDs were open before the Go runtime kicked in. */
+ d = opendir ("/proc/self/fd");
+ if (d)
+ {
+ struct dirent *ent;
+
+ for (ent = readdir (d); ent; ent = readdir (d))
+ {
+ int fd = atoi (ent->d_name);
+ if (fd > n_files && fd != dirfd (d))
+ n_files = fd;
+ }
+ closedir (d);
+ }
+}
+
+
static int
syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid)
{
@@ -133,12 +159,25 @@ reexec_userns_join (int userns, int mountns)
pid = fork ();
if (pid < 0)
fprintf (stderr, "cannot fork: %s\n", strerror (errno));
+
if (pid)
- return pid;
+ {
+ /* We passed down these fds, close them. */
+ int f;
+ for (f = 3; f < n_files; f++)
+ close (f);
+ return pid;
+ }
setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1);
setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1);
+ if (prctl (PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) < 0)
+ {
+ fprintf (stderr, "cannot prctl(PR_SET_PDEATHSIG): %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
if (setns (userns, 0) < 0)
{
fprintf (stderr, "cannot setns: %s\n", strerror (errno));
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index c753228f1..1d1b1713d 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -46,11 +46,6 @@ func IsRootless() bool {
return isRootless
}
-// Argument returns the argument that was set for the rootless session.
-func Argument() string {
- return os.Getenv("_CONTAINERS_ROOTLESS_ARG")
-}
-
// GetRootlessUID returns the UID of the user in the parent userNS
func GetRootlessUID() int {
uidEnv := os.Getenv("_CONTAINERS_ROOTLESS_UID")
@@ -90,51 +85,86 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
return nil
}
-// JoinNS re-exec podman in a new userNS and join the user namespace of the specified
-// PID.
-func JoinNS(pid uint, preserveFDs int) (bool, int, error) {
- if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
- return false, -1, nil
+func readUserNs(path string) (string, error) {
+ b := make([]byte, 256)
+ _, err := syscall.Readlink(path, b)
+ if err != nil {
+ return "", err
+ }
+ return string(b), nil
+}
+
+func readUserNsFd(fd uintptr) (string, error) {
+ return readUserNs(fmt.Sprintf("/proc/self/fd/%d", fd))
+}
+
+func getParentUserNs(fd uintptr) (uintptr, error) {
+ const nsGetParent = 0xb702
+ ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetParent), 0)
+ if errno != 0 {
+ return 0, errno
}
+ return (uintptr)(unsafe.Pointer(ret)), nil
+}
- userNS, err := getUserNSForPid(pid)
+// getUserNSFirstChild returns an open FD for the first direct child user namespace that created the process
+// Each container creates a new user namespace where the runtime runs. The current process in the container
+// might have created new user namespaces that are child of the initial namespace we created.
+// This function finds the initial namespace created for the container that is a child of the current namespace.
+//
+// current ns
+// / \
+// TARGET -> a [other containers]
+// /
+// b
+// /
+// NS READ USING THE PID -> c
+func getUserNSFirstChild(fd uintptr) (*os.File, error) {
+ currentNS, err := readUserNs("/proc/self/ns/user")
if err != nil {
- return false, -1, err
+ return nil, err
}
- defer userNS.Close()
- pidC := C.reexec_userns_join(C.int(userNS.Fd()), -1)
- if int(pidC) < 0 {
- return false, -1, errors.Errorf("cannot re-exec process")
+ ns, err := readUserNsFd(fd)
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot read user namespace")
}
- if preserveFDs > 0 {
- for fd := 3; fd < 3+preserveFDs; fd++ {
- // These fds were passed down to the runtime. Close them
- // and not interfere
- os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close()
- }
+ if ns == currentNS {
+ return nil, errors.New("process running in the same user namespace")
}
- ret := C.reexec_in_user_namespace_wait(pidC)
- if ret < 0 {
- return false, -1, errors.New("error waiting for the re-exec process")
- }
+ for {
+ nextFd, err := getParentUserNs(fd)
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot get parent user namespace")
+ }
- return true, int(ret), nil
-}
+ ns, err = readUserNsFd(nextFd)
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot read user namespace")
+ }
-// JoinDirectUserAndMountNS re-exec podman in a new userNS and join the user and mount
-// namespace of the specified PID without looking up its parent. Useful to join directly
-// the conmon process. It is a convenience function for JoinDirectUserAndMountNSWithOpts
-// with a default configuration.
-func JoinDirectUserAndMountNS(pid uint) (bool, int, error) {
- return JoinDirectUserAndMountNSWithOpts(pid, nil)
+ if ns == currentNS {
+ syscall.Close(int(nextFd))
+
+ // Drop O_CLOEXEC for the fd.
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_SETFD, 0)
+ if errno != 0 {
+ syscall.Close(int(fd))
+ return nil, errno
+ }
+
+ return os.NewFile(fd, "userns child"), nil
+ }
+ syscall.Close(int(fd))
+ fd = nextFd
+ }
}
-// JoinDirectUserAndMountNSWithOpts re-exec podman in a new userNS and join the user and
-// mount namespace of the specified PID without looking up its parent. Useful to join
-// directly the conmon process.
-func JoinDirectUserAndMountNSWithOpts(pid uint, opts *Opts) (bool, int, error) {
+// JoinUserAndMountNS re-exec podman in a new userNS and join the user and mount
+// namespace of the specified PID without looking up its parent. Useful to join directly
+// the conmon process.
+func JoinUserAndMountNS(pid uint) (bool, int, error) {
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
return false, -1, nil
}
@@ -151,39 +181,11 @@ func JoinDirectUserAndMountNSWithOpts(pid uint, opts *Opts) (bool, int, error) {
}
defer userNS.Close()
- if opts != nil && opts.Argument != "" {
- if err := os.Setenv("_CONTAINERS_ROOTLESS_ARG", opts.Argument); err != nil {
- return false, -1, err
- }
- }
-
- pidC := C.reexec_userns_join(C.int(userNS.Fd()), C.int(mountNS.Fd()))
- if int(pidC) < 0 {
- return false, -1, errors.Errorf("cannot re-exec process")
- }
-
- ret := C.reexec_in_user_namespace_wait(pidC)
- if ret < 0 {
- return false, -1, errors.New("error waiting for the re-exec process")
- }
-
- return true, int(ret), nil
-}
-
-// JoinNSPath re-exec podman in a new userNS and join the owner user namespace of the
-// specified path.
-func JoinNSPath(path string) (bool, int, error) {
- if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
- return false, -1, nil
- }
-
- userNS, err := getUserNSForPath(path)
+ fd, err := getUserNSFirstChild(userNS.Fd())
if err != nil {
return false, -1, err
}
- defer userNS.Close()
-
- pidC := C.reexec_userns_join(C.int(userNS.Fd()), -1)
+ pidC := C.reexec_userns_join(C.int(fd.Fd()), C.int(mountNS.Fd()))
if int(pidC) < 0 {
return false, -1, errors.Errorf("cannot re-exec process")
}
@@ -199,16 +201,8 @@ func JoinNSPath(path string) (bool, int, error) {
// BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed
// into a new user namespace and the return code from the re-executed podman process.
// If podman was re-executed the caller needs to propagate the error code returned by the child
-// process. It is a convenience function for BecomeRootInUserNSWithOpts with a default configuration.
-func BecomeRootInUserNS() (bool, int, error) {
- return BecomeRootInUserNSWithOpts(nil)
-}
-
-// BecomeRootInUserNSWithOpts re-exec podman in a new userNS. It returns whether podman was
-// re-execute into a new user namespace and the return code from the re-executed podman process.
-// If podman was re-executed the caller needs to propagate the error code returned by the child
// process.
-func BecomeRootInUserNSWithOpts(opts *Opts) (bool, int, error) {
+func BecomeRootInUserNS() (bool, int, error) {
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
if os.Getenv("_CONTAINERS_USERNS_CONFIGURED") == "init" {
return false, 0, runInUser()
@@ -227,12 +221,6 @@ func BecomeRootInUserNSWithOpts(opts *Opts) (bool, int, error) {
defer w.Close()
defer w.Write([]byte("0"))
- if opts != nil && opts.Argument != "" {
- if err := os.Setenv("_CONTAINERS_ROOTLESS_ARG", opts.Argument); err != nil {
- return false, -1, err
- }
- }
-
pidC := C.reexec_in_user_namespace(C.int(r.Fd()))
pid := int(pidC)
if pid < 0 {
@@ -314,112 +302,3 @@ func BecomeRootInUserNSWithOpts(opts *Opts) (bool, int, error) {
return true, int(ret), nil
}
-
-func readUserNs(path string) (string, error) {
- b := make([]byte, 256)
- _, err := syscall.Readlink(path, b)
- if err != nil {
- return "", err
- }
- return string(b), nil
-}
-
-func readUserNsFd(fd uintptr) (string, error) {
- return readUserNs(fmt.Sprintf("/proc/self/fd/%d", fd))
-}
-
-func getOwner(fd uintptr) (uintptr, error) {
- const nsGetUserns = 0xb701
- ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetUserns), 0)
- if errno != 0 {
- return 0, errno
- }
- return (uintptr)(unsafe.Pointer(ret)), nil
-}
-
-func getParentUserNs(fd uintptr) (uintptr, error) {
- const nsGetParent = 0xb702
- ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetParent), 0)
- if errno != 0 {
- return 0, errno
- }
- return (uintptr)(unsafe.Pointer(ret)), nil
-}
-
-func getUserNSForPath(path string) (*os.File, error) {
- u, err := os.Open(path)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot open %s", path)
- }
- defer u.Close()
- fd, err := getOwner(u.Fd())
- if err != nil {
- return nil, err
- }
-
- return getUserNSFirstChild(fd)
-}
-
-func getUserNSForPid(pid uint) (*os.File, error) {
- path := fmt.Sprintf("/proc/%d/ns/user", pid)
- u, err := os.Open(path)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot open %s", path)
- }
-
- return getUserNSFirstChild(u.Fd())
-}
-
-// getUserNSFirstChild returns an open FD for the first direct child user namespace that created the process
-// Each container creates a new user namespace where the runtime runs. The current process in the container
-// might have created new user namespaces that are child of the initial namespace we created.
-// This function finds the initial namespace created for the container that is a child of the current namespace.
-//
-// current ns
-// / \
-// TARGET -> a [other containers]
-// /
-// b
-// /
-// NS READ USING THE PID -> c
-func getUserNSFirstChild(fd uintptr) (*os.File, error) {
- currentNS, err := readUserNs("/proc/self/ns/user")
- if err != nil {
- return nil, err
- }
-
- ns, err := readUserNsFd(fd)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot read user namespace")
- }
- if ns == currentNS {
- return nil, errors.New("process running in the same user namespace")
- }
-
- for {
- nextFd, err := getParentUserNs(fd)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot get parent user namespace")
- }
-
- ns, err = readUserNsFd(nextFd)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot read user namespace")
- }
-
- if ns == currentNS {
- syscall.Close(int(nextFd))
-
- // Drop O_CLOEXEC for the fd.
- _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_SETFD, 0)
- if errno != 0 {
- syscall.Close(int(fd))
- return nil, errno
- }
-
- return os.NewFile(fd, "userns child"), nil
- }
- syscall.Close(int(fd))
- fd = nextFd
- }
-}
diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go
index 24009610a..47b5dd7cc 100644
--- a/pkg/rootless/rootless_unsupported.go
+++ b/pkg/rootless/rootless_unsupported.go
@@ -19,45 +19,15 @@ func BecomeRootInUserNS() (bool, int, error) {
return false, -1, errors.New("this function is not supported on this os")
}
-// BecomeRootInUserNS is a stub function that always returns false and an
-// error on unsupported OS's
-func BecomeRootInUserNSWithOpts(opts *Opts) (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os")
-}
-
// GetRootlessUID returns the UID of the user in the parent userNS
func GetRootlessUID() int {
return -1
}
-// JoinNS re-exec podman in a new userNS and join the user namespace of the specified
-// PID.
-func JoinNS(pid uint, preserveFDs int) (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os")
-}
-
-// JoinNSPath re-exec podman in a new userNS and join the owner user namespace of the
-// specified path.
-func JoinNSPath(path string) (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os")
-}
-
-// JoinDirectUserAndMountNSWithOpts re-exec podman in a new userNS and join the user and
-// mount namespace of the specified PID without looking up its parent. Useful to join
-// directly the conmon process.
-func JoinDirectUserAndMountNSWithOpts(pid uint, opts *Opts) (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os")
-}
-
-// JoinDirectUserAndMountNS re-exec podman in a new userNS and join the user and mount
+// JoinUserAndMountNS re-exec podman in a new userNS and join the user and mount
// namespace of the specified PID without looking up its parent. Useful to join directly
-// the conmon process. It is a convenience function for JoinDirectUserAndMountNSWithOpts
+// the conmon process. It is a convenience function for JoinUserAndMountNSWithOpts
// with a default configuration.
-func JoinDirectUserAndMountNS(pid uint) (bool, int, error) {
+func JoinUserAndMountNS(pid uint) (bool, int, error) {
return false, -1, errors.New("this function is not supported on this os")
}
-
-// Argument returns the argument that was set for the rootless session.
-func Argument() string {
- return ""
-}