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

libcontainer: Allow passing mount propagation flags #264

Merged
merged 1 commit into from
Sep 17, 2015
Merged
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
48 changes: 48 additions & 0 deletions libcontainer/configs/mount.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package configs

import (
"path/filepath"
"strings"
"syscall"

"github.com/opencontainers/runc/libcontainer/label"
)

type Mount struct {
// Source path for the mount.
Source string `json:"source"`
Expand All @@ -13,6 +21,9 @@ type Mount struct {
// Mount flags.
Flags int `json:"flags"`

// Propagation Flags
PropagationFlags []int `json:"propagation_flags"`

// Mount data applied to the mount.
Data string `json:"data"`

Expand All @@ -25,3 +36,40 @@ type Mount struct {
// Optional Command to be run after Source is mounted.
PostmountCmds []Command `json:"postmount_cmds"`
}

func (m *Mount) Remount(rootfs string) error {
var (
dest = m.Destination
)
if !strings.HasPrefix(dest, rootfs) {
dest = filepath.Join(rootfs, dest)
}

if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags|syscall.MS_REMOUNT), ""); err != nil {
return err
}
return nil
}

// Do the mount operation followed by additional mounts required to take care
// of propagation flags.
func (m *Mount) MountPropagate(rootfs string, mountLabel string) error {
var (
dest = m.Destination
data = label.FormatMountLabel(m.Data, mountLabel)
)
if !strings.HasPrefix(dest, rootfs) {
dest = filepath.Join(rootfs, dest)
}

if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data); err != nil {
return err
}

for _, pflag := range m.PropagationFlags {
if err := syscall.Mount("", dest, "", uintptr(pflag), ""); err != nil {
return err
}
}
return nil
}
47 changes: 23 additions & 24 deletions libcontainer/rootfs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ func mountCmd(cmd configs.Command) error {
func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
var (
dest = m.Destination
data = label.FormatMountLabel(m.Data, mountLabel)
)
if !strings.HasPrefix(dest, rootfs) {
dest = filepath.Join(rootfs, dest)
Expand All @@ -107,12 +106,12 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
if err := os.MkdirAll(dest, 0755); err != nil {
return err
}
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "")
return m.MountPropagate(rootfs, mountLabel)
case "mqueue":
if err := os.MkdirAll(dest, 0755); err != nil {
return err
}
if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), ""); err != nil {
if err := m.MountPropagate(rootfs, mountLabel); err != nil {
return err
}
return label.SetFileLabel(dest, mountLabel)
Expand All @@ -123,7 +122,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
return err
}
}
if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data); err != nil {
if err := m.MountPropagate(rootfs, mountLabel); err != nil {
return err
}
if stat != nil {
Expand All @@ -136,12 +135,12 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
if err := os.MkdirAll(dest, 0755); err != nil {
return err
}
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data)
return m.MountPropagate(rootfs, mountLabel)
case "securityfs":
if err := os.MkdirAll(dest, 0755); err != nil {
return err
}
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data)
return m.MountPropagate(rootfs, mountLabel)
case "bind":
stat, err := os.Stat(m.Source)
if err != nil {
Expand All @@ -162,11 +161,11 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
if err := createIfNotExists(dest, stat.IsDir()); err != nil {
return err
}
if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data); err != nil {
if err := m.MountPropagate(rootfs, mountLabel); err != nil {
return err
}
// bind mount won't change mount options, we need remount to make mount options effective.
if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags|syscall.MS_REMOUNT), ""); err != nil {
if err := m.Remount(rootfs); err != nil {
return err
}
if m.Relabel != "" {
Expand All @@ -178,11 +177,6 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
return err
}
}
if m.Flags&syscall.MS_PRIVATE != 0 {
if err := syscall.Mount("", dest, "none", uintptr(syscall.MS_PRIVATE), ""); err != nil {
return err
}
}
case "cgroup":
binds, err := getCgroupMounts(m)
if err != nil {
Expand All @@ -196,11 +190,12 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
}
}
tmpfs := &configs.Mount{
Source: "tmpfs",
Device: "tmpfs",
Destination: m.Destination,
Flags: defaultMountFlags,
Data: "mode=755",
Source: "tmpfs",
Device: "tmpfs",
Destination: m.Destination,
Flags: defaultMountFlags,
Data: "mode=755",
PropagationFlags: m.PropagationFlags,
}
if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
return err
Expand Down Expand Up @@ -235,8 +230,11 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
}
if m.Flags&syscall.MS_RDONLY != 0 {
// remount cgroup root as readonly
rootfsCgroup := filepath.Join(rootfs, m.Destination)
if err := syscall.Mount("", rootfsCgroup, "", defaultMountFlags|syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil {
mcgrouproot := &configs.Mount{
Destination: m.Destination,
Flags: defaultMountFlags | syscall.MS_RDONLY,
}
if err := mcgrouproot.Remount(rootfs); err != nil {
return err
}
}
Expand Down Expand Up @@ -269,10 +267,11 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) {
return nil, err
}
binds = append(binds, &configs.Mount{
Device: "bind",
Source: filepath.Join(mm.Mountpoint, relDir),
Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")),
Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags,
Device: "bind",
Source: filepath.Join(mm.Mountpoint, relDir),
Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")),
Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags,
PropagationFlags: m.PropagationFlags,
})
}

