From 93b3c9b76c16104cbb5cc55b6f2339cb43c356b5 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 9 Apr 2019 11:30:35 -0700 Subject: runsc: set UID and GID if gofer is executed in a new user namespace Otherwise, we will not have capabilities in the user namespace. And this patch adds the noexec option for mounts. https://github.com/google/gvisor/issues/145 PiperOrigin-RevId: 242706519 Change-Id: I1b78b77d6969bd18038c71616e8eb7111b71207c --- runsc/container/container.go | 7 +++- runsc/container/container_test.go | 76 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/runsc/container/container.go b/runsc/container/container.go index 687b89935..cc0c1ee25 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -866,8 +866,13 @@ func (c *Container) createGoferProcess(spec *specs.Spec, conf *boot.Config, bund // Setup any uid/gid mappings, and create or join the configured user // namespace so the gofer's view of the filesystem aligns with the // users in the sandbox. - nss = append(nss, specutils.FilterNS([]specs.LinuxNamespaceType{specs.UserNamespace}, spec)...) + userNS := specutils.FilterNS([]specs.LinuxNamespaceType{specs.UserNamespace}, spec) + nss = append(nss, userNS...) specutils.SetUIDGIDMappings(cmd, spec) + if len(userNS) != 0 { + // We need to set UID and GID to have capabilities in a new user namespace. + cmd.SysProcAttr.Credential = &syscall.Credential{Uid: 0, Gid: 0} + } // Start the gofer in the given namespace. log.Debugf("Starting gofer: %s %v", binPath, args) diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go index f17155175..9fe584aa3 100644 --- a/runsc/container/container_test.go +++ b/runsc/container/container_test.go @@ -1250,6 +1250,82 @@ func TestReadonlyRoot(t *testing.T) { } } +func TestUIDMap(t *testing.T) { + for _, conf := range configs(noOverlay...) { + t.Logf("Running test with conf: %+v", conf) + testDir, err := ioutil.TempDir(testutil.TmpDir(), "test-mount") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(testDir) + testFile := path.Join(testDir, "testfile") + + spec := testutil.NewSpecWithArgs("touch", "/tmp/testfile") + uid := os.Getuid() + gid := os.Getgid() + spec.Linux = &specs.Linux{ + Namespaces: []specs.LinuxNamespace{ + {Type: specs.UserNamespace}, + {Type: specs.PIDNamespace}, + {Type: specs.MountNamespace}, + }, + UIDMappings: []specs.LinuxIDMapping{ + { + ContainerID: 0, + HostID: uint32(uid), + Size: 1, + }, + }, + GIDMappings: []specs.LinuxIDMapping{ + { + ContainerID: 0, + HostID: uint32(gid), + Size: 1, + }, + }, + } + + spec.Mounts = append(spec.Mounts, specs.Mount{ + Destination: "/tmp", + Source: testDir, + Type: "bind", + }) + + rootDir, bundleDir, err := testutil.SetupContainer(spec, conf) + if err != nil { + t.Fatalf("error setting up container: %v", err) + } + defer os.RemoveAll(rootDir) + defer os.RemoveAll(bundleDir) + + // Create, start and wait for the container. + c, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "", "") + if err != nil { + t.Fatalf("error creating container: %v", err) + } + defer c.Destroy() + if err := c.Start(conf); err != nil { + t.Fatalf("error starting container: %v", err) + } + + ws, err := c.Wait() + if err != nil { + t.Fatalf("error waiting on container: %v", err) + } + if !ws.Exited() || ws.ExitStatus() != 0 { + t.Fatalf("container failed, waitStatus: %v", ws) + } + st := syscall.Stat_t{} + if err := syscall.Stat(testFile, &st); err != nil { + t.Fatalf("error stat /testfile: %v", err) + } + + if st.Uid != uint32(uid) || st.Gid != uint32(gid) { + t.Fatalf("UID: %d (%d) GID: %d (%d)", st.Uid, uid, st.Gid, gid) + } + } +} + func TestReadonlyMount(t *testing.T) { for _, conf := range configs(overlay) { t.Logf("Running test with conf: %+v", conf) -- cgit v1.2.3