From da605a43d62ec827443185a4c5b94c283ba85001 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 6 Mar 2014 19:30:52 -0800 Subject: [PATCH] Add env var to toggle pivot root or ms_move Use the DOCKER_RAMDISK env var to tell the native driver not to use a pivot root when setting up the rootfs of a container. Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- libcontainer/container.go | 23 ++++++++++--------- libcontainer/nsinit/init.go | 2 +- libcontainer/nsinit/mount.go | 44 +++++++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/libcontainer/container.go b/libcontainer/container.go index bd16825..a777da5 100644 --- a/libcontainer/container.go +++ b/libcontainer/container.go @@ -11,17 +11,18 @@ type Context map[string]string // Container defines configuration options for how a // container is setup inside a directory and how a process should be executed type Container struct { - Hostname string `json:"hostname,omitempty"` // hostname - ReadonlyFs bool `json:"readonly_fs,omitempty"` // set the containers rootfs as readonly - User string `json:"user,omitempty"` // user to execute the process as - WorkingDir string `json:"working_dir,omitempty"` // current working directory - Env []string `json:"environment,omitempty"` // environment to set - Tty bool `json:"tty,omitempty"` // setup a proper tty or not - Namespaces Namespaces `json:"namespaces,omitempty"` // namespaces to apply - Capabilities Capabilities `json:"capabilities,omitempty"` // capabilities to drop - Networks []*Network `json:"networks,omitempty"` // nil for host's network stack - Cgroups *cgroups.Cgroup `json:"cgroups,omitempty"` // cgroups - Context Context `json:"context,omitempty"` // generic context for specific options (apparmor, selinux) + Hostname string `json:"hostname,omitempty"` // hostname + ReadonlyFs bool `json:"readonly_fs,omitempty"` // set the containers rootfs as readonly + NoPivotRoot bool `json:"no_pivot_root,omitempty"` // this can be enabled if you are running in ramdisk + User string `json:"user,omitempty"` // user to execute the process as + WorkingDir string `json:"working_dir,omitempty"` // current working directory + Env []string `json:"environment,omitempty"` // environment to set + Tty bool `json:"tty,omitempty"` // setup a proper tty or not + Namespaces Namespaces `json:"namespaces,omitempty"` // namespaces to apply + Capabilities Capabilities `json:"capabilities,omitempty"` // capabilities to drop + Networks []*Network `json:"networks,omitempty"` // nil for host's network stack + Cgroups *cgroups.Cgroup `json:"cgroups,omitempty"` // cgroups + Context Context `json:"context,omitempty"` // generic context for specific options (apparmor, selinux) } // Network defines configuration for a container's networking stack diff --git a/libcontainer/nsinit/init.go b/libcontainer/nsinit/init.go index 8d3f908..336fc1e 100644 --- a/libcontainer/nsinit/init.go +++ b/libcontainer/nsinit/init.go @@ -51,7 +51,7 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol if err := system.ParentDeathSignal(); err != nil { return fmt.Errorf("parent death signal %s", err) } - if err := setupNewMountNamespace(rootfs, console, container.ReadonlyFs); err != nil { + if err := setupNewMountNamespace(rootfs, console, container.ReadonlyFs, container.NoPivotRoot); err != nil { return fmt.Errorf("setup mount namespace %s", err) } if err := setupNetwork(container, context); err != nil { diff --git a/libcontainer/nsinit/mount.go b/libcontainer/nsinit/mount.go index 69d85d6..83577cf 100644 --- a/libcontainer/nsinit/mount.go +++ b/libcontainer/nsinit/mount.go @@ -19,9 +19,12 @@ const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NOD // // There is no need to unmount the new mounts because as soon as the mount namespace // is no longer in use, the mounts will be removed automatically -func setupNewMountNamespace(rootfs, console string, readonly bool) error { - // mount as slave so that the new mounts do not propagate to the host - if err := system.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil { +func setupNewMountNamespace(rootfs, console string, readonly, noPivotRoot bool) error { + flag := syscall.MS_PRIVATE + if noPivotRoot { + flag = syscall.MS_SLAVE + } + if err := system.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil { return fmt.Errorf("mounting / as slave %s", err) } if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil { @@ -52,6 +55,23 @@ func setupNewMountNamespace(rootfs, console string, readonly bool) error { return fmt.Errorf("chdir into %s %s", rootfs, err) } + if noPivotRoot { + if err := rootMsMove(rootfs); err != nil { + return err + } + } else { + if err := rootPivot(rootfs); err != nil { + return err + } + } + + system.Umask(0022) + + return nil +} + +// use a pivot root to setup the rootfs +func rootPivot(rootfs string) error { pivotDir, err := ioutil.TempDir(rootfs, ".pivot_root") if err != nil { return fmt.Errorf("can't create pivot_root dir %s", pivotDir, err) @@ -62,20 +82,28 @@ func setupNewMountNamespace(rootfs, console string, readonly bool) error { if err := system.Chdir("/"); err != nil { return fmt.Errorf("chdir / %s", err) } - // path to pivot dir now changed, update pivotDir = filepath.Join("/", filepath.Base(pivotDir)) - if err := system.Unmount(pivotDir, syscall.MNT_DETACH); err != nil { return fmt.Errorf("unmount pivot_root dir %s", err) } - if err := os.Remove(pivotDir); err != nil { return fmt.Errorf("remove pivot_root dir %s", err) } + return nil +} - system.Umask(0022) - +// use MS_MOVE and chroot to setup the rootfs +func rootMsMove(rootfs string) error { + if err := system.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil { + return fmt.Errorf("mount move %s into / %s", rootfs, err) + } + if err := system.Chroot("."); err != nil { + return fmt.Errorf("chroot . %s", err) + } + if err := system.Chdir("/"); err != nil { + return fmt.Errorf("chdir / %s", err) + } return nil }