Skip to content

Commit 3bfad05

Browse files
committed
libct: switch final WithProcfd users to WithProcfdFile
This probably should've been done as part of commit d40b343 ("rootfs: switch to fd-based handling of mountpoint targets") but it seems I missed them when doing the rest of the conversions. This also lets us remove utils.WithProcfd entirely, as well as pathrs.MkdirAllInRoot. Signed-off-by: Aleksa Sarai <[email protected]>
1 parent 9f3b057 commit 3bfad05

File tree

4 files changed

+22
-58
lines changed

4 files changed

+22
-58
lines changed

internal/pathrs/mkdirall_pathrslite.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,3 @@ func MkdirAllInRootOpen(root, unsafePath string, mode os.FileMode) (*os.File, er
8787
return pathrs.MkdirAllHandle(rootDir, unsafePath, mode)
8888
})
8989
}
90-
91-
// MkdirAllInRoot is a wrapper around MkdirAllInRootOpen which closes the
92-
// returned handle, for callers that don't need to use it.
93-
func MkdirAllInRoot(root, unsafePath string, mode os.FileMode) error {
94-
f, err := MkdirAllInRootOpen(root, unsafePath, mode)
95-
if err == nil {
96-
_ = f.Close()
97-
}
98-
return err
99-
}

libcontainer/criu_linux.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"google.golang.org/protobuf/proto"
2626