Expand Down
49 changes: 29 additions & 20 deletions spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,19 +387,20 @@ func createLibcontainerConfig(cgroupName string, spec *specs.LinuxSpec, rspec *s
}

func createLibcontainerMount(cwd, dest string, m specs.Mount) *configs.Mount {
flags, data := parseMountOptions(m.Options)
flags, pgflags, data := parseMountOptions(m.Options)
source := m.Source
if m.Type == "bind" {
if !filepath.IsAbs(source) {
source = filepath.Join(cwd, m.Source)
}
}
return &configs.Mount{
Device: m.Type,
Source: source,
Destination: dest,
Data: data,
Flags: flags,
Device: m.Type,
Source: source,
Destination: dest,
Data: data,
Flags: flags,
PropagationFlags: pgflags,
}
}

Expand Down Expand Up @@ -519,12 +520,13 @@ func createLibContainerRlimit(rlimit specs.Rlimit) (configs.Rlimit, error) {
}, nil
}

// parseMountOptions parses the string and returns the flags and any mount data that
// it contains.
func parseMountOptions(options []string) (int, string) {
// parseMountOptions parses the string and returns the flags, propagation
// flags and any mount data that it contains.
func parseMountOptions(options []string) (int, []int, string) {
var (
flag int
data []string
flag int
pgflag []int
data []string
)
flags := map[string]struct {
clear bool
Expand All @@ -547,22 +549,27 @@ func parseMountOptions(options []string) (int, string) {
"norelatime": {true, syscall.MS_RELATIME},
"nostrictatime": {true, syscall.MS_STRICTATIME},
"nosuid": {false, syscall.MS_NOSUID},
"private": {false, syscall.MS_PRIVATE},
"rbind": {false, syscall.MS_BIND | syscall.MS_REC},
"relatime": {false, syscall.MS_RELATIME},
"remount": {false, syscall.MS_REMOUNT},
"ro": {false, syscall.MS_RDONLY},
"rprivate": {false, syscall.MS_PRIVATE | syscall.MS_REC},
"rshared": {false, syscall.MS_SHARED | syscall.MS_REC},
"rslave": {false, syscall.MS_SLAVE | syscall.MS_REC},
"runbindable": {false, syscall.MS_UNBINDABLE | syscall.MS_REC},
"rw": {true, syscall.MS_RDONLY},
"shared": {false, syscall.MS_SHARED},
"slave": {false, syscall.MS_SLAVE},
"strictatime": {false, syscall.MS_STRICTATIME},
"suid": {true, syscall.MS_NOSUID},
"sync": {false, syscall.MS_SYNCHRONOUS},
"unbindable": {false, syscall.MS_UNBINDABLE},
}
propagationFlags := map[string]struct {
clear bool
flag int
}{
"private": {false, syscall.MS_PRIVATE},
"shared": {false, syscall.MS_SHARED},
"slave": {false, syscall.MS_SLAVE},
"unbindable": {false, syscall.MS_UNBINDABLE},
"rprivate": {false, syscall.MS_PRIVATE | syscall.MS_REC},
"rshared": {false, syscall.MS_SHARED | syscall.MS_REC},
"rslave": {false, syscall.MS_SLAVE | syscall.MS_REC},
"runbindable": {false, syscall.MS_UNBINDABLE | syscall.MS_REC},
}
for _, o := range options {
// If the option does not exist in the flags table or the flag
Expand All @@ -574,11 +581,13 @@ func parseMountOptions(options []string) (int, string) {
} else {
flag |= f.flag
}
} else if f, exists := propagationFlags[o]; exists && f.flag != 0 {
pgflag = append(pgflag, f.flag)
} else {
data = append(data, o)
}
}
return flag, strings.Join(data, ",")
return flag, pgflag, strings.Join(data, ",")
}

func setupSeccomp(config *specs.Seccomp) (*configs.Seccomp, error) {
Expand Down