-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request moby#22506 from cpuguy83/no_chroot
Use pivot_root instead of chroot for chrootarchive
- Loading branch information
Showing
3 changed files
with
102 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package chrootarchive | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"syscall" | ||
) | ||
|
||
// 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) | ||
if errCleanup != nil { | ||
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 | ||
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 | ||
} | ||
|
||
func realChroot(path string) error { | ||
if err := syscall.Chroot(path); err != nil { | ||
return fmt.Errorf("Error after fallback to chroot: %v", err) | ||
} | ||
if err := syscall.Chdir("/"); err != nil { | ||
return fmt.Errorf("Error chaning to new root after chroot: %v", err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// +build !windows,!linux | ||
|
||
package chrootarchive | ||
|
||
import "syscall" | ||
|
||
func chroot(path string) error { | ||
if err := syscall.Chroot(path); err != nil { | ||
return err | ||
} | ||
return syscall.Chdir("/") | ||
} |