diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 6a7bd86ba..808c3f871 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,12 +1328,20 @@ 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 ). // 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) @@ -1394,13 +1402,18 @@ 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 // 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)