Repository: opencontainers/runc
File: libcontainer/rootfs_linux.go (Go)

Code before:
		return fmt.Errorf("error jailing process inside rootfs: %w", err)
	}

	if err := adjustRootMountPropagation(uintptr(config.RootPropagation)); err != nil {
		return err
	}

	if setupDev {
		if err := reOpenDevNull(); err != nil {
			return fmt.Errorf("error reopening /dev/null inside container: %w", err)
		}
	}

	if cwd := iConfig.Cwd; cwd != "" {
		// Note that spec.Process.Cwd can contain unclean value like  "../../../../foo/bar...".
		// However, we are safe to call MkDirAll directly because we are in the jail here.
		if err := os.MkdirAll(cwd, 0o755); err != nil {
			return err
		}
	}

	return nil
}

// adjustRootMountPropagation applies mount propagation flags such as MS_SHARED or MS_UNBINDABLE
// to the root mount after the pivot_root or chroot has taken place.
func adjustRootMountPropagation(rootPropagation uintptr) error {
	var flag uintptr

	switch {
	case rootPropagation&unix.MS_SHARED != 0:
		flag = unix.MS_SHARED
	case rootPropagation&unix.MS_UNBINDABLE != 0:
		flag = unix.MS_UNBINDABLE
	default:
		return nil
	}

	if err := unix.Mount("", "/", "", flag, ""); err != nil {
		return fmt.Errorf("failed to set rootfs propagation: %w", err)
	}

	return nil
}

// finalizeRootfs sets anything to ro if necessary. You must call
// prepareRootfs first.
func finalizeRootfs(config *configs.Config) (err error) {
	// All tmpfs mounts and /dev were previously mounted as rw
	// by mountPropagate. Remount them read-only as requested.
	for _, m := range config.Mounts {

Review comment (suggestion):
Needs a comment to explain why this cannot be done in `prepareRoot`:
https://github.com/opencontainers/runc/blob/3d8a278bdd7d76915878ef6bdd0e5f031c589f30/libcontainer/rootfs_linux.go#L1012-L1027

Code after:
		return fmt.Errorf("error jailing process inside rootfs: %w", err)
	}

	// Apply root mount propagation flags.
	// This must be done after pivot_root/chroot because the mount propagation flag is applied
	// to the current root ("/"), and not to the old rootfs before it becomes "/". Applying the
	// flag in prepareRoot would affect the host mount namespace if the container's
	// root mount is shared.
	// MS_PRIVATE is skipped as rootfsParentMountPrivate() is already called.
	if config.RootPropagation != 0 && config.RootPropagation&unix.MS_PRIVATE == 0 {
		if err := mount("", "/", "", uintptr(config.RootPropagation), ""); err != nil {
			return fmt.Errorf("unable to apply root propagation flags: %w", err)
		}
	}

	if setupDev {
		if err := reOpenDevNull(); err != nil {
			return fmt.Errorf("error reopening /dev/null inside container: %w", err)
		}
	}

	if cwd := iConfig.Cwd; cwd != "" {
		// Note that spec.Process.Cwd can contain unclean value like  "../../../../foo/bar...".
		// However, we are safe to call MkDirAll directly because we are in the jail here.
		if err := os.MkdirAll(cwd, 0o755); err != nil {
			return err
		}
	}

	return nil
}

// finalizeRootfs sets anything to ro if necessary. You must call
// prepareRootfs first.
func finalizeRootfs(config *configs.Config) (err error) {
	// All tmpfs mounts and /dev were previously mounted as rw
	// by mountPropagate. Remount them read-only as requested.
	for _, m := range config.Mounts {
		if m.Flags&unix.MS_RDONLY != unix.MS_RDONLY {
			continue
		}
		if m.Device == "tmpfs" || utils.CleanPath(m.Destination) == "/dev" {
			if err := remountReadonly(m); err != nil {
				return err
			}
		}
	}

	// set rootfs ( / ) as readonly
	if config.Readonlyfs {
		if err := setReadonly(); err != nil {