Skip to content

Commit c7ed224

Browse files
committed
merge branch 'pr-1125'
LGTMs: @hqhq @mrunalp Closes #1125
2 parents 35f55e6 + f8e6b5a commit c7ed224

File tree

2 files changed

+46
-33
lines changed

2 files changed

+46
-33
lines changed

libcontainer/configs/config.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ type Config struct {
8585
// that the parent process dies.
8686
ParentDeathSignal int `json:"parent_death_signal"`
8787

88-
// PivotDir allows a custom directory inside the container's root filesystem to be used as pivot, when NoPivotRoot is not set.
89-
// When a custom PivotDir not set, a temporary dir inside the root filesystem will be used. The pivot dir needs to be writeable.
90-
// 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.
91-
PivotDir string `json:"pivot_dir"`
92-
9388
// Path to a directory containing the container's root filesystem.
9489
Rootfs string `json:"rootfs"`
9590

libcontainer/rootfs_linux.go

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func setupRootfs(config *configs.Config, console *linuxConsole, pipe io.ReadWrit
8484
if config.NoPivotRoot {
8585
err = msMoveRoot(config.Rootfs)
8686
} else {
87-
err = pivotRoot(config.Rootfs, config.PivotDir)
87+
err = pivotRoot(config.Rootfs)
8888
}
8989
if err != nil {
9090
return newSystemErrorWithCause(err, "jailing process inside rootfs")
@@ -590,48 +590,66 @@ func setupPtmx(config *configs.Config, console *linuxConsole) error {
590590
return nil
591591
}
592592

593-
func pivotRoot(rootfs, pivotBaseDir string) (err error) {
594-
if pivotBaseDir == "" {
595-
pivotBaseDir = "/"
596-
}
597-
tmpDir := filepath.Join(rootfs, pivotBaseDir)
598-
if err := os.MkdirAll(tmpDir, 0755); err != nil {
599-
return fmt.Errorf("can't create tmp dir %s, error %v", tmpDir, err)
593+
// pivotRoot will call pivot_root such that rootfs becomes the new root
594+
// filesystem, and everything else is cleaned up.
595+
func pivotRoot(rootfs string) error {
596+
// While the documentation may claim otherwise, pivot_root(".", ".") is
597+
// actually valid. What this results in is / being the new root but
598+
// /proc/self/cwd being the old root. Since we can play around with the cwd
599+
// with pivot_root this allows us to pivot without creating directories in
600+
// the rootfs. Shout-outs to the LXC developers for giving us this idea.
601+
602+
oldroot, err := syscall.Open("/", syscall.O_DIRECTORY|syscall.O_RDONLY, 0)
603+
if err != nil {
604+
return err
600605
}
601-
pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root")
606+
defer syscall.Close(oldroot)
607+
608+
newroot, err := syscall.Open(rootfs, syscall.O_DIRECTORY|syscall.O_RDONLY, 0)
602609
if err != nil {
603-
return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
610+
return err
604611
}
605-
defer func() {
606-
errVal := os.Remove(pivotDir)
607-
if err == nil {
608-
err = errVal
609-
}
610-
}()
611-
if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
612+
defer syscall.Close(newroot)
613+
614+
// Change to the new root so that the pivot_root actually acts on it.
615+
if err := syscall.Fchdir(newroot); err != nil {
616+
return err
617+
}
618+
619+
if err := syscall.PivotRoot(".", "."); err != nil {
612620
// Make the parent mount private
613-
if err := rootfsParentMountPrivate(rootfs); err != nil {
621+
if err := rootfsParentMountPrivate("."); err != nil {
614622
return err
615623
}
624+
616625
// Try again
617-
if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
626+
if err := syscall.PivotRoot(".", "."); err != nil {
618627
return fmt.Errorf("pivot_root %s", err)
619628
}
620629
}
621-
if err := syscall.Chdir("/"); err != nil {
622-
return fmt.Errorf("chdir / %s", err)
630+
631+
// Currently our "." is oldroot (according to the current kernel code).
632+
// However, purely for safety, we will fchdir(oldroot) since there isn't
633+
// really any guarantee from the kernel what /proc/self/cwd will be after a
634+
// pivot_root(2).
635+
636+
if err := syscall.Fchdir(oldroot); err != nil {
637+
return err
623638
}
624-
// path to pivot dir now changed, update
625-
pivotDir = filepath.Join(pivotBaseDir, filepath.Base(pivotDir))
626639

627-
// Make pivotDir rprivate to make sure any of the unmounts don't
628-
// propagate to parent.
629-
if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
640+
// Make oldroot rprivate to make sure our unmounts don't propogate to the
641+
// host (and thus bork the machine).
642+
if err := syscall.Mount("", ".", "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
643+
return err
644+
}
645+
// Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd.
646+
if err := syscall.Unmount(".", syscall.MNT_DETACH); err != nil {
630647
return err
631648
}
632649

633-
if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
634-
return fmt.Errorf("unmount pivot_root dir %s", err)
650+
// Switch back to our shiny new root.
651+
if err := syscall.Chdir("/"); err != nil {
652+
return fmt.Errorf("chdir / %s", err)
635653
}
636654
return nil
637655
}

0 commit comments

Comments
 (0)