commit
c7ed2244f4
|
@ -85,11 +85,6 @@ type Config struct {
|
||||||
// that the parent process dies.
|
// that the parent process dies.
|
||||||
ParentDeathSignal int `json:"parent_death_signal"`
|
ParentDeathSignal int `json:"parent_death_signal"`
|
||||||
|
|
||||||
// PivotDir allows a custom directory inside the container's root filesystem to be used as pivot, when NoPivotRoot is not set.
|
|
||||||
// When a custom PivotDir not set, a temporary dir inside the root filesystem will be used. The pivot dir needs to be writeable.
|
|
||||||
// This is required when using read only root filesystems. In these cases, a read/writeable path can be (bind) mounted somewhere inside the root filesystem to act as pivot.
|
|
||||||
PivotDir string `json:"pivot_dir"`
|
|
||||||
|
|
||||||
// Path to a directory containing the container's root filesystem.
|
// Path to a directory containing the container's root filesystem.
|
||||||
Rootfs string `json:"rootfs"`
|
Rootfs string `json:"rootfs"`
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ func setupRootfs(config *configs.Config, console *linuxConsole, pipe io.ReadWrit
|
||||||
if config.NoPivotRoot {
|
if config.NoPivotRoot {
|
||||||
err = msMoveRoot(config.Rootfs)
|
err = msMoveRoot(config.Rootfs)
|
||||||
} else {
|
} else {
|
||||||
err = pivotRoot(config.Rootfs, config.PivotDir)
|
err = pivotRoot(config.Rootfs)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newSystemErrorWithCause(err, "jailing process inside rootfs")
|
return newSystemErrorWithCause(err, "jailing process inside rootfs")
|
||||||
|
@ -590,48 +590,66 @@ func setupPtmx(config *configs.Config, console *linuxConsole) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pivotRoot(rootfs, pivotBaseDir string) (err error) {
|
// pivotRoot will call pivot_root such that rootfs becomes the new root
|
||||||
if pivotBaseDir == "" {
|
// filesystem, and everything else is cleaned up.
|
||||||
pivotBaseDir = "/"
|
func pivotRoot(rootfs string) error {
|
||||||
}
|
// While the documentation may claim otherwise, pivot_root(".", ".") is
|
||||||
tmpDir := filepath.Join(rootfs, pivotBaseDir)
|
// actually valid. What this results in is / being the new root but
|
||||||
if err := os.MkdirAll(tmpDir, 0755); err != nil {
|
// /proc/self/cwd being the old root. Since we can play around with the cwd
|
||||||
return fmt.Errorf("can't create tmp dir %s, error %v", tmpDir, err)
|
// with pivot_root this allows us to pivot without creating directories in
|
||||||
}
|
// the rootfs. Shout-outs to the LXC developers for giving us this idea.
|
||||||
pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root")
|
|
||||||
|
oldroot, err := syscall.Open("/", syscall.O_DIRECTORY|syscall.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
errVal := os.Remove(pivotDir)
|
|
||||||
if err == nil {
|
|
||||||
err = errVal
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
|
|
||||||
// Make the parent mount private
|
|
||||||
if err := rootfsParentMountPrivate(rootfs); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer syscall.Close(oldroot)
|
||||||
|
|
||||||
|
newroot, err := syscall.Open(rootfs, syscall.O_DIRECTORY|syscall.O_RDONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer syscall.Close(newroot)
|
||||||
|
|
||||||
|
// Change to the new root so that the pivot_root actually acts on it.
|
||||||
|
if err := syscall.Fchdir(newroot); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syscall.PivotRoot(".", "."); err != nil {
|
||||||
|
// Make the parent mount private
|
||||||
|
if err := rootfsParentMountPrivate("."); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Try again
|
// Try again
|
||||||
if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
|
if err := syscall.PivotRoot(".", "."); err != nil {
|
||||||
return fmt.Errorf("pivot_root %s", err)
|
return fmt.Errorf("pivot_root %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := syscall.Chdir("/"); err != nil {
|
|
||||||
return fmt.Errorf("chdir / %s", err)
|
|
||||||
}
|
|
||||||
// path to pivot dir now changed, update
|
|
||||||
pivotDir = filepath.Join(pivotBaseDir, filepath.Base(pivotDir))
|
|
||||||
|
|
||||||
// Make pivotDir rprivate to make sure any of the unmounts don't
|
// Currently our "." is oldroot (according to the current kernel code).
|
||||||
// propagate to parent.
|
// However, purely for safety, we will fchdir(oldroot) since there isn't
|
||||||
if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
|
// really any guarantee from the kernel what /proc/self/cwd will be after a
|
||||||
|
// pivot_root(2).
|
||||||
|
|
||||||
|
if err := syscall.Fchdir(oldroot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
|
// Make oldroot rprivate to make sure our unmounts don't propogate to the
|
||||||
return fmt.Errorf("unmount pivot_root dir %s", err)
|
// host (and thus bork the machine).
|
||||||
|
if err := syscall.Mount("", ".", "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd.
|
||||||
|
if err := syscall.Unmount(".", syscall.MNT_DETACH); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch back to our shiny new root.
|
||||||
|
if err := syscall.Chdir("/"); err != nil {
|
||||||
|
return fmt.Errorf("chdir / %s", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue