rootless: fix exec
We cannot re-exec into a new user namespace to gain privileges and access an existing as the new namespace is not the owner of the existing container. "unshare" is used to join the user namespace of the target container. The current implementation assumes that the main process of the container didn't create a new user namespace. Since in the setup phase we are not running with euid=0, we must skip the setup for containers/storage. Closes: https://github.com/containers/libpod/issues/1329 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> Closes: #1331 Approved by: rhatdan
This commit is contained in:
parent
1ac4dbb508
commit
720eb85ba5
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
|
@ -66,6 +67,7 @@ func execCmd(c *cli.Context) error {
|
|||
if c.Bool("latest") {
|
||||
argStart = 0
|
||||
}
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
cmd := args[argStart:]
|
||||
runtime, err := libpodruntime.GetRuntime(c)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ var (
|
|||
exitCode = 125
|
||||
)
|
||||
|
||||
var cmdsNotRequiringRootless = map[string]bool{"help": true, "version": true}
|
||||
var cmdsNotRequiringRootless = map[string]bool{"help": true, "version": true, "exec": true}
|
||||
|
||||
func main() {
|
||||
debug := false
|
||||
|
|
|
|||
|
|
@ -681,6 +681,12 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
|
|||
logrus.Debugf("Starting runtime %s with following arguments: %v", r.path, args)
|
||||
|
||||
execCmd := exec.Command(r.path, args...)
|
||||
if rootless.IsRootless() {
|
||||
args = append([]string{"--preserve-credentials", "-U", "-t", fmt.Sprintf("%d", c.state.PID), r.path}, args...)
|
||||
// using nsenter might not be correct if the target PID joined a different user namespace.
|
||||
// A better way would be to retrieve the parent ns (NS_GET_PARENT) until it is a child of the current namespace.
|
||||
execCmd = exec.Command("nsenter", args...)
|
||||
}
|
||||
execCmd.Stdout = os.Stdout
|
||||
execCmd.Stderr = os.Stderr
|
||||
execCmd.Stdin = os.Stdin
|
||||
|
|
|
|||
|
|
@ -405,9 +405,14 @@ func makeRuntime(runtime *Runtime) (err error) {
|
|||
}
|
||||
|
||||
// Set up containers/storage
|
||||
store, err := storage.GetStore(runtime.config.StorageConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
var store storage.Store
|
||||
if rootless.SkipStorageSetup() {
|
||||
logrus.Debug("Not configuring container store")
|
||||
} else {
|
||||
store, err = storage.GetStore(runtime.config.StorageConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
runtime.store = store
|
||||
|
|
@ -424,7 +429,7 @@ func makeRuntime(runtime *Runtime) (err error) {
|
|||
// Setting signaturepolicypath
|
||||
ir.SignaturePolicyPath = runtime.config.SignaturePolicyPath
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err != nil && store != nil {
|
||||
// Don't forcibly shut down
|
||||
// We could be opening a store in use by another libpod
|
||||
_, err2 := store.Shutdown(false)
|
||||
|
|
@ -611,8 +616,10 @@ func (r *Runtime) Shutdown(force bool) error {
|
|||
}
|
||||
|
||||
var lastError error
|
||||
if _, err := r.store.Shutdown(force); err != nil {
|
||||
lastError = errors.Wrapf(err, "Error shutting down container storage")
|
||||
if r.store != nil {
|
||||
if _, err := r.store.Shutdown(force); err != nil {
|
||||
lastError = errors.Wrapf(err, "Error shutting down container storage")
|
||||
}
|
||||
}
|
||||
if err := r.state.Close(); err != nil {
|
||||
if lastError != nil {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,20 @@ func IsRootless() bool {
|
|||
return os.Getuid() != 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != ""
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// GetRootlessUID returns the UID of the user in the parent userNS
|
||||
func GetRootlessUID() int {
|
||||
uidEnv := os.Getenv("_LIBPOD_ROOTLESS_UID")
|
||||
|
|
|
|||
|
|
@ -21,3 +21,12 @@ func BecomeRootInUserNS() (bool, int, error) {
|
|||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,19 @@ var _ = Describe("Podman rootless", func() {
|
|||
cmd.WaitWithDefaultTimeout()
|
||||
Expect(cmd.LineInOutputContains("hello")).To(BeTrue())
|
||||
Expect(cmd.ExitCode()).To(Equal(0))
|
||||
|
||||
allArgsD := append([]string{"run", "-d"}, args...)
|
||||
allArgsD = append(allArgsD, "--rootfs", mountPath, "sleep", "1d")
|
||||
cmd = podmanTest.PodmanAsUser(allArgsD, 1000, 1000, env)
|
||||
cmd.WaitWithDefaultTimeout()
|
||||
Expect(cmd.ExitCode()).To(Equal(0))
|
||||
cid := cmd.OutputToStringArray()[0]
|
||||
|
||||
allArgsE := []string{"exec", cid, "echo", "hello"}
|
||||
cmd = podmanTest.PodmanAsUser(allArgsE, 1000, 1000, env)
|
||||
cmd.WaitWithDefaultTimeout()
|
||||
Expect(cmd.ExitCode()).To(Equal(0))
|
||||
Expect(cmd.LineInOutputContains("hello")).To(BeTrue())
|
||||
}
|
||||
|
||||
runRootless(mountPath)
|
||||
|
|
|
|||
Loading…
Reference in New Issue