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:
Giuseppe Scrivano 2018-08-23 23:02:04 +02:00 committed by Atomic Bot
parent 1ac4dbb508
commit 720eb85ba5
7 changed files with 58 additions and 7 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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")

View File

@ -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
}

View File

@ -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)