mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-10 21:53:57 +08:00
9c444070ec
The source of the bind mount might not be accessible in a different user namespace because a component of the source path might not be traversed under the users and groups mapped inside the user namespace. This caused errors such as the following: # time="2020-06-22T13:48:26Z" level=error msg="container_linux.go:367: starting container process caused: process_linux.go:459: container init caused: rootfs_linux.go:58: mounting \"/tmp/busyboxtest/source-inaccessible/dir\" to rootfs at \"/tmp/inaccessible\" caused: stat /tmp/busyboxtest/source-inaccessible/dir: permission denied" To solve this problem, this patch performs the following: 1. in nsexec.c, it opens the source path in the host userns (so we have the right permissions to open it) but in the container mntns (so the kernel cross mntns mount check let us mount it later: https://github.com/torvalds/linux/blob/v5.8/fs/namespace.c#L2312). 2. in nsexec.c, it passes the file descriptors of the source to the child process with SCM_RIGHTS. 3. In runc-init in Golang, it finishes the mounts while inside the userns even without access to the some components of the source paths. Passing the fds with SCM_RIGHTS is necessary because once the child process is in the container mntns, it is already in the container userns so it cannot temporarily join the host mntns. This patch uses the existing mechanism with _LIBCONTAINER_* environment variables to pass the file descriptors from runc to runc init. This patch uses the existing mechanism with the Netlink-style bootstrap to pass information about the list of source mounts to nsexec.c. Rootless containers don't use this bind mount sources fdpassing mechanism because we can't setns() to the target mntns in a rootless container (we don't have the privileges when we are in the host userns). This patch takes care of using O_CLOEXEC on mount fds, and close them early. Fixes: #2484. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
package libcontainer
|
|
|
|
import (
|
|
"github.com/vishvananda/netlink/nl"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// list of known message types we want to send to bootstrap program
|
|
// The number is randomly chosen to not conflict with known netlink types
|
|
const (
|
|
InitMsg uint16 = 62000
|
|
CloneFlagsAttr uint16 = 27281
|
|
NsPathsAttr uint16 = 27282
|
|
UidmapAttr uint16 = 27283
|
|
GidmapAttr uint16 = 27284
|
|
SetgroupAttr uint16 = 27285
|
|
OomScoreAdjAttr uint16 = 27286
|
|
RootlessEUIDAttr uint16 = 27287
|
|
UidmapPathAttr uint16 = 27288
|
|
GidmapPathAttr uint16 = 27289
|
|
MountSourcesAttr uint16 = 27290
|
|
)
|
|
|
|
type Int32msg struct {
|
|
Type uint16
|
|
Value uint32
|
|
}
|
|
|
|
// Serialize serializes the message.
|
|
// Int32msg has the following representation
|
|
// | nlattr len | nlattr type |
|
|
// | uint32 value |
|
|
func (msg *Int32msg) Serialize() []byte {
|
|
buf := make([]byte, msg.Len())
|
|
native := nl.NativeEndian()
|
|
native.PutUint16(buf[0:2], uint16(msg.Len()))
|
|
native.PutUint16(buf[2:4], msg.Type)
|
|
native.PutUint32(buf[4:8], msg.Value)
|
|
return buf
|
|
}
|
|
|
|
func (msg *Int32msg) Len() int {
|
|
return unix.NLA_HDRLEN + 4
|
|
}
|
|
|
|
// Bytemsg has the following representation
|
|
// | nlattr len | nlattr type |
|
|
// | value | pad |
|
|
type Bytemsg struct {
|
|
Type uint16
|
|
Value []byte
|
|
}
|
|
|
|
func (msg *Bytemsg) Serialize() []byte {
|
|
l := msg.Len()
|
|
buf := make([]byte, (l+unix.NLA_ALIGNTO-1) & ^(unix.NLA_ALIGNTO-1))
|
|
native := nl.NativeEndian()
|
|
native.PutUint16(buf[0:2], uint16(l))
|
|
native.PutUint16(buf[2:4], msg.Type)
|
|
copy(buf[4:], msg.Value)
|
|
return buf
|
|
}
|
|
|
|
func (msg *Bytemsg) Len() int {
|
|
return unix.NLA_HDRLEN + len(msg.Value) + 1 // null-terminated
|
|
}
|
|
|
|
type Boolmsg struct {
|
|
Type uint16
|
|
Value bool
|
|
}
|
|
|
|
func (msg *Boolmsg) Serialize() []byte {
|
|
buf := make([]byte, msg.Len())
|
|
native := nl.NativeEndian()
|
|
native.PutUint16(buf[0:2], uint16(msg.Len()))
|
|
native.PutUint16(buf[2:4], msg.Type)
|
|
if msg.Value {
|
|
native.PutUint32(buf[4:8], uint32(1))
|
|
} else {
|
|
native.PutUint32(buf[4:8], uint32(0))
|
|
}
|
|
return buf
|
|
}
|
|
|
|
func (msg *Boolmsg) Len() int {
|
|
return unix.NLA_HDRLEN + 4 // alignment
|
|
}
|