The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/distrobuilder/pull/18
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Signed-off-by: Stéphane Graber <[email protected]>
From 3ed3b15cf7951948b7b8a7e335e4c9c68b236481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]> Date: Wed, 21 Feb 2018 13:31:48 -0500 Subject: [PATCH] chroot: Fix mount logic and symlink handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <[email protected]> --- distrobuilder/chroot.go | 74 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/distrobuilder/chroot.go b/distrobuilder/chroot.go index f055d73..f859dcb 100644 --- a/distrobuilder/chroot.go +++ b/distrobuilder/chroot.go @@ -22,15 +22,19 @@ type chrootMount struct { } func setupMounts(rootfs string, mounts []chrootMount) error { + // Create a temporary mount path err := os.MkdirAll(filepath.Join(rootfs, ".distrobuilder"), 0700) if err != nil { return err } for i, mount := range mounts { + // Target path tmpTarget := filepath.Join(rootfs, ".distrobuilder", fmt.Sprintf("%d", i)) + + // Create the target mountpoint if mount.isDir { - err := os.MkdirAll(tmpTarget, 0755) + err := os.Mkdir(tmpTarget, 0755) if err != nil { return err } @@ -41,6 +45,7 @@ func setupMounts(rootfs string, mounts []chrootMount) error { } } + // Mount to the temporary path err := syscall.Mount(mount.source, tmpTarget, mount.fstype, mount.flags, mount.data) if err != nil { return fmt.Errorf("Failed to mount '%s': %s", mount.source, err) @@ -52,25 +57,59 @@ func setupMounts(rootfs string, mounts []chrootMount) error { func moveMounts(mounts []chrootMount) error { for i, mount := range mounts { + // Source path tmpSource := filepath.Join("/", ".distrobuilder", fmt.Sprintf("%d", i)) + + // Resolve symlinks + target := mount.target + for { + // Get information on current target + fi, err := os.Lstat(target) + if err != nil { + break + } + + // If not a symlink, we're done + if fi.Mode()&os.ModeSymlink == 0 { + break + } + + // If a symlink, resolve it + newTarget, err := os.Readlink(target) + if err != nil { + break + } + + target = newTarget + } + + // Create parent paths if missing + err := os.MkdirAll(filepath.Dir(target), 0755) + if err != nil { + return err + } + + // Create target path if mount.isDir { - err := os.MkdirAll(mount.target, 0755) + err = os.MkdirAll(target, 0755) if err != nil { return err } } else { - _, err := os.Create(mount.target) + _, err = os.Create(target) if err != nil { return err } } - err := syscall.Mount(tmpSource, mount.target, "", syscall.MS_MOVE, "") + // Move the mount to its destination + err = syscall.Mount(tmpSource, target, "", syscall.MS_MOVE, "") if err != nil { return fmt.Errorf("Failed to mount '%s': %s", mount.source, err) } } + // Cleanup our temporary path err := os.RemoveAll(filepath.Join("/", ".distrobuilder")) if err != nil { return err @@ -81,6 +120,7 @@ func moveMounts(mounts []chrootMount) error { } func killChrootProcesses(rootfs string) error { + // List all files under /proc proc, err := os.Open(filepath.Join(rootfs, "proc")) if err != nil { return err @@ -91,6 +131,7 @@ func killChrootProcesses(rootfs string) error { return err } + // Get all processes and kill them for _, dir := range dirs { match, _ := regexp.MatchString(`\d+`, dir) if match { @@ -106,10 +147,14 @@ func killChrootProcesses(rootfs string) error { } func setupChroot(rootfs string) (func() error, error) { - var err error + // Mount the rootfs + err := syscall.Mount(rootfs, rootfs, "", syscall.MS_BIND, "") + if err != nil { + return nil, fmt.Errorf("Failed to mount '%s': %s", rootfs, err) + } + // Setup all other needed mounts mounts := []chrootMount{ - {rootfs, "/", "", syscall.MS_BIND, "", true}, {"none", "/proc", "proc", 0, "", true}, {"none", "/sys", "sysfs", 0, "", true}, {"/dev", "/dev", "", syscall.MS_BIND, "", true}, @@ -118,21 +163,24 @@ func setupChroot(rootfs string) (func() error, error) { {"/etc/resolv.conf", "/etc/resolv.conf", "", syscall.MS_BIND, "", false}, } - cwd, err := os.Getwd() + // Keep a reference to the host rootfs and cwd + root, err := os.Open("/") if err != nil { return nil, err } - err = setupMounts(rootfs, mounts) + cwd, err := os.Getwd() if err != nil { - return nil, fmt.Errorf("Failed to mount filesystems: %v", err) + return nil, err } - root, err := os.Open("/") + // Setup all needed mounts in a temporary location + err = setupMounts(rootfs, mounts) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to mount filesystems: %v", err) } + // Chroot into the container's rootfs err = syscall.Chroot(rootfs) if err != nil { root.Close() @@ -144,6 +192,7 @@ func setupChroot(rootfs string) (func() error, error) { return nil, err } + // Move all the mounts into place err = moveMounts(mounts) if err != nil { return nil, err @@ -152,6 +201,7 @@ func setupChroot(rootfs string) (func() error, error) { return func() error { defer root.Close() + // Switch back to the host rootfs err = root.Chdir() if err != nil { return err @@ -170,6 +220,8 @@ func setupChroot(rootfs string) (func() error, error) { // This will kill all processes in the chroot and allow to cleanly // unmount everything. killChrootProcesses(rootfs) + + // And now unmount the entire tree syscall.Unmount(rootfs, syscall.MNT_DETACH) return nil
_______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
