summaryrefslogtreecommitdiffhomepage
path: root/runsc/container
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/container')
-rw-r--r--runsc/container/BUILD1
-rw-r--r--runsc/container/container_test.go137
-rw-r--r--runsc/container/shared_volume_test.go267
3 files changed, 268 insertions, 137 deletions
diff --git a/runsc/container/BUILD b/runsc/container/BUILD
index 5dfff5c5e..354ce2661 100644
--- a/runsc/container/BUILD
+++ b/runsc/container/BUILD
@@ -36,6 +36,7 @@ go_test(
"container_test.go",
"fs_test.go",
"multi_container_test.go",
+ "shared_volume_test.go",
],
data = [
":test_app",
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index 9f3d6b454..06a25de6d 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -1353,143 +1353,6 @@ func TestAbbreviatedIDs(t *testing.T) {
}
}
-// Check that modifications to a volume mount are propigated into and out of
-// the sandbox.
-func TestContainerVolumeContentsShared(t *testing.T) {
- // Only run this test with shared file access, since that is the only
- // behavior it is testing.
- conf := testutil.TestConfig()
- conf.FileAccess = boot.FileAccessShared
- t.Logf("Running test with conf: %+v", conf)
-
- // Main process just sleeps. We will use "exec" to probe the state of
- // the filesystem.
- spec := testutil.NewSpecWithArgs("sleep", "1000")
-
- dir, err := ioutil.TempDir(testutil.TmpDir(), "root-fs-test")
- if err != nil {
- t.Fatalf("TempDir failed: %v", err)
- }
-
- 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 and start 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)
- }
-
- // File that will be used to check consistency inside/outside sandbox.
- filename := filepath.Join(dir, "file")
-
- // File does not exist yet. Reading from the sandbox should fail.
- argsTestFile := &control.ExecArgs{
- Filename: "/usr/bin/test",
- Argv: []string{"test", "-f", filename},
- }
- if ws, err := c.executeSync(argsTestFile); err != nil {
- t.Fatalf("unexpected error testing file %q: %v", filename, err)
- } else if ws.ExitStatus() == 0 {
- t.Errorf("test %q exited with code %v, wanted not zero", ws.ExitStatus(), err)
- }
-
- // Create the file from outside of the sandbox.
- if err := ioutil.WriteFile(filename, []byte("foobar"), 0777); err != nil {
- t.Fatalf("error writing to file %q: %v", filename, err)
- }
-
- // Now we should be able to test the file from within the sandbox.
- if ws, err := c.executeSync(argsTestFile); err != nil {
- t.Fatalf("unexpected error testing file %q: %v", filename, err)
- } else if ws.ExitStatus() != 0 {
- t.Errorf("test %q exited with code %v, wanted zero", filename, ws.ExitStatus())
- }
-
- // Rename the file from outside of the sandbox.
- newFilename := filepath.Join(dir, "newfile")
- if err := os.Rename(filename, newFilename); err != nil {
- t.Fatalf("os.Rename(%q, %q) failed: %v", filename, newFilename, err)
- }
-
- // File should no longer exist at the old path within the sandbox.
- if ws, err := c.executeSync(argsTestFile); err != nil {
- t.Fatalf("unexpected error testing file %q: %v", filename, err)
- } else if ws.ExitStatus() == 0 {
- t.Errorf("test %q exited with code %v, wanted not zero", filename, ws.ExitStatus())
- }
-
- // We should be able to test the new filename from within the sandbox.
- argsTestNewFile := &control.ExecArgs{
- Filename: "/usr/bin/test",
- Argv: []string{"test", "-f", newFilename},
- }
- if ws, err := c.executeSync(argsTestNewFile); err != nil {
- t.Fatalf("unexpected error testing file %q: %v", newFilename, err)
- } else if ws.ExitStatus() != 0 {
- t.Errorf("test %q exited with code %v, wanted zero", newFilename, ws.ExitStatus())
- }
-
- // Delete the renamed file from outside of the sandbox.
- if err := os.Remove(newFilename); err != nil {
- t.Fatalf("error removing file %q: %v", filename, err)
- }
-
- // Renamed file should no longer exist at the old path within the sandbox.
- if ws, err := c.executeSync(argsTestNewFile); err != nil {
- t.Fatalf("unexpected error testing file %q: %v", newFilename, err)
- } else if ws.ExitStatus() == 0 {
- t.Errorf("test %q exited with code %v, wanted not zero", newFilename, ws.ExitStatus())
- }
-
- // Now create the file from WITHIN the sandbox.
- argsTouch := &control.ExecArgs{
- Filename: "/usr/bin/touch",
- Argv: []string{"touch", filename},
- KUID: auth.KUID(os.Getuid()),
- KGID: auth.KGID(os.Getgid()),
- }
- if ws, err := c.executeSync(argsTouch); err != nil {
- t.Fatalf("unexpected error touching file %q: %v", filename, err)
- } else if ws.ExitStatus() != 0 {
- t.Errorf("touch %q exited with code %v, wanted zero", filename, ws.ExitStatus())
- }
-
- // File should exist outside the sandbox.
- if _, err := os.Stat(filename); err != nil {
- t.Errorf("stat %q got error %v, wanted nil", filename, err)
- }
-
- // File should exist outside the sandbox.
- if _, err := os.Stat(filename); err != nil {
- t.Errorf("stat %q got error %v, wanted nil", filename, err)
- }
-
- // Delete the file from within the sandbox.
- argsRemove := &control.ExecArgs{
- Filename: "/bin/rm",
- Argv: []string{"rm", filename},
- }
- if ws, err := c.executeSync(argsRemove); err != nil {
- t.Fatalf("unexpected error removing file %q: %v", filename, err)
- } else if ws.ExitStatus() != 0 {
- t.Errorf("remove %q exited with code %v, wanted zero", filename, ws.ExitStatus())
- }
-
- // File should not exist outside the sandbox.
- if _, err := os.Stat(filename); !os.IsNotExist(err) {
- t.Errorf("stat %q got error %v, wanted ErrNotExist", filename, err)
- }
-}
-
func TestGoferExits(t *testing.T) {
spec := testutil.NewSpecWithArgs("/bin/sleep", "10000")
conf := testutil.TestConfig()
diff --git a/runsc/container/shared_volume_test.go b/runsc/container/shared_volume_test.go
new file mode 100644
index 000000000..8f81ed630
--- /dev/null
+++ b/runsc/container/shared_volume_test.go
@@ -0,0 +1,267 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package container
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "gvisor.googlesource.com/gvisor/pkg/sentry/control"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth"
+ "gvisor.googlesource.com/gvisor/runsc/boot"
+ "gvisor.googlesource.com/gvisor/runsc/test/testutil"
+)
+
+// TestSharedVolume checks that modifications to a volume mount are propagated
+// into and out of the sandbox.
+func TestSharedVolume(t *testing.T) {
+ conf := testutil.TestConfig()
+ conf.FileAccess = boot.FileAccessShared
+ t.Logf("Running test with conf: %+v", conf)
+
+ // Main process just sleeps. We will use "exec" to probe the state of
+ // the filesystem.
+ spec := testutil.NewSpecWithArgs("sleep", "1000")
+
+ dir, err := ioutil.TempDir(testutil.TmpDir(), "shared-volume-test")
+ if err != nil {
+ t.Fatalf("TempDir failed: %v", err)
+ }
+
+ 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 and start 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)
+ }
+
+ // File that will be used to check consistency inside/outside sandbox.
+ filename := filepath.Join(dir, "file")
+
+ // File does not exist yet. Reading from the sandbox should fail.
+ argsTestFile := &control.ExecArgs{
+ Filename: "/usr/bin/test",
+ Argv: []string{"test", "-f", filename},
+ }
+ if ws, err := c.executeSync(argsTestFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", filename, err)
+ } else if ws.ExitStatus() == 0 {
+ t.Errorf("test %q exited with code %v, wanted not zero", ws.ExitStatus(), err)
+ }
+
+ // Create the file from outside of the sandbox.
+ if err := ioutil.WriteFile(filename, []byte("foobar"), 0777); err != nil {
+ t.Fatalf("error writing to file %q: %v", filename, err)
+ }
+
+ // Now we should be able to test the file from within the sandbox.
+ if ws, err := c.executeSync(argsTestFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", filename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("test %q exited with code %v, wanted zero", filename, ws.ExitStatus())
+ }
+
+ // Rename the file from outside of the sandbox.
+ newFilename := filepath.Join(dir, "newfile")
+ if err := os.Rename(filename, newFilename); err != nil {
+ t.Fatalf("os.Rename(%q, %q) failed: %v", filename, newFilename, err)
+ }
+
+ // File should no longer exist at the old path within the sandbox.
+ if ws, err := c.executeSync(argsTestFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", filename, err)
+ } else if ws.ExitStatus() == 0 {
+ t.Errorf("test %q exited with code %v, wanted not zero", filename, ws.ExitStatus())
+ }
+
+ // We should be able to test the new filename from within the sandbox.
+ argsTestNewFile := &control.ExecArgs{
+ Filename: "/usr/bin/test",
+ Argv: []string{"test", "-f", newFilename},
+ }
+ if ws, err := c.executeSync(argsTestNewFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", newFilename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("test %q exited with code %v, wanted zero", newFilename, ws.ExitStatus())
+ }
+
+ // Delete the renamed file from outside of the sandbox.
+ if err := os.Remove(newFilename); err != nil {
+ t.Fatalf("error removing file %q: %v", filename, err)
+ }
+
+ // Renamed file should no longer exist at the old path within the sandbox.
+ if ws, err := c.executeSync(argsTestNewFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", newFilename, err)
+ } else if ws.ExitStatus() == 0 {
+ t.Errorf("test %q exited with code %v, wanted not zero", newFilename, ws.ExitStatus())
+ }
+
+ // Now create the file from WITHIN the sandbox.
+ argsTouch := &control.ExecArgs{
+ Filename: "/usr/bin/touch",
+ Argv: []string{"touch", filename},
+ KUID: auth.KUID(os.Getuid()),
+ KGID: auth.KGID(os.Getgid()),
+ }
+ if ws, err := c.executeSync(argsTouch); err != nil {
+ t.Fatalf("unexpected error touching file %q: %v", filename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("touch %q exited with code %v, wanted zero", filename, ws.ExitStatus())
+ }
+
+ // File should exist outside the sandbox.
+ if _, err := os.Stat(filename); err != nil {
+ t.Errorf("stat %q got error %v, wanted nil", filename, err)
+ }
+
+ // File should exist outside the sandbox.
+ if _, err := os.Stat(filename); err != nil {
+ t.Errorf("stat %q got error %v, wanted nil", filename, err)
+ }
+
+ // Delete the file from within the sandbox.
+ argsRemove := &control.ExecArgs{
+ Filename: "/bin/rm",
+ Argv: []string{"rm", filename},
+ }
+ if ws, err := c.executeSync(argsRemove); err != nil {
+ t.Fatalf("unexpected error removing file %q: %v", filename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("remove %q exited with code %v, wanted zero", filename, ws.ExitStatus())
+ }
+
+ // File should not exist outside the sandbox.
+ if _, err := os.Stat(filename); !os.IsNotExist(err) {
+ t.Errorf("stat %q got error %v, wanted ErrNotExist", filename, err)
+ }
+}
+
+func checkFile(c *Container, filename string, want []byte) error {
+ cpy := filename + ".copy"
+ argsCp := &control.ExecArgs{
+ Filename: "/bin/cp",
+ Argv: []string{"cp", "-f", filename, cpy},
+ }
+ if _, err := c.executeSync(argsCp); err != nil {
+ return fmt.Errorf("unexpected error copying file %q to %q: %v", filename, cpy, err)
+ }
+ got, err := ioutil.ReadFile(cpy)
+ if err != nil {
+ return fmt.Errorf("Error reading file %q: %v", filename, err)
+ }
+ if !bytes.Equal(got, want) {
+ return fmt.Errorf("file content inside the sandbox is wrong, got: %q, want: %q", got, want)
+ }
+ return nil
+}
+
+// TestSharedVolumeFile tests that changes to file content outside the sandbox
+// is reflected inside.
+func TestSharedVolumeFile(t *testing.T) {
+ conf := testutil.TestConfig()
+ conf.FileAccess = boot.FileAccessShared
+ t.Logf("Running test with conf: %+v", conf)
+
+ // Main process just sleeps. We will use "exec" to probe the state of
+ // the filesystem.
+ spec := testutil.NewSpecWithArgs("sleep", "1000")
+
+ dir, err := ioutil.TempDir(testutil.TmpDir(), "shared-volume-test")
+ if err != nil {
+ t.Fatalf("TempDir failed: %v", err)
+ }
+
+ 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 and start 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)
+ }
+
+ // File that will be used to check consistency inside/outside sandbox.
+ filename := filepath.Join(dir, "file")
+
+ // Write file from outside the container and check that the same content is
+ // read inside.
+ want := []byte("host-")
+ if err := ioutil.WriteFile(filename, []byte(want), 0666); err != nil {
+ t.Fatalf("Error writing to %q: %v", filename, err)
+ }
+ if err := checkFile(c, filename, want); err != nil {
+ t.Fatal(err.Error())
+ }
+
+ // Append to file inside the container and check that content is not lost.
+ argsAppend := &control.ExecArgs{
+ Filename: "/bin/bash",
+ Argv: []string{"bash", "-c", "echo -n sandbox- >> " + filename},
+ }
+ if _, err := c.executeSync(argsAppend); err != nil {
+ t.Fatalf("unexpected error appending file %q: %v", filename, err)
+ }
+ want = []byte("host-sandbox-")
+ if err := checkFile(c, filename, want); err != nil {
+ t.Fatal(err.Error())
+ }
+
+ // Write again from outside the container and check that the same content is
+ // read inside.
+ f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0)
+ if err != nil {
+ t.Fatalf("Error openning file %q: %v", filename, err)
+ }
+ defer f.Close()
+ if _, err := f.Write([]byte("host")); err != nil {
+ t.Fatalf("Error writing to file %q: %v", filename, err)
+ }
+ want = []byte("host-sandbox-host")
+ if err := checkFile(c, filename, want); err != nil {
+ t.Fatal(err.Error())
+ }
+
+ // Shrink file outside and check that the same content is read inside.
+ if err := f.Truncate(5); err != nil {
+ t.Fatalf("Error truncating file %q: %v", filename, err)
+ }
+ want = want[:5]
+ if err := checkFile(c, filename, want); err != nil {
+ t.Fatal(err.Error())
+ }
+}