Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mount: add enhanced mount functionality to support run container in userns with host network #3613

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libcontainer/configs/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ type Mount struct {
func (m *Mount) IsBind() bool {
return m.Flags&unix.MS_BIND != 0
}

func (m *Mount) IsMove() bool {
return m.Flags&unix.MS_MOVE != 0
}
76 changes: 69 additions & 7 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ func (c *Container) shouldSendMountSources() bool {

// We need to send sources if there are bind-mounts.
for _, m := range c.config.Mounts {
if m.IsBind() {
if m.IsBind() || m.IsMove() {
return true
}
}
Expand All @@ -536,18 +536,46 @@ func (c *Container) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, l
nsMaps[ns.Type] = ns.Path
}
}

nsList := make(map[configs.NamespaceType]string)
for _, ns := range c.config.Namespaces {
nsList[ns.Type] = ns.Path
}

_, sharePidns := nsMaps[configs.NEWPID]
data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps, initStandard)
if err != nil {
return nil, err
userNsMountFds := [3]int{-1, -1, -1}

// Enable open_tree()/move_mount() for special filesystems to support cross user namespace mounting.
if _, ok := nsList[configs.NEWUSER]; ok {
for idx, m := range c.config.Mounts {
if m.Device == "proc" && m.Source == "proc" && m.Destination == "/proc" &&
m.Flags == unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_NOSUID {
// procfs depends on Pid namespace
if _, exist := nsList[configs.NEWPID]; exist {
}
Comment on lines +554 to +555
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is some code missing here?

} else if m.Device == "sysfs" && m.Source == "sysfs" && m.Destination == "/sys" &&
m.Flags == unix.MS_NODEV|unix.MS_NOSUID|unix.MS_NOEXEC|unix.MS_RDONLY {
// sysfs depends on Net namespace
// meaning exclude runc unshare new netns
if path, exist := nsList[configs.NEWNET]; !exist || path != "" {
c.config.Mounts[idx].Flags |= unix.MS_MOVE
}
} else if m.Device == "mqueue" && m.Source == "mqueue" && m.Destination == "/dev/mqueue" &&
m.Flags == unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_NOSUID {
// /mqueue depends on IPC namespace
if _, exist := nsList[configs.NEWIPC]; exist {
c.config.Mounts[idx].Flags |= unix.MS_MOVE
}
}
}
}

if c.shouldSendMountSources() {
// Elements on this slice will be paired with mounts (see StartInitialization() and
// prepareRootfs()). This slice MUST have the same size as c.config.Mounts.
mountFds := make([]int, len(c.config.Mounts))
for i, m := range c.config.Mounts {
if !m.IsBind() {
if !m.IsBind() && !m.IsMove() {
// Non bind-mounts do not use an fd.
mountFds[i] = -1
continue
Expand All @@ -559,6 +587,17 @@ func (c *Container) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, l
// lifecycle of that fd is already taken care of.
cmd.ExtraFiles = append(cmd.ExtraFiles, messageSockPair.child)
mountFds[i] = stdioFdCount + len(cmd.ExtraFiles) - 1

// MS_MOVE flag is set for cross user namespace mounting
if m.IsMove() {
if m.Device == "proc" {
userNsMountFds[0] = mountFds[i]
} else if m.Device == "sysfs" {
userNsMountFds[1] = mountFds[i]
} else if m.Device == "mqueue" {
userNsMountFds[2] = mountFds[i]
}
}
}

mountFdsJson, err := json.Marshal(mountFds)
Expand All @@ -571,6 +610,11 @@ func (c *Container) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, l
)
}

data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps, initStandard, &userNsMountFds)
if err != nil {
return nil, err
}

init := &initProcess{
cmd: cmd,
messageSockPair: messageSockPair,
Expand All @@ -595,7 +639,7 @@ func (c *Container) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockPair,
}
// for setns process, we don't have to set cloneflags as the process namespaces
// will only be set via setns syscall
data, err := c.bootstrapData(0, state.NamespacePaths, initSetns)
data, err := c.bootstrapData(0, state.NamespacePaths, initSetns, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2119,7 +2163,8 @@ type netlinkError struct{ error }
// such as one that uses nsenter package to bootstrap the container's
// init process correctly, i.e. with correct namespaces, uid/gid
// mapping etc.
func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, it initType) (_ io.Reader, Err error) {
func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string,
it initType, userNsMountFd *[3]int) (_ io.Reader, Err error) {
// create the netlink message
r := nl.NewNetlinkRequest(int(InitMsg), 0)

Expand Down Expand Up @@ -2238,6 +2283,23 @@ func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Namespa
Type: MountSourcesAttr,
Value: mounts,
})

// File descriptors to support cross user namespace mounting
if userNsMountFd == nil {
return nil, fmt.Errorf("user mount fd array should not be null")
}
r.AddData(&Int32msg{
Type: MountFdProc,
Value: uint32(userNsMountFd[0]),
})
r.AddData(&Int32msg{
Type: MountFdSys,
Value: uint32(userNsMountFd[1]),
})
r.AddData(&Int32msg{
Type: MountFdMqueue,
Value: uint32(userNsMountFd[2]),
})
}

return bytes.NewReader(r.Serialize()), nil
Expand Down
3 changes: 3 additions & 0 deletions libcontainer/message_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ const (
UidmapPathAttr uint16 = 27288
GidmapPathAttr uint16 = 27289
MountSourcesAttr uint16 = 27290
MountFdProc uint16 = 27291
MountFdSys uint16 = 27292
MountFdMqueue uint16 = 27293
)

type Int32msg struct {
Expand Down
Loading