Example #1
0
func pivotRoot(rootfs, pivotBaseDir string) error {
	if pivotBaseDir == "" {
		pivotBaseDir = "/"
	}
	tmpDir := filepath.Join(rootfs, pivotBaseDir)
	if err := os.MkdirAll(tmpDir, 0755); err != nil {
		return fmt.Errorf("can't create tmp dir %s, error %v", tmpDir, err)
	}
	pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root")
	if err != nil {
		return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
	}
	if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
		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))
	if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("unmount pivot_root dir %s", err)
	}
	return os.Remove(pivotDir)
}
Example #2
0
func pivotRoot(rootfs, pivotBaseDir string) error {
	if pivotBaseDir == "" {
		pivotBaseDir = "/"
	}
	tmpDir := filepath.Join(rootfs, pivotBaseDir)
	if err := os.MkdirAll(tmpDir, 0755); err != nil {
		return fmt.Errorf("can't create tmp dir %s, error %v", tmpDir, err)
	}
	pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root")
	if err != nil {
		return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
	}
	if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
		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
	// propagate to parent.
	if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
		return err
	}

	if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("unmount pivot_root dir %s", err)
	}
	return os.Remove(pivotDir)
}
Example #3
0
func (r *RootFS) Enter() error {
	if err := checkDirectory(r.Root); err != nil {
		return err
	}

	if err := syscall.Mount(r.Root, r.Root, "", uintptr(syscall.MS_BIND|syscall.MS_REC), ""); err != nil {
		return fmt.Errorf("system: failed to bind mount the root filesystem onto itself: %s", err)
	}

	if err := os.Chdir(r.Root); err != nil {
		return fmt.Errorf("system: failed to change directory into the bind mounted rootfs dir: %s", err)
	}

	if err := os.MkdirAll("tmp/garden-host", 0700); err != nil {
		return fmt.Errorf("system: mkdir: %s", err)
	}

	if err := syscall.PivotRoot(".", "tmp/garden-host"); err != nil {
		return fmt.Errorf("system: failed to pivot root: %s", err)
	}

	if err := os.Chdir("/"); err != nil {
		return fmt.Errorf("system: failed to chdir to new root: %s", err)
	}

	return nil
}
Example #4
0
func pivotRoot(root string) error {
	// we need this to satisfy restriction:
	// "new_root and put_old must not be on the same filesystem as the current root"
	if err := syscall.Mount(root, root, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
		return fmt.Errorf("Mount rootfs to itself error: %v", err)
	}
	// create rootfs/.pivot_root as path for old_root
	pivotDir := filepath.Join(root, ".pivot_root")
	if err := os.Mkdir(pivotDir, 0777); err != nil {
		return err
	}
	logrus.Debugf("Pivot root dir: %s", pivotDir)
	logrus.Debugf("Pivot root to %s", root)
	// pivot_root to rootfs, now old_root is mounted in rootfs/.pivot_root
	// mounts from it still can be seen in `mount`
	if err := syscall.PivotRoot(root, pivotDir); err != nil {
		return fmt.Errorf("pivot_root %v", err)
	}
	// change working directory to /
	// it is recommendation from man-page
	if err := syscall.Chdir("/"); err != nil {
		return fmt.Errorf("chdir / %v", err)
	}
	// path to pivot root now changed, update
	pivotDir = filepath.Join("/", ".pivot_root")
	// umount rootfs/.pivot_root(which is now /.pivot_root) with all submounts
	// now we have only mounts that we mounted ourself in `mount`
	if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("unmount pivot_root dir %v", err)
	}
	// remove temporary directory
	return os.Remove(pivotDir)
}
Example #5
0
func main() {
	flag.Usage = usage
	flag.Parse()
	if flag.NArg() < 2 {
		usage()
	}
	ck(syscall.PivotRoot(flag.Arg(0), flag.Arg(1)))
}
Example #6
0
// pivotRoot will call pivot_root such that rootfs becomes the new root
// filesystem, and everything else is cleaned up.
func pivotRoot(rootfs string) error {
	// While the documentation may claim otherwise, pivot_root(".", ".") is
	// actually valid. What this results in is / being the new root but
	// /proc/self/cwd being the old root. Since we can play around with the cwd
	// 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.

	oldroot, err := syscall.Open("/", syscall.O_DIRECTORY|syscall.O_RDONLY, 0)
	if err != nil {
		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 {
		return fmt.Errorf("pivot_root %s", err)
	}

	// Currently our "." is oldroot (according to the current kernel code).
	// However, purely for safety, we will fchdir(oldroot) since there isn't
	// 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
	}

	// Make oldroot rprivate to make sure our unmounts don't propagate to the
	// 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
}
Example #7
0
/*   PivotRoot()
 */
