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

Code before:
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/devices"
	"github.com/opencontainers/runc/libcontainer/userns"
	"github.com/opencontainers/runc/libcontainer/utils"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/opencontainers/selinux/go-selinux/label"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV

// mountConfig contains mount data not specific to a mount point.
type mountConfig struct {
	root            string
	label           string
	cgroup2Path     string
	rootlessCgroups bool
	cgroupns        bool
}

// mountEntry contains mount data specific to a mount point.
type mountEntry struct {
	*configs.Mount
	srcFD   int
	idmapFD int
}

func (m *mountEntry) src() string {
	if m.srcFD != -1 {
		return "/proc/self/fd/" + strconv.Itoa(m.srcFD)
	}
	return m.Source
}

// needsSetupDev returns true if /dev needs to be set up.
func needsSetupDev(config *configs.Config) bool {
	for _, m := range config.Mounts {
		if m.Device == "bind" && utils.CleanPath(m.Destination) == "/dev" {
			return false
		}
	}
	return true
}

// prepareRootfs sets up the devices, mount points, and filesystems for use
// inside a new mount namespace. It doesn't set anything as ro. You must call
// finalizeRootfs after this function to finish setting up the rootfs.
func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig, mountFds mountFds) (err error) {
	config := iConfig.Config
	if err := prepareRoot(config); err != nil {

Review comment (suggestion):
```suggestion
	fd   int
```
I think now that both are type int, we can switch this to just have one `fd`. 

srcFD and idmapFD are mutually exclusive, and we already know based on the mount properties if the fd at hand is a srcFD or an idmapFD.

[Here][link] we could just read "fd" and treat it as an idmapFD. Otherwise, we treat it as a srcFD.

I like the separation of fds, to avoid mistakes from happening, but I think having just one fd and using it appropriately (as all the fds there are mutually exclusive: only one of those fields can be set to something != -1).

What do you think?

I would do that change on top of these commits, though. So it is simpler to review and we can come back to the state the PR is currently at by just removing that commit.

[link]: https://github.com/opencontainers/runc/pull/3939/commits/2e9093faccd36b782788fad77e832179a0a5f692#diff-e0932af06cb46065b2ef5fc89bc2bd9b880c9578e01b89ef4ecaeffb78a8bef0R484-R487

Code after:
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/devices"
	"github.com/opencontainers/runc/libcontainer/userns"
	"github.com/opencontainers/runc/libcontainer/utils"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/opencontainers/selinux/go-selinux/label"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV

// mountConfig contains mount data not specific to a mount point.
type mountConfig struct {
	root            string
	label           string
	cgroup2Path     string
	rootlessCgroups bool
	cgroupns        bool
}

// mountEntry contains mount data specific to a mount point.
type mountEntry struct {
	*configs.Mount
	srcFD *int
}

func (m *mountEntry) src() string {
	if m.srcFD != nil {
		return "/proc/self/fd/" + strconv.Itoa(*m.srcFD)
	}
	return m.Source
}

// needsSetupDev returns true if /dev needs to be set up.
func needsSetupDev(config *configs.Config) bool {
	for _, m := range config.Mounts {
		if m.Device == "bind" && utils.CleanPath(m.Destination) == "/dev" {
			return false
		}
	}
	return true
}

// prepareRootfs sets up the devices, mount points, and filesystems for use
// inside a new mount namespace. It doesn't set anything as ro. You must call
// finalizeRootfs after this function to finish setting up the rootfs.
func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig, mountFds mountFds) (err error) {
	config := iConfig.Config
	if err := prepareRoot(config); err != nil {
		return fmt.Errorf("error preparing rootfs: %w", err)