diff options
-rw-r--r-- | cmd/podman/utils.go | 29 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 10 | ||||
-rw-r--r-- | libpod/oci_linux.go | 17 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 5 | ||||
-rw-r--r-- | test/e2e/run_userns_test.go | 15 |
5 files changed, 45 insertions, 31 deletions
diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go index 4ec0f8a13..45d081512 100644 --- a/cmd/podman/utils.go +++ b/cmd/podman/utils.go @@ -200,35 +200,6 @@ func getPodsFromContext(c *cliconfig.PodmanCommand, r *libpod.Runtime) ([]*libpo return pods, lastError } -func getVolumesFromContext(c *cliconfig.PodmanCommand, r *libpod.Runtime) ([]*libpod.Volume, error) { - args := c.InputArgs - var ( - vols []*libpod.Volume - lastError error - err error - ) - - if c.Bool("all") { - vols, err = r.Volumes() - if err != nil { - return nil, errors.Wrapf(err, "unable to get all volumes") - } - } - - for _, i := range args { - vol, err := r.GetVolume(i) - if err != nil { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to find volume %s", i) - continue - } - vols = append(vols, vol) - } - return vols, lastError -} - //printParallelOutput takes the map of parallel worker results and outputs them // to stdout func printParallelOutput(m map[string]error, errCount int) error { diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 2a7808bdf..c6c9ceb0c 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -203,7 +203,8 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } // Check if the spec file mounts contain the label Relabel flags z or Z. // If they do, relabel the source directory and then remove the option. - for _, m := range g.Mounts() { + for i := range g.Config.Mounts { + m := &g.Config.Mounts[i] var options []string for _, o := range m.Options { switch o { @@ -219,6 +220,13 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } } m.Options = options + + // If we are using a user namespace, we will use an intermediate + // directory to bind mount volumes + if c.state.UserNSRoot != "" && strings.HasPrefix(m.Source, c.runtime.config.VolumePath) { + newSourceDir := filepath.Join(c.state.UserNSRoot, "volumes") + m.Source = strings.Replace(m.Source, c.runtime.config.VolumePath, newSourceDir, 1) + } } g.SetProcessSelinuxLabel(c.ProcessLabel()) diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index 2737a641e..f85c5ee62 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -106,6 +106,23 @@ func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restor if err != nil { return } + + if ctr.state.UserNSRoot != "" { + _, err := os.Stat(ctr.runtime.config.VolumePath) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + volumesTarget := filepath.Join(ctr.state.UserNSRoot, "volumes") + if err := idtools.MkdirAs(volumesTarget, 0700, ctr.RootUID(), ctr.RootGID()); err != nil { + return + } + if err = unix.Mount(ctr.runtime.config.VolumePath, volumesTarget, "none", unix.MS_BIND, ""); err != nil { + return + } + } + } + err = r.createOCIContainer(ctr, cgroupParent, restoreOptions) }() wg.Wait() diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 3b74a65dd..f23dc86dd 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -186,8 +186,11 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. return nil, errors.Wrapf(err, "error creating named volume %q", vol.Source) } ctr.config.Spec.Mounts[i].Source = newVol.MountPoint() + if err := os.Chown(ctr.config.Spec.Mounts[i].Source, ctr.RootUID(), ctr.RootGID()); err != nil { + return nil, errors.Wrapf(err, "cannot chown %q to %d:%d", ctr.config.Spec.Mounts[i].Source, ctr.RootUID(), ctr.RootGID()) + } if err := ctr.copyWithTarFromImage(ctr.config.Spec.Mounts[i].Destination, ctr.config.Spec.Mounts[i].Source); err != nil && !os.IsNotExist(err) { - return nil, errors.Wrapf(err, "Failed to copy content into new volume mount %q", vol.Source) + return nil, errors.Wrapf(err, "failed to copy content into new volume mount %q", vol.Source) } continue } diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index c6c94d2f6..5c38a8950 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -69,6 +69,21 @@ var _ = Describe("Podman UserNS support", func() { Expect(ok).To(BeTrue()) }) + It("podman uidmapping and gidmapping with a volume", func() { + if os.Getenv("SKIP_USERNS") != "" { + Skip("Skip userns tests.") + } + if _, err := os.Stat("/proc/self/uid_map"); err != nil { + Skip("User namespaces not supported.") + } + + session := podmanTest.Podman([]string{"run", "--uidmap=0:1:70000", "--gidmap=0:20000:70000", "-v", "my-foo-volume:/foo:Z", "busybox", "echo", "hello"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + ok, _ := session.GrepString("hello") + Expect(ok).To(BeTrue()) + }) + It("podman uidmapping and gidmapping --net=host", func() { if os.Getenv("SKIP_USERNS") != "" { Skip("Skip userns tests.") |