summaryrefslogtreecommitdiffhomepage
path: root/runsc/container
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/container')
-rw-r--r--runsc/container/container.go26
-rw-r--r--runsc/container/container_test.go2
-rw-r--r--runsc/container/fs.go30
3 files changed, 44 insertions, 14 deletions
diff --git a/runsc/container/container.go b/runsc/container/container.go
index 0ec4d03c1..f76bad1aa 100644
--- a/runsc/container/container.go
+++ b/runsc/container/container.go
@@ -271,6 +271,19 @@ func Create(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSo
// init container in the sandbox.
if specutils.ShouldCreateSandbox(spec) {
log.Debugf("Creating new sandbox for container %q", id)
+
+ // Setup rootfs and mounts. It returns a new mount list with destination
+ // paths resolved. Since the spec for the root container is read from disk,
+ // Write the new spec to a new file that will be used by the sandbox.
+ cleanMounts, err := setupFS(spec, conf, bundleDir)
+ if err != nil {
+ return nil, fmt.Errorf("setup mounts: %v", err)
+ }
+ spec.Mounts = cleanMounts
+ if err := specutils.WriteCleanSpec(bundleDir, spec); err != nil {
+ return nil, fmt.Errorf("writing clean spec: %v", err)
+ }
+
ioFiles, err := c.createGoferProcess(spec, conf, bundleDir)
if err != nil {
return nil, err
@@ -351,6 +364,15 @@ func (c *Container) Start(conf *boot.Config) error {
return err
}
} else {
+ // Setup rootfs and mounts. It returns a new mount list with destination
+ // paths resolved. Replace the original spec with new mount list and start
+ // container.
+ cleanMounts, err := setupFS(c.Spec, conf, c.BundleDir)
+ if err != nil {
+ return fmt.Errorf("setup mounts: %v", err)
+ }
+ c.Spec.Mounts = cleanMounts
+
// Create the gofer process.
ioFiles, err := c.createGoferProcess(c.Spec, conf, c.BundleDir)
if err != nil {
@@ -691,10 +713,6 @@ func (c *Container) waitForStopped() error {
}
func (c *Container) createGoferProcess(spec *specs.Spec, conf *boot.Config, bundleDir string) ([]*os.File, error) {
- if err := setupFS(spec, conf, bundleDir); err != nil {
- return nil, fmt.Errorf("failed to setup mounts: %v", err)
- }
-
// Start with the general config flags.
args := conf.ToFlags()
args = append(args, "gofer", "--bundle", bundleDir)
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index e2bb7d8ec..662591b3b 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -458,7 +458,7 @@ func TestAppExitStatus(t *testing.T) {
defer os.RemoveAll(rootDir2)
defer os.RemoveAll(bundleDir2)
- ws, err = Run(testutil.UniqueContainerID(), succSpec, conf, bundleDir2, "", "", "")
+ ws, err = Run(testutil.UniqueContainerID(), errSpec, conf, bundleDir2, "", "", "")
if err != nil {
t.Fatalf("error running container: %v", err)
}
diff --git a/runsc/container/fs.go b/runsc/container/fs.go
index 59edd9488..2ed42fd93 100644
--- a/runsc/container/fs.go
+++ b/runsc/container/fs.go
@@ -73,9 +73,13 @@ var optionsMap = map[string]mapping{
// This allows the gofer serving the containers to be chroot under this
// directory to create an extra layer to security in case the gofer gets
// compromised.
-func setupFS(spec *specs.Spec, conf *boot.Config, bundleDir string) error {
+// Returns list of mounts equivalent to 'spec.Mounts' with all destination paths
+// cleaned and with symlinks resolved.
+func setupFS(spec *specs.Spec, conf *boot.Config, bundleDir string) ([]specs.Mount, error) {
+ rv := make([]specs.Mount, 0, len(spec.Mounts))
for _, m := range spec.Mounts {
if m.Type != "bind" || !specutils.IsSupportedDevMount(m) {
+ rv = append(rv, m)
continue
}
@@ -83,39 +87,47 @@ func setupFS(spec *specs.Spec, conf *boot.Config, bundleDir string) error {
// container.
dst, err := resolveSymlinks(spec.Root.Path, m.Destination)
if err != nil {
- return fmt.Errorf("failed to resolve symlinks: %v", err)
+ return nil, fmt.Errorf("failed to resolve symlinks: %v", err)
}
flags := optionsToFlags(m.Options)
flags |= syscall.MS_BIND
log.Infof("Mounting src: %q, dst: %q, flags: %#x", m.Source, dst, flags)
if err := specutils.Mount(m.Source, dst, m.Type, flags); err != nil {
- return fmt.Errorf("failed to mount %v: %v", m, err)
+ return nil, fmt.Errorf("failed to mount %v: %v", m, err)
}
// Make the mount a slave, so that for recursive bind mount, umount won't
// propagate to the source.
flags = syscall.MS_SLAVE | syscall.MS_REC
if err := syscall.Mount("", dst, "", uintptr(flags), ""); err != nil {
- return fmt.Errorf("failed to rslave mount dst: %q, flags: %#x, err: %v", dst, flags, err)
+ return nil, fmt.Errorf("failed to rslave mount dst: %q, flags: %#x, err: %v", dst, flags, err)
}
+
+ cpy := m
+ relDst, err := filepath.Rel(spec.Root.Path, dst)
+ if err != nil {
+ panic(fmt.Sprintf("%q could not be made relative to %q: %v", dst, spec.Root.Path, err))
+ }
+ cpy.Destination = filepath.Join("/", relDst)
+ rv = append(rv, cpy)
}
// If root is read only, check if it needs to be remounted as readonly.
if spec.Root.Readonly {
isMountPoint, readonly, err := mountInfo(spec.Root.Path)
if err != nil {
- return err
+ return nil, err
}
if readonly {
- return nil
+ return rv, nil
}
if !isMountPoint {
// Readonly root is not a mount point nor read-only. Can't do much other
// than just logging a warning. The gofer will prevent files to be open
// in write mode.
log.Warningf("Mount where root is located is not read-only and cannot be changed: %q", spec.Root.Path)
- return nil
+ return rv, nil
}
// If root is a mount point but not read-only, we can change mount options
@@ -124,10 +136,10 @@ func setupFS(spec *specs.Spec, conf *boot.Config, bundleDir string) error {
flags := uintptr(syscall.MS_BIND | syscall.MS_REMOUNT | syscall.MS_RDONLY | syscall.MS_REC)
src := spec.Root.Path
if err := syscall.Mount(src, src, "bind", flags, ""); err != nil {
- return fmt.Errorf("failed to remount root as read-only with source: %q, target: %q, flags: %#x, err: %v", spec.Root.Path, spec.Root.Path, flags, err)
+ return nil, fmt.Errorf("failed to remount root as read-only with source: %q, target: %q, flags: %#x, err: %v", spec.Root.Path, spec.Root.Path, flags, err)
}
}
- return nil
+ return rv, nil
}
// mountInfo returns whether the path is a mount point and whether the mount