mirror of
https://github.com/containers/podman.git
synced 2025-12-11 17:27:19 +08:00
Merge pull request #2706 from giuseppe/rootless-single-usernamespace
rootless: single user namespace
This commit is contained in:
@@ -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"
|
||||
@@ -58,9 +55,6 @@ func cpCmd(c *cliconfig.CpValues) error {
|
||||
if len(args) != 2 {
|
||||
return errors.Errorf("you must provide a source path and a destination path")
|
||||
}
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
@@ -90,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
|
||||
|
||||
@@ -2,12 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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/pkg/rootless"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -54,10 +52,6 @@ func createCmd(c *cliconfig.CreateValues) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating libpod runtime")
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -67,7 +66,6 @@ func execCmd(c *cliconfig.ExecValues) error {
|
||||
if c.Latest {
|
||||
argStart = 0
|
||||
}
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
cmd := args[argStart:]
|
||||
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
@@ -107,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{}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||
"github.com/containers/libpod/cmd/podman/shared/parse"
|
||||
"github.com/containers/libpod/pkg/adapter"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -41,10 +40,6 @@ func init() {
|
||||
|
||||
// exportCmd saves a container to a tarball on disk
|
||||
func exportCmd(c *cliconfig.ExportValues) 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")
|
||||
|
||||
@@ -4,12 +4,10 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/containers/libpod/pkg/adapter"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/adapter"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -63,7 +61,6 @@ func killCmd(c *cliconfig.KillValues) error {
|
||||
return err
|
||||
}
|
||||
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
|
||||
@@ -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"
|
||||
@@ -60,36 +63,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",
|
||||
@@ -153,18 +126,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 {
|
||||
|
||||
@@ -60,10 +60,6 @@ type jsonMountPoint struct {
|
||||
}
|
||||
|
||||
func mountCmd(c *cliconfig.MountValues) error {
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||
"github.com/containers/libpod/pkg/adapter"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -49,7 +48,6 @@ func init() {
|
||||
|
||||
// podKillCmd kills one or more pods with a signal
|
||||
func podKillCmd(c *cliconfig.PodKillValues) error {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
|
||||
@@ -2,11 +2,9 @@ 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"
|
||||
@@ -48,24 +46,12 @@ func init() {
|
||||
|
||||
func podRestartCmd(c *cliconfig.PodRestartValues) error {
|
||||
var lastError 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
|
||||
}
|
||||
}
|
||||
|
||||
restartIDs, conErrors, restartErrors := runtime.RestartPods(getContext(), c)
|
||||
|
||||
for _, p := range restartIDs {
|
||||
|
||||
@@ -2,11 +2,9 @@ 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"
|
||||
@@ -48,23 +46,12 @@ 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)
|
||||
|
||||
@@ -2,11 +2,9 @@ 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"
|
||||
@@ -48,24 +46,12 @@ 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)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -54,10 +53,6 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
|
||||
)
|
||||
args := c.InputArgs
|
||||
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
|
||||
if c.ListDescriptors {
|
||||
descriptors, err := libpod.GetContainerPidInformationDescriptors()
|
||||
if err != nil {
|
||||
@@ -83,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 {
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"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/containers/libpod/pkg/util"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
"github.com/docker/go-units"
|
||||
@@ -202,9 +201,6 @@ func init() {
|
||||
}
|
||||
|
||||
func psCmd(c *cliconfig.PsValues) error {
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
if c.Bool("trace") {
|
||||
span, _ := opentracing.StartSpanFromContext(Ctx, "psCmd")
|
||||
defer span.Finish()
|
||||
|
||||
@@ -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,19 +54,6 @@ func restartCmd(c *cliconfig.RestartValues) error {
|
||||
restartContainers []*libpod.Container
|
||||
)
|
||||
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
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
|
||||
@@ -115,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
|
||||
|
||||
@@ -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,39 +48,11 @@ 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)
|
||||
@@ -93,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 {
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"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"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -57,9 +56,6 @@ func runCmd(c *cliconfig.RunValues) error {
|
||||
if err := createInit(&c.PodmanCommand); err != nil {
|
||||
return err
|
||||
}
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -75,7 +74,8 @@ func CreateContainer(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l
|
||||
imageName := ""
|
||||
var data *inspect.ImageData = nil
|
||||
|
||||
if rootfs == "" && !rootless.SkipStorageSetup() {
|
||||
// Set the storage if we are running as euid == 0 and there is no rootfs specified
|
||||
if rootfs == "" && os.Geteuid() == 0 {
|
||||
var writer io.Writer
|
||||
if !c.Bool("quiet") {
|
||||
writer = os.Stderr
|
||||
@@ -758,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 {
|
||||
@@ -833,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 {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/adapter"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -59,7 +58,6 @@ func stopCmd(c *cliconfig.StopValues) error {
|
||||
defer span.Finish()
|
||||
}
|
||||
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -77,7 +76,6 @@ func topCmd(c *cliconfig.TopValues) error {
|
||||
return errors.Errorf("you must provide the name or id of a running container")
|
||||
}
|
||||
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating libpod runtime")
|
||||
@@ -104,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
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -742,7 +741,7 @@ func makeRuntime(runtime *Runtime) (err error) {
|
||||
|
||||
// Set up containers/storage
|
||||
var store storage.Store
|
||||
if rootless.SkipStorageSetup() {
|
||||
if os.Geteuid() != 0 {
|
||||
logrus.Debug("Not configuring container store")
|
||||
} else {
|
||||
store, err = storage.GetStore(runtime.config.StorageConfig)
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/buildah"
|
||||
@@ -124,38 +123,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)
|
||||
}
|
||||
|
||||
@@ -343,46 +310,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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -46,25 +46,6 @@ func IsRootless() bool {
|
||||
return isRootless
|
||||
}
|
||||
|
||||
var (
|
||||
skipStorageSetup = false
|
||||
)
|
||||
|
||||
// SetSkipStorageSetup tells the runtime to not setup containers/storage
|
||||
func SetSkipStorageSetup(v bool) {
|
||||
skipStorageSetup = v
|
||||
}
|
||||
|
||||
// SkipStorageSetup tells if we should skip the containers/storage setup
|
||||
func SkipStorageSetup() bool {
|
||||
return skipStorageSetup
|
||||
}
|
||||
|
||||
// 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")
|
||||
@@ -104,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
|
||||
}
|
||||
|
||||
userNS, err := getUserNSForPid(pid)
|
||||
func readUserNs(path string) (string, error) {
|
||||
b := make([]byte, 256)
|
||||
_, err := syscall.Readlink(path, b)
|
||||
if err != nil {
|
||||
return false, -1, err
|
||||
return "", err
|
||||
}
|
||||
defer userNS.Close()
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
pidC := C.reexec_userns_join(C.int(userNS.Fd()), -1)
|
||||
if int(pidC) < 0 {
|
||||
return false, -1, errors.Errorf("cannot re-exec process")
|
||||
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
|
||||
}
|
||||
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()
|
||||
return (uintptr)(unsafe.Pointer(ret)), nil
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
ret := C.reexec_in_user_namespace_wait(pidC)
|
||||
if ret < 0 {
|
||||
return false, -1, errors.New("error waiting for the re-exec process")
|
||||
}
|
||||
ns, err = readUserNsFd(nextFd)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot read user namespace")
|
||||
}
|
||||
|
||||
return true, int(ret), 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
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// with a default configuration.
|
||||
func JoinDirectUserAndMountNS(pid uint) (bool, int, error) {
|
||||
return JoinDirectUserAndMountNSWithOpts(pid, nil)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// the conmon process.
|
||||
func JoinUserAndMountNS(pid uint) (bool, int, error) {
|
||||
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
|
||||
return false, -1, nil
|
||||
}
|
||||
@@ -165,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")
|
||||
}
|
||||
@@ -213,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()
|
||||
@@ -241,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 {
|
||||
@@ -328,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,54 +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
|
||||
}
|
||||
|
||||
// SetSkipStorageSetup tells the runtime to not setup containers/storage
|
||||
func SetSkipStorageSetup(bool) {
|
||||
}
|
||||
|
||||
// SkipStorageSetup tells if we should skip the containers/storage setup
|
||||
func SkipStorageSetup() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 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 ""
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/namespaces"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
@@ -271,7 +270,7 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
|
||||
func (c *CreateConfig) GetVolumesFrom() error {
|
||||
var options string
|
||||
|
||||
if rootless.SkipStorageSetup() {
|
||||
if os.Geteuid() != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user