2727
"github.com/opencontainers/cgroups"
28+
"github.com/opencontainers/runc/internal/pathrs"
2829
"github.com/opencontainers/runc/libcontainer/configs"
2930
"github.com/opencontainers/runc/libcontainer/utils"
3031
)
@@ -555,16 +556,22 @@ func (c *Container) prepareCriuRestoreMounts(mounts []*configs.Mount) error {
555556
umounts := []string{}
556557
defer func() {
557558
for _, u := range umounts {
558-
_ = utils.WithProcfd(c.config.Rootfs, u, func(procfd string) error {
559-
if e := unix.Unmount(procfd, unix.MNT_DETACH); e != nil {
560-
if e != unix.EINVAL {
559+
mntFile, err := pathrs.OpenInRoot(c.config.Rootfs, u, unix.O_PATH)
560+
if err != nil {
561+
logrus.Warnf("Error during cleanup unmounting %s: open handle: %v", u, err)
562+
continue
563+
}
564+
_ = utils.WithProcfdFile(mntFile, func(procfd string) error {
565+
if err := unix.Unmount(procfd, unix.MNT_DETACH); err != nil {
566+
if err != unix.EINVAL {
561567
// Ignore EINVAL as it means 'target is not a mount point.'
562568
// It probably has already been unmounted.
563-
logrus.Warnf("Error during cleanup unmounting of %s (%s): %v", procfd, u, e)
569+
logrus.Warnf("Error during cleanup unmounting of %s (%s): %v", procfd, u, err)
564570
}
565571
}
566572
return nil
567573
})
574+
_ = mntFile.Close()
568575
}
569576
}()
570577
// Now go through all mounts and create the required mountpoints.

libcontainer/rootfs_linux.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -329,12 +329,15 @@ func mountCgroupV1(m mountEntry, c *mountConfig) error {
329329
// We just created the tmpfs, and so we can just use filepath.Join
330330
// here (not to mention we want to make sure we create the path
331331
// inside the tmpfs, so we don't want to resolve symlinks).
332+
// TODO: Why not just use b.Destination (c.root is the root here)?
332333
subsystemPath := filepath.Join(c.root, b.Destination)
333334
subsystemName := filepath.Base(b.Destination)
334-
if err := pathrs.MkdirAllInRoot(c.root, subsystemPath, 0o755); err != nil {
335+
subsystemDir, err := pathrs.MkdirAllInRootOpen(c.root, subsystemPath, 0o755)
336+
if err != nil {
335337
return err
336338
}
337-
if err := utils.WithProcfd(c.root, b.Destination, func(dstFd string) error {
339+
defer subsystemDir.Close()
340+
if err := utils.WithProcfdFile(subsystemDir, func(dstFd string) error {
338341
flags := defaultMountFlags
339342
if m.Flags&unix.MS_RDONLY != 0 {
340343
flags = flags | unix.MS_RDONLY
@@ -1454,9 +1457,7 @@ func (m *mountEntry) mountPropagate(rootfs string, mountLabel string) error {
14541457
_ = m.dstFile.Close()
14551458
m.dstFile = newDstFile
14561459

1457-
// We have to apply mount propagation flags in a separate WithProcfd() call
1458-
// because the previous call invalidates the passed procfd -- the mount
1459-
// target needs to be re-opened.
1460+
// Apply the propagation flags on the new mount.
14601461
if err := utils.WithProcfdFile(m.dstFile, func(dstFd string) error {
14611462
for _, pflag := range m.PropagationFlags {
14621463
if err := mountViaFds("", nil, m.Destination, dstFd, "", uintptr(pflag), ""); err != nil {

libcontainer/utils/utils_unix.go

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ import (
66
"fmt"
77
"math"
88
"os"
9-
"path/filepath"
109
"runtime"
1110
"strconv"
1211
"sync"
1312
_ "unsafe" // for go:linkname
1413

15-
securejoin "github.com/cyphar/filepath-securejoin"
1614
"github.com/sirupsen/logrus"
1715
"golang.org/x/sys/unix"
1816

@@ -146,45 +144,13 @@ func NewSockPair(name string) (parent, child *os.File, err error) {
146144
return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil
147145
}
148146

149-
// WithProcfd runs the passed closure with a procfd path (/proc/self/fd/...)
150-
// corresponding to the unsafePath resolved within the root. Before passing the
151-
// fd, this path is verified to have been inside the root -- so operating on it
152-
// through the passed fdpath should be safe. Do not access this path through
153-
// the original path strings, and do not attempt to use the pathname outside of
154-
// the passed closure (the file handle will be freed once the closure returns).
155-
func WithProcfd(root, unsafePath string, fn func(procfd string) error) error {
156-
// Remove the root then forcefully resolve inside the root.
157-
unsafePath = pathrs.LexicallyStripRoot(root, unsafePath)
158-
fullPath, err := securejoin.SecureJoin(root, unsafePath)
159-
if err != nil {
160-
return fmt.Errorf("resolving path inside rootfs failed: %w", err)
161-
}
162-
163-
procSelfFd, closer := ProcThreadSelf("fd/")
164-
defer closer()
165-
166-
// Open the target path.
167-
fh, err := os.OpenFile(fullPath, unix.O_PATH|unix.O_CLOEXEC, 0)
168-
if err != nil {
169-
return fmt.Errorf("open o_path procfd: %w", err)
170-
}
171-
defer fh.Close()
172-
173-
procfd := filepath.Join(procSelfFd, strconv.Itoa(int(fh.Fd())))
174-
// Double-check the path is the one we expected.
175-
if realpath, err := os.Readlink(procfd); err != nil {
176-
return fmt.Errorf("procfd verification failed: %w", err)
177-
} else if realpath != fullPath {
178-
return fmt.Errorf("possibly malicious path detected -- refusing to operate on %s", realpath)
179-
}
180-
181-
return fn(procfd)
182-
}
183-
184-
// WithProcfdFile is a very minimal wrapper around [ProcThreadSelfFd], intended
185-
// to make migrating from [WithProcfd] and [WithProcfdPath] usage easier. The
147+
// WithProcfdFile is a very minimal wrapper around [ProcThreadSelfFd]. The
186148
// caller is responsible for making sure that the provided file handle is
187149
// actually safe to operate on.
150+
//
151+
// TODO: Migrate the mount logic towards a more move_mount(2)-friendly design
152+
// where this is kind of /proc/self/... tomfoolery is only done in a fallback
153+
// path for old kernels.
188154
func WithProcfdFile(file *os.File, fn func(procfd string) error) error {
189155
fdpath, closer := ProcThreadSelfFd(file.Fd())
190156
defer closer()

0 commit comments

Comments
 (0)