Skip to content
4 changes: 2 additions & 2 deletions internal/pathrs/mkdirall.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ import (
// Callers need to be very careful operating on the trailing path, as trivial
// mistakes like following symlinks can cause security bugs. Most people
// should probably just use [MkdirAllInRoot] or [CreateInRoot].
func MkdirAllParentInRoot(root, unsafePath string, mode os.FileMode) (*os.File, string, error) {
func MkdirAllParentInRoot(root *os.File, unsafePath string, mode os.FileMode) (*os.File, string, error) {
// MkdirAllInRoot also does hallucinateUnsafePath, but we need to do it
// here first because when we split unsafePath into (dir, file) components
// we want to be doing so with the hallucinated path (so that trailing
// dangling symlinks are treated correctly).
unsafePath, err := hallucinateUnsafePath(root, unsafePath)
unsafePath, err := hallucinateUnsafePath(root.Name(), unsafePath)
if err != nil {
return nil, "", fmt.Errorf("failed to construct hallucinated target path: %w", err)
}
Expand Down
15 changes: 4 additions & 11 deletions internal/pathrs/mkdirall_pathrslite.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ import (

"github.com/cyphar/filepath-securejoin/pathrs-lite"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)

// MkdirAllInRoot attempts to make
//
// path, _ := securejoin.SecureJoin(root, unsafePath)
// path, _ := securejoin.SecureJoin(root.Name(), unsafePath)
// os.MkdirAll(path, mode)
// os.Open(path)
//
Expand All @@ -48,8 +47,8 @@ import (
// handling if unsafePath has already been scoped within the rootfs (this is
// needed for a lot of runc callers and fixing this would require reworking a
// lot of path logic).
func MkdirAllInRoot(root, unsafePath string, mode os.FileMode) (*os.File, error) {
unsafePath, err := hallucinateUnsafePath(root, unsafePath)
func MkdirAllInRoot(root *os.File, unsafePath string, mode os.FileMode) (*os.File, error) {
unsafePath, err := hallucinateUnsafePath(root.Name(), unsafePath)
if err != nil {
return nil, fmt.Errorf("failed to construct hallucinated target path: %w", err)
}
Expand All @@ -67,13 +66,7 @@ func MkdirAllInRoot(root, unsafePath string, mode os.FileMode) (*os.File, error)
mode &= 0o1777
}

rootDir, err := os.OpenFile(root, unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
if err != nil {
return nil, fmt.Errorf("open root handle: %w", err)
}
defer rootDir.Close()

return retryEAGAIN(func() (*os.File, error) {
return pathrs.MkdirAllHandle(rootDir, unsafePath, mode)
return pathrs.MkdirAllHandle(root, unsafePath, mode)
})
}
10 changes: 5 additions & 5 deletions internal/pathrs/root_pathrslite.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ import (
)

// OpenInRoot opens the given path inside the root with the provided flags. It
// is effectively shorthand for [securejoin.OpenInRoot] followed by
// is effectively shorthand for [securejoin.OpenatInRoot] followed by
// [securejoin.Reopen].
func OpenInRoot(root, subpath string, flags int) (*os.File, error) {
func OpenInRoot(root *os.File, subpath string, flags int) (*os.File, error) {
handle, err := retryEAGAIN(func() (*os.File, error) {
return pathrs.OpenInRoot(root, subpath)
return pathrs.OpenatInRoot(root, subpath)
})
if err != nil {
return nil, err
Expand All @@ -47,7 +47,7 @@ func OpenInRoot(root, subpath string, flags int) (*os.File, error) {
// open(O_CREAT|O_NOFOLLOW) semantics. If you want the creation to use O_EXCL,
// include it in the passed flags. The fileMode argument uses unix.* mode bits,
// *not* os.FileMode.
func CreateInRoot(root, subpath string, flags int, fileMode uint32) (*os.File, error) {
func CreateInRoot(root *os.File, subpath string, flags int, fileMode uint32) (*os.File, error) {
dirFd, filename, err := MkdirAllParentInRoot(root, subpath, 0o755)
if err != nil {
return nil, err
Expand All @@ -63,5 +63,5 @@ func CreateInRoot(root, subpath string, flags int, fileMode uint32) (*os.File, e
if err != nil {
return nil, err
}
return os.NewFile(uintptr(fd), root+"/"+subpath), nil
return os.NewFile(uintptr(fd), root.Name()+"/"+subpath), nil
}
10 changes: 8 additions & 2 deletions libcontainer/criu_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,10 +540,16 @@ func isOnTmpfs(path string, mounts []*configs.Mount) bool {
// This function also creates missing mountpoints as long as they
// are not on top of a tmpfs, as CRIU will restore tmpfs content anyway.
func (c *Container) prepareCriuRestoreMounts(mounts []*configs.Mount) error {
rootFd, err := os.OpenFile(c.config.Rootfs, unix.O_DIRECTORY|unix.O_CLOEXEC|unix.O_PATH, 0)
if err != nil {
return fmt.Errorf("open rootfs handle: %w", err)
}
defer rootFd.Close()

umounts := []string{}
defer func() {
for _, u := range umounts {
mntFile, err := pathrs.OpenInRoot(c.config.Rootfs, u, unix.O_PATH)
mntFile, err := pathrs.OpenInRoot(rootFd, u, unix.O_PATH)
if err != nil {
logrus.Warnf("Error during cleanup unmounting %s: open handle: %v", u, err)
continue
Expand Down Expand Up @@ -577,7 +583,7 @@ func (c *Container) prepareCriuRestoreMounts(mounts []*configs.Mount) error {
continue
}
me := mountEntry{Mount: m}
if err := me.createOpenMountpoint(c.config.Rootfs); err != nil {
if err := me.createOpenMountpoint(rootFd); err != nil {
return fmt.Errorf("create criu restore mountpoint for %s mount: %w", me.Destination, err)
}
if me.dstFile != nil {
Expand Down
Loading
Loading