From e7e2f00248a2700827f1fbc54e8767a53ad11117 Mon Sep 17 00:00:00 2001 From: lifubang Date: Sat, 16 May 2026 04:12:44 +0000 Subject: [PATCH 1/2] libct: optimize maskPaths for single-directory case This is a follow-up to #5275. That change reused a single tmpfs mount to mask multiple directories, which is efficient when masking more than one path. However, it introduced unnecessary overhead when only one directory is masked. This commit restores the original behavior for the single-path case while preserving shared tmpfs logic for multiple paths. Signed-off-by: lifubang --- libcontainer/rootfs_linux.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 6a7bd86ba..a28adb983 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -419,7 +419,7 @@ func mountCgroupV2(m mountEntry, c *mountConfig) error { // Mask `/sys/fs/cgroup` to ensure it is read-only, even when `/sys` is mounted // with `rbind,ro` (`runc spec --rootless` produces `rbind,ro` for `/sys`). err = utils.WithProcfdFile(m.dstFile, func(procfd string) error { - return maskPaths(c.root, []string{procfd}, c.label) + return maskDir(procfd, c.label) }) } return err @@ -1328,6 +1328,11 @@ func verifyDevNull(f *os.File) error { }) } +// maskDir mounts a read-only tmpfs on top of the specified path. +func maskDir(path, mountLabel string) error { + return mount("tmpfs", path, "tmpfs", unix.MS_RDONLY, label.FormatMountLabel("nr_blocks=1,nr_inodes=1", mountLabel)) +} + // maskPaths masks the top of the specified paths inside a container to avoid // security issues from processes reading information from non-namespace aware // mounts ( proc/kcore ). @@ -1394,7 +1399,7 @@ func maskPaths(rootFd *os.File, paths []string, mountLabel string) error { } } if bindFailed || sharedMaskSrc == nil { - err = mount("tmpfs", path, "tmpfs", unix.MS_RDONLY, label.FormatMountLabel("nr_blocks=1,nr_inodes=1", mountLabel)) + err = maskDir(path, mountLabel) if err == nil && !bindFailed && sharedMaskSrc == nil { // Establish this mount as the reusable shared source. reopenAfterMount // resolves the underlying inode via procfs and re-opens it through From b88635e57ec51c83a4b3d2ef281e3cfb692e30ca Mon Sep 17 00:00:00 2001 From: lifubang Date: Sat, 16 May 2026 04:40:37 +0000 Subject: [PATCH 2/2] libct: close rootFd ASAP in maskPaths Close the root file descriptor immediately after use in maskPaths to reduce the window during which an attacker could potentially exploit an open fd to access or manipulate the root filesystem. This follows the principle of least privilege and mitigates risks in compromised or malicious container scenarios. Co-authored-by: Kir Kolyshkin Signed-off-by: lifubang --- libcontainer/rootfs_linux.go | 10 +++++++++- libcontainer/standard_init_linux.go | 13 +++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index a28adb983..808c3f871 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -1338,7 +1338,10 @@ func maskDir(path, mountLabel string) error { // mounts ( proc/kcore ). // For files, maskPath bind mounts /dev/null over the top of the specified path. // For directories, maskPath mounts read-only tmpfs over the top of the specified path. -func maskPaths(rootFd *os.File, paths []string, mountLabel string) error { +func maskPaths(rootFs string, paths []string, mountLabel string) error { + if len(paths) == 0 { + return nil + } devNull, err := os.OpenFile("/dev/null", unix.O_PATH, 0) if err != nil { return fmt.Errorf("can't mask paths: %w", err) @@ -1405,7 +1408,12 @@ func maskPaths(rootFd *os.File, paths []string, mountLabel string) error { // resolves the underlying inode via procfs and re-opens it through // rootFd, so the resulting fd is anchored to the real path inside the // container rootfs even if path was a /proc/self/fd/N alias. + rootFd, err := os.OpenFile(rootFs, unix.O_DIRECTORY|unix.O_CLOEXEC|unix.O_PATH, 0) + if err != nil { + return fmt.Errorf("open rootfs handle for masked paths: %w", err) + } reopened, err := reopenAfterMount(rootFd, dstFh, unix.O_PATH|unix.O_CLOEXEC) + rootFd.Close() if err != nil { return fmt.Errorf("can't reopen shared directory mask: %w", err) } diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go index 116e659a8..933c1de34 100644 --- a/libcontainer/standard_init_linux.go +++ b/libcontainer/standard_init_linux.go @@ -142,17 +142,10 @@ func (l *linuxStandardInit) Init() error { } } - if len(l.config.Config.MaskPaths) > 0 { - rootFd, err := os.OpenFile("/", unix.O_DIRECTORY|unix.O_CLOEXEC|unix.O_PATH, 0) - if err != nil { - return fmt.Errorf("open rootfs handle for masked paths: %w", err) - } - err = maskPaths(rootFd, l.config.Config.MaskPaths, l.config.Config.MountLabel) - rootFd.Close() - if err != nil { - return err - } + if err := maskPaths("/", l.config.Config.MaskPaths, l.config.Config.MountLabel); err != nil { + return err } + pdeath, err := system.GetParentDeathSignal() if err != nil { return fmt.Errorf("can't get pdeath signal: %w", err)