func PivotRoot(rootfs string) error {
	pivotRoot := filepath.Join(rootfs, ".pivot_root")

	if e := BindMount("/dev", filepath.Join(rootfs, "dev")); e != nil {
		return fmt.Errorf("Failed to bind mount dev: %v", e)
	}

	if e := BindMount("/proc", filepath.Join(rootfs, "proc")); e != nil {
		return fmt.Errorf("Failed to bind mount dev: %v", e)
	}

	if e := BindMount("/sys", filepath.Join(rootfs, "sys")); e != nil {
		return fmt.Errorf("Failed to mount sysfs: %v", e)
	}

	if e := BindMount(rootfs, rootfs); e != nil {
		return fmt.Errorf("Failed to bind mount rootfs: %v", e)
	}

	if _, e := os.Stat(pivotRoot); os.IsNotExist(e) {
		if e := os.Mkdir(pivotRoot, 755); e != nil {
			return fmt.Errorf("Failed to make .pivot_root dir: %v", e)
		}
	}

	if e := syscall.PivotRoot(rootfs, pivotRoot); e != nil {
		return fmt.Errorf("Failed to pivot_root: %v", e)
	}

	if e := syscall.Chdir("/"); e != nil {
		return fmt.Errorf("Failed to cd to /: %v", e)
	}

	if e := syscall.Unmount("/.pivot_root", syscall.MNT_DETACH); e != nil {
		return fmt.Errorf("Failed to unmount pivot_root dir: %v", e)
	}

	if e := os.Remove("/.pivot_root"); e != nil {
		return fmt.Errorf("Failed to rmdir /.pivot_root: %v", e)
	}

	return nil
}
Example #8
0
func child() {
	// Create temp file for NS
	path := "/proc/self/ns/net"

	must(syscall.Mount("fs/rootfs", "fs/rootfs", "", syscall.MS_BIND, ""))
	must(os.MkdirAll("fs/rootfs/oldrootfs", 0700))
	must(syscall.PivotRoot("fs/rootfs", "fs/rootfs/oldrootfs"))
	must(os.Chdir("/"))

	must(syscall.Unmount("/oldrootfs", syscall.MNT_DETACH))
	must(os.Remove("/oldrootfs"))
	must(syscall.Mount("proc", "/proc", "proc", 0, ""))

	// Some devices
	syscall.Mknod("/dev/null", 0666, Mkdev(int64(1), int64(3)))
	syscall.Mknod("/dev/zero", 0666, Mkdev(int64(1), int64(5)))
	syscall.Mknod("/dev/random", 0666, Mkdev(int64(1), int64(8)))
	syscall.Mknod("/dev/urandom", 0666, Mkdev(int64(1), int64(9)))

	fmt.Println("Pid:", os.Getpid())

	ns, err := netns.GetFromPath(path)
	if err != nil {
		fmt.Println("cant find ns")
	}
	must(netns.Set(ns))

	routingUp()

	cmd := exec.Command(os.Args[2], os.Args[3:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("ERROR", err)
		os.Exit(1)
	}

	routingDown()

}
Example #9
0
func PivotRoot(rootfs string) error {
	pivotDir, err := ioutil.TempDir(rootfs, ".pivot_root")
	if err != nil {
		return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
	}

	if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
		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("/", filepath.Base(pivotDir))
	if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("unmount pivot_root dir %s", err)
	}

	return os.Remove(pivotDir)
}
Example #10
0
func Pivotroot(newroot, putold string) error {
	return syscall.PivotRoot(newroot, putold)
}
Example #11
0
// chroot on linux uses pivot_root instead of chroot
// pivot_root takes a new root and an old root.
// Old root must be a sub-dir of new root, it is where the current rootfs will reside after the call to pivot_root.
// New root is where the new rootfs is set to.
// Old root is removed after the call to pivot_root so it is no longer available under the new root.
// This is similar to how libcontainer sets up a container's rootfs
func chroot(path string) (err error) {
	// Create new mount namespace so mounts don't leak
	if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
		return fmt.Errorf("Error creating mount namespace before pivot: %v", err)
	}
	// path must be a different fs for pivot_root, so bind-mount to itself to ensure this
	if err := syscall.Mount(path, path, "", syscall.MS_BIND, ""); err != nil {
		return fmt.Errorf("Error mounting pivot dir before pivot: %v", err)
	}

	// setup oldRoot for pivot_root
	pivotDir, err := ioutil.TempDir(path, ".pivot_root")
	if err != nil {
		return fmt.Errorf("Error setting up pivot dir: %v", err)
	}

	var mounted bool
	defer func() {
		if mounted {
			// make sure pivotDir is not mounted before we try to remove it
			if errCleanup := syscall.Unmount(pivotDir, syscall.MNT_DETACH); errCleanup != nil {
				if err == nil {
					err = errCleanup
				}
				return
			}
		}

		errCleanup := os.Remove(pivotDir)
		// pivotDir doesn't exist if pivot_root failed and chroot+chdir was successful
		// but we already cleaned it up on failed pivot_root
		if errCleanup != nil && !os.IsNotExist(errCleanup) {
			errCleanup = fmt.Errorf("Error cleaning up after pivot: %v", errCleanup)
			if err == nil {
				err = errCleanup
			}
		}
	}()

	if err := syscall.PivotRoot(path, pivotDir); err != nil {
		// If pivot fails, fall back to the normal chroot after cleaning up temp dir for pivot_root
		if err := os.Remove(pivotDir); err != nil {
			return fmt.Errorf("Error cleaning up after failed pivot: %v", err)
		}
		return realChroot(path)
	}
	mounted = true

	// This is the new path for where the old root (prior to the pivot) has been moved to
	// This dir contains the rootfs of the caller, which we need to remove so it is not visible during extraction
	pivotDir = filepath.Join("/", filepath.Base(pivotDir))

	if err := syscall.Chdir("/"); err != nil {
		return fmt.Errorf("Error changing to new root: %v", err)
	}

	// Make the pivotDir (where the old root lives) private so it can be unmounted without propagating to the host
	if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
		return fmt.Errorf("Error making old root private after pivot: %v", err)
	}

	// Now unmount the old root so it's no longer visible from the new root
	if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("Error while unmounting old root after pivot: %v", err)
	}
	mounted = false

	return nil
}