mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
commit
79e8ef28e4
26 changed files with 700 additions and 72 deletions
|
@ -87,7 +87,7 @@ RUN git config --global user.email 'docker-dummy@example.com'
|
|||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/dotcloud/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor
|
||||
ENV DOCKER_BUILDTAGS apparmor selinux
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
|
|
@ -189,7 +189,7 @@ func (graph *Graph) Register(jsonData []byte, layerData archive.ArchiveReader, i
|
|||
}
|
||||
|
||||
// Create root filesystem in the driver
|
||||
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
||||
if err := graph.driver.Create(img.ID, img.Parent, ""); err != nil {
|
||||
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
||||
}
|
||||
// Mount the root filesystem so we can apply the diff/layer
|
||||
|
|
|
@ -177,6 +177,13 @@ export DOCKER_BUILDTAGS='exclude_graphdriver_aufs'
|
|||
|
||||
NOTE: if you need to set more than one build tag, space separate them.
|
||||
|
||||
If you're building a binary that may need to be used on platforms that include
|
||||
SELinux, you will need to set `DOCKER_BUILDTAGS` as follows:
|
||||
|
||||
```bash
|
||||
export DOCKER_BUILDTAGS='selinux'
|
||||
```
|
||||
|
||||
### Static Daemon
|
||||
|
||||
If it is feasible within the constraints of your distribution, you should
|
||||
|
|
23
pkg/label/label.go
Normal file
23
pkg/label/label.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
// +build !selinux !linux
|
||||
|
||||
package label
|
||||
|
||||
func GenLabels(options string) (string, string, error) {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func FormatMountLabel(src string, MountLabel string) string {
|
||||
return src
|
||||
}
|
||||
|
||||
func SetProcessLabel(processLabel string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetFileLabel(path string, fileLabel string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPidCon(pid int) (string, error) {
|
||||
return "", nil
|
||||
}
|
69
pkg/label/label_selinux.go
Normal file
69
pkg/label/label_selinux.go
Normal file
|
@ -0,0 +1,69 @@
|
|||
// +build selinux,linux
|
||||
|
||||
package label
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/selinux"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GenLabels(options string) (string, string, error) {
|
||||
processLabel, mountLabel := selinux.GetLxcContexts()
|
||||
var err error
|
||||
if processLabel == "" { // SELinux is disabled
|
||||
return "", "", err
|
||||
}
|
||||
s := strings.Fields(options)
|
||||
l := len(s)
|
||||
if l > 0 {
|
||||
pcon := selinux.NewContext(processLabel)
|
||||
for i := 0; i < l; i++ {
|
||||
o := strings.Split(s[i], "=")
|
||||
pcon[o[0]] = o[1]
|
||||
}
|
||||
processLabel = pcon.Get()
|
||||
mountLabel, err = selinux.CopyLevel(processLabel, mountLabel)
|
||||
}
|
||||
return processLabel, mountLabel, err
|
||||
}
|
||||
|
||||
func FormatMountLabel(src string, MountLabel string) string {
|
||||
var mountLabel string
|
||||
if src != "" {
|
||||
mountLabel = src
|
||||
if MountLabel != "" {
|
||||
mountLabel = fmt.Sprintf("%s,context=\"%s\"", mountLabel, MountLabel)
|
||||
}
|
||||
} else {
|
||||
if MountLabel != "" {
|
||||
mountLabel = fmt.Sprintf("context=\"%s\"", MountLabel)
|
||||
}
|
||||
}
|
||||
return mountLabel
|
||||
}
|
||||
|
||||
func SetProcessLabel(processLabel string) error {
|
||||
if selinux.SelinuxEnabled() {
|
||||
return selinux.Setexeccon(processLabel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetProcessLabel() (string, error) {
|
||||
if selinux.SelinuxEnabled() {
|
||||
return selinux.Getexeccon()
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func SetFileLabel(path string, fileLabel string) error {
|
||||
if selinux.SelinuxEnabled() && fileLabel != "" {
|
||||
return selinux.Setfilecon(path, fileLabel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPidCon(pid int) (string, error) {
|
||||
return selinux.Getpidcon(pid)
|
||||
}
|
|
@ -4,6 +4,7 @@ package nsinit
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/system"
|
||||
"os"
|
||||
|
@ -32,7 +33,11 @@ func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []s
|
|||
closeFds()
|
||||
return -1, err
|
||||
}
|
||||
|
||||
processLabel, err := label.GetPidCon(nspid)
|
||||
if err != nil {
|
||||
closeFds()
|
||||
return -1, err
|
||||
}
|
||||
// foreach namespace fd, use setns to join an existing container's namespaces
|
||||
for _, fd := range fds {
|
||||
if fd > 0 {
|
||||
|
@ -80,6 +85,10 @@ dropAndExec:
|
|||
if err := finalizeNamespace(container); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
err = label.SetProcessLabel(processLabel)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if err := system.Execv(args[0], args[0:], container.Env); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package nsinit
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer/apparmor"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer/capabilities"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"github.com/dotcloud/docker/pkg/system"
|
||||
"github.com/dotcloud/docker/pkg/user"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
@ -57,7 +59,7 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol
|
|||
return fmt.Errorf("parent death signal %s", err)
|
||||
}
|
||||
ns.logger.Println("setup mount namespace")
|
||||
if err := setupNewMountNamespace(rootfs, container.Mounts, console, container.ReadonlyFs, container.NoPivotRoot); err != nil {
|
||||
if err := setupNewMountNamespace(rootfs, container.Mounts, console, container.ReadonlyFs, container.NoPivotRoot, container.Context["mount_label"]); err != nil {
|
||||
return fmt.Errorf("setup mount namespace %s", err)
|
||||
}
|
||||
if err := setupNetwork(container, context); err != nil {
|
||||
|
@ -76,6 +78,10 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol
|
|||
return err
|
||||
}
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
if err := label.SetProcessLabel(container.Context["process_label"]); err != nil {
|
||||
return fmt.Errorf("SetProcessLabel label %s", err)
|
||||
}
|
||||
ns.logger.Printf("execing %s\n", args[0])
|
||||
return system.Execv(args[0], args[0:], container.Env)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package nsinit
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/system"
|
||||
"io/ioutil"
|
||||
|
@ -20,7 +21,7 @@ const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NOD
|
|||
//
|
||||
// There is no need to unmount the new mounts because as soon as the mount namespace
|
||||
// is no longer in use, the mounts will be removed automatically
|
||||
func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, console string, readonly, noPivotRoot bool) error {
|
||||
func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, console string, readonly, noPivotRoot bool, mountLabel string) error {
|
||||
flag := syscall.MS_PRIVATE
|
||||
if noPivotRoot {
|
||||
flag = syscall.MS_SLAVE
|
||||
|
@ -36,7 +37,7 @@ func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, cons
|
|||
return fmt.Errorf("mounting %s as readonly %s", rootfs, err)
|
||||
}
|
||||
}
|
||||
if err := mountSystem(rootfs); err != nil {
|
||||
if err := mountSystem(rootfs, mountLabel); err != nil {
|
||||
return fmt.Errorf("mount system %s", err)
|
||||
}
|
||||
|
||||
|
@ -64,7 +65,7 @@ func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, cons
|
|||
if err := setupDev(rootfs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setupPtmx(rootfs, console); err != nil {
|
||||
if err := setupPtmx(rootfs, console, mountLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.Chdir(rootfs); err != nil {
|
||||
|
@ -196,7 +197,7 @@ func setupDev(rootfs string) error {
|
|||
}
|
||||
|
||||
// setupConsole ensures that the container has a proper /dev/console setup
|
||||
func setupConsole(rootfs, console string) error {
|
||||
func setupConsole(rootfs, console string, mountLabel string) error {
|
||||
oldMask := system.Umask(0000)
|
||||
defer system.Umask(oldMask)
|
||||
|
||||
|
@ -220,6 +221,9 @@ func setupConsole(rootfs, console string) error {
|
|||
if err := system.Mknod(dest, (st.Mode&^07777)|0600, int(st.Rdev)); err != nil {
|
||||
return fmt.Errorf("mknod %s %s", dest, err)
|
||||
}
|
||||
if err := label.SetFileLabel(console, mountLabel); err != nil {
|
||||
return fmt.Errorf("SetFileLabel Failed %s %s", dest, err)
|
||||
}
|
||||
if err := system.Mount(console, dest, "bind", syscall.MS_BIND, ""); err != nil {
|
||||
return fmt.Errorf("bind %s to %s %s", console, dest, err)
|
||||
}
|
||||
|
@ -228,7 +232,7 @@ func setupConsole(rootfs, console string) error {
|
|||
|
||||
// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
|
||||
// inside the mount namespace
|
||||
func mountSystem(rootfs string) error {
|
||||
func mountSystem(rootfs string, mountLabel string) error {
|
||||
for _, m := range []struct {
|
||||
source string
|
||||
path string
|
||||
|
@ -238,8 +242,8 @@ func mountSystem(rootfs string) error {
|
|||
}{
|
||||
{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
|
||||
{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaultMountFlags},
|
||||
{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: "mode=1777,size=65536k"},
|
||||
{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: "newinstance,ptmxmode=0666,mode=620,gid=5"},
|
||||
{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: label.FormatMountLabel("mode=1755,size=65536k", mountLabel)},
|
||||
{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: label.FormatMountLabel("newinstance,ptmxmode=0666,mode=620,gid=5", mountLabel)},
|
||||
} {
|
||||
if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("mkdirall %s %s", m.path, err)
|
||||
|
@ -253,7 +257,7 @@ func mountSystem(rootfs string) error {
|
|||
|
||||
// setupPtmx adds a symlink to pts/ptmx for /dev/ptmx and
|
||||
// finishes setting up /dev/console
|
||||
func setupPtmx(rootfs, console string) error {
|
||||
func setupPtmx(rootfs, console string, mountLabel string) error {
|
||||
ptmx := filepath.Join(rootfs, "dev/ptmx")
|
||||
if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
|
@ -262,7 +266,7 @@ func setupPtmx(rootfs, console string) error {
|
|||
return fmt.Errorf("symlink dev ptmx %s", err)
|
||||
}
|
||||
if console != "" {
|
||||
if err := setupConsole(rootfs, console); err != nil {
|
||||
if err := setupConsole(rootfs, console, mountLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
387
pkg/selinux/selinux.go
Normal file
387
pkg/selinux/selinux.go
Normal file
|
@ -0,0 +1,387 @@
|
|||
package selinux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/mount"
|
||||
"github.com/dotcloud/docker/pkg/system"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
Enforcing = 1
|
||||
Permissive = 0
|
||||
Disabled = -1
|
||||
selinuxDir = "/etc/selinux/"
|
||||
selinuxConfig = selinuxDir + "config"
|
||||
selinuxTypeTag = "SELINUXTYPE"
|
||||
selinuxTag = "SELINUX"
|
||||
selinuxPath = "/sys/fs/selinux"
|
||||
xattrNameSelinux = "security.selinux"
|
||||
stRdOnly = 0x01
|
||||
)
|
||||
|
||||
var (
|
||||
assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
|
||||
spaceRegex = regexp.MustCompile(`^([^=]+) (.*)$`)
|
||||
mcsList = make(map[string]bool)
|
||||
selinuxfs = "unknown"
|
||||
selinuxEnabled = false
|
||||
selinuxEnabledChecked = false
|
||||
)
|
||||
|
||||
type SELinuxContext map[string]string
|
||||
|
||||
func GetSelinuxMountPoint() string {
|
||||
if selinuxfs != "unknown" {
|
||||
return selinuxfs
|
||||
}
|
||||
selinuxfs = ""
|
||||
|
||||
mounts, err := mount.GetMounts()
|
||||
if err != nil {
|
||||
return selinuxfs
|
||||
}
|
||||
for _, mount := range mounts {
|
||||
if mount.Fstype == "selinuxfs" {
|
||||
selinuxfs = mount.Mountpoint
|
||||
break
|
||||
}
|
||||
}
|
||||
if selinuxfs != "" {
|
||||
var buf syscall.Statfs_t
|
||||
syscall.Statfs(selinuxfs, &buf)
|
||||
if (buf.Flags & stRdOnly) == 1 {
|
||||
selinuxfs = ""
|
||||
}
|
||||
}
|
||||
return selinuxfs
|
||||
}
|
||||
|
||||
func SelinuxEnabled() bool {
|
||||
if selinuxEnabledChecked {
|
||||
return selinuxEnabled
|
||||
}
|
||||
selinuxEnabledChecked = true
|
||||
if fs := GetSelinuxMountPoint(); fs != "" {
|
||||
if con, _ := Getcon(); con != "kernel" {
|
||||
selinuxEnabled = true
|
||||
}
|
||||
}
|
||||
return selinuxEnabled
|
||||
}
|
||||
|
||||
func ReadConfig(target string) (value string) {
|
||||
var (
|
||||
val, key string
|
||||
bufin *bufio.Reader
|
||||
)
|
||||
|
||||
in, err := os.Open(selinuxConfig)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
bufin = bufio.NewReader(in)
|
||||
|
||||
for done := false; !done; {
|
||||
var line string
|
||||
if line, err = bufin.ReadString('\n'); err != nil {
|
||||
if err != io.EOF {
|
||||
return ""
|
||||
}
|
||||
done = true
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
// Skip blank lines
|
||||
continue
|
||||
}
|
||||
if line[0] == ';' || line[0] == '#' {
|
||||
// Skip comments
|
||||
continue
|
||||
}
|
||||
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
|
||||
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
|
||||
if key == target {
|
||||
return strings.Trim(val, "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetSELinuxPolicyRoot() string {
|
||||
return selinuxDir + ReadConfig(selinuxTypeTag)
|
||||
}
|
||||
|
||||
func readCon(name string) (string, error) {
|
||||
var val string
|
||||
|
||||
in, err := os.Open(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
_, err = fmt.Fscanf(in, "%s", &val)
|
||||
return val, err
|
||||
}
|
||||
|
||||
func Setfilecon(path string, scon string) error {
|
||||
return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0)
|
||||
}
|
||||
|
||||
func Getfilecon(path string) (string, error) {
|
||||
var scon []byte
|
||||
|
||||
cnt, err := syscall.Getxattr(path, xattrNameSelinux, scon)
|
||||
scon = make([]byte, cnt)
|
||||
cnt, err = syscall.Getxattr(path, xattrNameSelinux, scon)
|
||||
return string(scon), err
|
||||
}
|
||||
|
||||
func Setfscreatecon(scon string) error {
|
||||
return writeCon("/proc/self/attr/fscreate", scon)
|
||||
}
|
||||
|
||||
func Getfscreatecon() (string, error) {
|
||||
return readCon("/proc/self/attr/fscreate")
|
||||
}
|
||||
|
||||
func Getcon() (string, error) {
|
||||
return readCon("/proc/self/attr/current")
|
||||
}
|
||||
|
||||
func Getpidcon(pid int) (string, error) {
|
||||
return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
|
||||
}
|
||||
|
||||
func Getexeccon() (string, error) {
|
||||
return readCon("/proc/self/attr/exec")
|
||||
}
|
||||
|
||||
func writeCon(name string, val string) error {
|
||||
if !SelinuxEnabled() {
|
||||
return nil
|
||||
}
|
||||
out, err := os.OpenFile(name, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
if val != "" {
|
||||
_, err = out.Write([]byte(val))
|
||||
} else {
|
||||
_, err = out.Write(nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Setexeccon(scon string) error {
|
||||
return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon)
|
||||
}
|
||||
|
||||
func (c SELinuxContext) Get() string {
|
||||
return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
|
||||
}
|
||||
|
||||
func NewContext(scon string) SELinuxContext {
|
||||
c := make(SELinuxContext)
|
||||
|
||||
if len(scon) != 0 {
|
||||
con := strings.SplitN(scon, ":", 4)
|
||||
c["user"] = con[0]
|
||||
c["role"] = con[1]
|
||||
c["type"] = con[2]
|
||||
c["level"] = con[3]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func SelinuxGetEnforce() int {
|
||||
var enforce int
|
||||
|
||||
enforceS, err := readCon(fmt.Sprintf("%s/enforce", selinuxPath))
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
enforce, err = strconv.Atoi(string(enforceS))
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return enforce
|
||||
}
|
||||
|
||||
func SelinuxGetEnforceMode() int {
|
||||
switch ReadConfig(selinuxTag) {
|
||||
case "enforcing":
|
||||
return Enforcing
|
||||
case "permissive":
|
||||
return Permissive
|
||||
}
|
||||
return Disabled
|
||||
}
|
||||
|
||||
func mcsAdd(mcs string) {
|
||||
mcsList[mcs] = true
|
||||
}
|
||||
|
||||
func mcsDelete(mcs string) {
|
||||
mcsList[mcs] = false
|
||||
}
|
||||
|
||||
func mcsExists(mcs string) bool {
|
||||
return mcsList[mcs]
|
||||
}
|
||||
|
||||
func IntToMcs(id int, catRange uint32) string {
|
||||
var (
|
||||
SETSIZE = int(catRange)
|
||||
TIER = SETSIZE
|
||||
ORD = id
|
||||
)
|
||||
|
||||
if id < 1 || id > 523776 {
|
||||
return ""
|
||||
}
|
||||
|
||||
for ORD > TIER {
|
||||
ORD = ORD - TIER
|
||||
TIER -= 1
|
||||
}
|
||||
TIER = SETSIZE - TIER
|
||||
ORD = ORD + TIER
|
||||
return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
|
||||
}
|
||||
|
||||
func uniqMcs(catRange uint32) string {
|
||||
var (
|
||||
n uint32
|
||||
c1, c2 uint32
|
||||
mcs string
|
||||
)
|
||||
|
||||
for {
|
||||
binary.Read(rand.Reader, binary.LittleEndian, &n)
|
||||
c1 = n % catRange
|
||||
binary.Read(rand.Reader, binary.LittleEndian, &n)
|
||||
c2 = n % catRange
|
||||
if c1 == c2 {
|
||||
continue
|
||||
} else {
|
||||
if c1 > c2 {
|
||||
t := c1
|
||||
c1 = c2
|
||||
c2 = t
|
||||
}
|
||||
}
|
||||
mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
|
||||
if mcsExists(mcs) {
|
||||
continue
|
||||
}
|
||||
mcsAdd(mcs)
|
||||
break
|
||||
}
|
||||
return mcs
|
||||
}
|
||||
|
||||
func FreeContext(con string) {
|
||||
if con != "" {
|
||||
scon := NewContext(con)
|
||||
mcsDelete(scon["level"])
|
||||
}
|
||||
}
|
||||
|
||||
func GetLxcContexts() (processLabel string, fileLabel string) {
|
||||
var (
|
||||
val, key string
|
||||
bufin *bufio.Reader
|
||||
)
|
||||
|
||||
if !SelinuxEnabled() {
|
||||
return "", ""
|
||||
}
|
||||
lxcPath := fmt.Sprintf("%s/content/lxc_contexts", GetSELinuxPolicyRoot())
|
||||
fileLabel = "system_u:object_r:svirt_sandbox_file_t:s0"
|
||||
processLabel = "system_u:system_r:svirt_lxc_net_t:s0"
|
||||
|
||||
in, err := os.Open(lxcPath)
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
bufin = bufio.NewReader(in)
|
||||
|
||||
for done := false; !done; {
|
||||
var line string
|
||||
if line, err = bufin.ReadString('\n'); err != nil {
|
||||
if err == io.EOF {
|
||||
done = true
|
||||
} else {
|
||||
goto exit
|
||||
}
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
// Skip blank lines
|
||||
continue
|
||||
}
|
||||
if line[0] == ';' || line[0] == '#' {
|
||||
// Skip comments
|
||||
continue
|
||||
}
|
||||
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
|
||||
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
|
||||
if key == "process" {
|
||||
processLabel = strings.Trim(val, "\"")
|
||||
}
|
||||
if key == "file" {
|
||||
fileLabel = strings.Trim(val, "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
exit:
|
||||
mcs := IntToMcs(os.Getpid(), 1024)
|
||||
scon := NewContext(processLabel)
|
||||
scon["level"] = mcs
|
||||
processLabel = scon.Get()
|
||||
scon = NewContext(fileLabel)
|
||||
scon["level"] = mcs
|
||||
fileLabel = scon.Get()
|
||||
return processLabel, fileLabel
|
||||
}
|
||||
|
||||
func SecurityCheckContext(val string) error {
|
||||
return writeCon(fmt.Sprintf("%s.context", selinuxPath), val)
|
||||
}
|
||||
|
||||
func CopyLevel(src, dest string) (string, error) {
|
||||
if !SelinuxEnabled() {
|
||||
return "", nil
|
||||
}
|
||||
if src == "" {
|
||||
return "", nil
|
||||
}
|
||||
if err := SecurityCheckContext(src); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := SecurityCheckContext(dest); err != nil {
|
||||
return "", err
|
||||
}
|
||||
scon := NewContext(src)
|
||||
tcon := NewContext(dest)
|
||||
tcon["level"] = scon["level"]
|
||||
return tcon.Get(), nil
|
||||
}
|
64
pkg/selinux/selinux_test.go
Normal file
64
pkg/selinux/selinux_test.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package selinux_test
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/pkg/selinux"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testSetfilecon(t *testing.T) {
|
||||
if selinux.SelinuxEnabled() {
|
||||
tmp := "selinux_test"
|
||||
out, _ := os.OpenFile(tmp, os.O_WRONLY, 0)
|
||||
out.Close()
|
||||
err := selinux.Setfilecon(tmp, "system_u:object_r:bin_t:s0")
|
||||
if err == nil {
|
||||
t.Log(selinux.Getfilecon(tmp))
|
||||
} else {
|
||||
t.Log("Setfilecon failed")
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.Remove(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSELinux(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
plabel, flabel string
|
||||
)
|
||||
|
||||
if selinux.SelinuxEnabled() {
|
||||
t.Log("Enabled")
|
||||
plabel, flabel = selinux.GetLxcContexts()
|
||||
t.Log(plabel)
|
||||
t.Log(flabel)
|
||||
plabel, flabel = selinux.GetLxcContexts()
|
||||
t.Log(plabel)
|
||||
t.Log(flabel)
|
||||
t.Log("getenforce ", selinux.SelinuxGetEnforce())
|
||||
t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
|
||||
pid := os.Getpid()
|
||||
t.Log("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
|
||||
t.Log(selinux.Getcon())
|
||||
t.Log(selinux.Getfilecon("/etc/passwd"))
|
||||
err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0")
|
||||
if err == nil {
|
||||
t.Log(selinux.Getfscreatecon())
|
||||
} else {
|
||||
t.Log("setfscreatecon failed", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = selinux.Setfscreatecon("")
|
||||
if err == nil {
|
||||
t.Log(selinux.Getfscreatecon())
|
||||
} else {
|
||||
t.Log("setfscreatecon failed", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(selinux.Getpidcon(1))
|
||||
t.Log(selinux.GetSelinuxMountPoint())
|
||||
} else {
|
||||
t.Log("Disabled")
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package runconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/runtime/execdriver"
|
||||
)
|
||||
|
||||
// Note: the Config structure should hold only portable information about the container.
|
||||
|
@ -34,9 +36,17 @@ type Config struct {
|
|||
Entrypoint []string
|
||||
NetworkDisabled bool
|
||||
OnBuild []string
|
||||
Context execdriver.Context
|
||||
}
|
||||
|
||||
func ContainerConfigFromJob(job *engine.Job) *Config {
|
||||
var context execdriver.Context
|
||||
val := job.Getenv("Context")
|
||||
if val != "" {
|
||||
if err := json.Unmarshal([]byte(val), &context); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
config := &Config{
|
||||
Hostname: job.Getenv("Hostname"),
|
||||
Domainname: job.Getenv("Domainname"),
|
||||
|
@ -54,6 +64,7 @@ func ContainerConfigFromJob(job *engine.Job) *Config {
|
|||
VolumesFrom: job.Getenv("VolumesFrom"),
|
||||
WorkingDir: job.Getenv("WorkingDir"),
|
||||
NetworkDisabled: job.GetenvBool("NetworkDisabled"),
|
||||
Context: context,
|
||||
}
|
||||
job.GetenvJson("ExposedPorts", &config.ExposedPorts)
|
||||
job.GetenvJson("Volumes", &config.Volumes)
|
||||
|
|
|
@ -4,8 +4,10 @@ import (
|
|||
"fmt"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/opts"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
flag "github.com/dotcloud/docker/pkg/mflag"
|
||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
||||
"github.com/dotcloud/docker/runtime/execdriver"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
|
@ -32,6 +34,10 @@ func ParseSubcommand(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo)
|
|||
}
|
||||
|
||||
func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||
var (
|
||||
processLabel string
|
||||
mountLabel string
|
||||
)
|
||||
var (
|
||||
// FIXME: use utils.ListOpts for attach and volumes?
|
||||
flAttach = opts.NewListOpts(opts.ValidateAttach)
|
||||
|
@ -60,6 +66,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
|||
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID")
|
||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
||||
flLabelOptions = cmd.String([]string{"Z", "-label"}, "", "Options to pass to underlying labeling system")
|
||||
|
||||
// For documentation purpose
|
||||
_ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
||||
|
@ -150,6 +157,15 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
|||
entrypoint = []string{*flEntrypoint}
|
||||
}
|
||||
|
||||
if !*flPrivileged {
|
||||
pLabel, mLabel, e := label.GenLabels(*flLabelOptions)
|
||||
if e != nil {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid security labels : %s", e)
|
||||
}
|
||||
processLabel = pLabel
|
||||
mountLabel = mLabel
|
||||
}
|
||||
|
||||
lxcConf, err := parseLxcConfOpts(flLxcOpts)
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
|
@ -204,6 +220,10 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
|||
VolumesFrom: strings.Join(flVolumesFrom.GetAll(), ","),
|
||||
Entrypoint: entrypoint,
|
||||
WorkingDir: *flWorkingDir,
|
||||
Context: execdriver.Context{
|
||||
"mount_label": mountLabel,
|
||||
"process_label": processLabel,
|
||||
},
|
||||
}
|
||||
|
||||
hostConfig := &HostConfig{
|
||||
|
|
|
@ -402,6 +402,7 @@ func populateCommand(c *Container) {
|
|||
User: c.Config.User,
|
||||
Config: driverConfig,
|
||||
Resources: resources,
|
||||
Context: c.Config.Context,
|
||||
}
|
||||
c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ import (
|
|||
"os/exec"
|
||||
)
|
||||
|
||||
// Context is a generic key value pair that allows
|
||||
// arbatrary data to be sent
|
||||
type Context map[string]string
|
||||
|
||||
var (
|
||||
ErrNotRunning = errors.New("Process could not be started")
|
||||
ErrWaitTimeoutReached = errors.New("Wait timeout reached")
|
||||
|
@ -121,6 +125,7 @@ type Command struct {
|
|||
Arguments []string `json:"arguments"`
|
||||
WorkingDir string `json:"working_dir"`
|
||||
ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
|
||||
Context Context `json:"context"` // generic context for specific options (apparmor, selinux)
|
||||
Tty bool `json:"tty"`
|
||||
Network *Network `json:"network"`
|
||||
Config []string `json:"config"` // generic values that specific drivers can consume
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package lxc
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/runtime/execdriver"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
@ -29,6 +30,10 @@ lxc.pts = 1024
|
|||
|
||||
# disable the main console
|
||||
lxc.console = none
|
||||
{{if getProcessLabel .Context}}
|
||||
lxc.se_context = {{ getProcessLabel .Context}}
|
||||
{{$MOUNTLABEL := getMountLabel .Context}}
|
||||
{{end}}
|
||||
|
||||
# no controlling tty at all
|
||||
lxc.tty = 1
|
||||
|
@ -85,8 +90,8 @@ lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noe
|
|||
lxc.mount.entry = {{.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0
|
||||
{{end}}
|
||||
|
||||
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
|
||||
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
|
||||
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMountLabel "newinstance,ptmxmode=0666,nosuid,noexec" "$MOUNTLABEL"}} 0 0
|
||||
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec" "$MOUNTLABEL"}} 0 0
|
||||
|
||||
{{range $value := .Mounts}}
|
||||
{{if $value.Writable}}
|
||||
|
@ -142,11 +147,22 @@ func getMemorySwap(v *execdriver.Resources) int64 {
|
|||
return v.Memory * 2
|
||||
}
|
||||
|
||||
func getProcessLabel(c execdriver.Context) string {
|
||||
return c["process_label"]
|
||||
}
|
||||
|
||||
func getMountLabel(c execdriver.Context) string {
|
||||
return c["mount_label"]
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
funcMap := template.FuncMap{
|
||||
"getMemorySwap": getMemorySwap,
|
||||
"getProcessLabel": getProcessLabel,
|
||||
"getMountLabel": getMountLabel,
|
||||
"escapeFstabSpaces": escapeFstabSpaces,
|
||||
"formatMountLabel": label.FormatMountLabel,
|
||||
}
|
||||
LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
|
||||
if err != nil {
|
||||
|
|
|
@ -18,6 +18,8 @@ func createContainer(c *execdriver.Command) *libcontainer.Container {
|
|||
container.User = c.User
|
||||
container.WorkingDir = c.WorkingDir
|
||||
container.Env = c.Env
|
||||
container.Context["mount_label"] = c.Context["mount_label"]
|
||||
container.Context["process_label"] = c.Context["process_label"]
|
||||
|
||||
loopbackNetwork := libcontainer.Network{
|
||||
Mtu: c.Network.Mtu,
|
||||
|
|
|
@ -134,7 +134,7 @@ func (a Driver) Exists(id string) bool {
|
|||
|
||||
// Three folders are created for each id
|
||||
// mnt, layers, and diff
|
||||
func (a *Driver) Create(id, parent string) error {
|
||||
func (a *Driver) Create(id, parent string, mountLabel string) error {
|
||||
if err := a.createDirsFor(id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ func TestCreateNewDir(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ func TestCreateNewDirStructure(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ func TestRemoveImage(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ func TestGetWithoutParent(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ func TestCleanupWithDir(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ func TestMountedFalseResponse(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -204,10 +204,10 @@ func TestMountedTrueReponse(t *testing.T) {
|
|||
defer os.RemoveAll(tmp)
|
||||
defer d.Cleanup()
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := d.Create("2", "1"); err != nil {
|
||||
if err := d.Create("2", "1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -230,10 +230,10 @@ func TestMountWithParent(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := d.Create("2", "1"); err != nil {
|
||||
if err := d.Create("2", "1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -261,10 +261,10 @@ func TestRemoveMountedDir(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := d.Create("2", "1"); err != nil {
|
||||
if err := d.Create("2", "1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ func TestCreateWithInvalidParent(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", "docker"); err == nil {
|
||||
if err := d.Create("1", "docker", ""); err == nil {
|
||||
t.Fatalf("Error should not be nil with parent does not exist")
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ func TestGetDiff(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -343,10 +343,10 @@ func TestChanges(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := d.Create("2", "1"); err != nil {
|
||||
if err := d.Create("2", "1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -392,7 +392,7 @@ func TestChanges(t *testing.T) {
|
|||
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
|
||||
}
|
||||
|
||||
if err := d.Create("3", "2"); err != nil {
|
||||
if err := d.Create("3", "2", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mntPoint, err = d.Get("3")
|
||||
|
@ -437,7 +437,7 @@ func TestDiffSize(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -479,7 +479,7 @@ func TestChildDiffSize(t *testing.T) {
|
|||
defer os.RemoveAll(tmp)
|
||||
defer d.Cleanup()
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -515,7 +515,7 @@ func TestChildDiffSize(t *testing.T) {
|
|||
t.Fatalf("Expected size to be %d got %d", size, diffSize)
|
||||
}
|
||||
|
||||
if err := d.Create("2", "1"); err != nil {
|
||||
if err := d.Create("2", "1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -534,7 +534,7 @@ func TestExists(t *testing.T) {
|
|||
defer os.RemoveAll(tmp)
|
||||
defer d.Cleanup()
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -552,7 +552,7 @@ func TestStatus(t *testing.T) {
|
|||
defer os.RemoveAll(tmp)
|
||||
defer d.Cleanup()
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -581,7 +581,7 @@ func TestApplyDiff(t *testing.T) {
|
|||
defer os.RemoveAll(tmp)
|
||||
defer d.Cleanup()
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -607,10 +607,10 @@ func TestApplyDiff(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := d.Create("2", ""); err != nil {
|
||||
if err := d.Create("2", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := d.Create("3", "2"); err != nil {
|
||||
if err := d.Create("3", "2", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -656,7 +656,7 @@ func TestMountMoreThan42Layers(t *testing.T) {
|
|||
}
|
||||
current = hash(current)
|
||||
|
||||
if err := d.Create(current, parent); err != nil {
|
||||
if err := d.Create(current, parent, ""); err != nil {
|
||||
t.Logf("Current layer %d", i)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) e
|
|||
}
|
||||
|
||||
initID := fmt.Sprintf("%s-init", id)
|
||||
if err := a.Create(initID, metadata.Image); err != nil {
|
||||
if err := a.Create(initID, metadata.Image, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) e
|
|||
return err
|
||||
}
|
||||
|
||||
if err := a.Create(id, initID); err != nil {
|
||||
if err := a.Create(id, initID, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ func (a *Driver) migrateImage(m *metadata, pth string, migrated map[string]bool)
|
|||
return err
|
||||
}
|
||||
if !a.Exists(m.ID) {
|
||||
if err := a.Create(m.ID, m.ParentID); err != nil {
|
||||
if err := a.Create(m.ID, m.ParentID, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ func getDirFd(dir *C.DIR) uintptr {
|
|||
return uintptr(C.dirfd(dir))
|
||||
}
|
||||
|
||||
func subvolCreate(path, name string) error {
|
||||
func subvolCreate(path, name string, mountLabel string) error {
|
||||
dir, err := openDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -155,13 +155,13 @@ func (d *Driver) subvolumesDirId(id string) string {
|
|||
return path.Join(d.subvolumesDir(), id)
|
||||
}
|
||||
|
||||
func (d *Driver) Create(id string, parent string) error {
|
||||
func (d *Driver) Create(id string, parent string, mountLabel string) error {
|
||||
subvolumes := path.Join(d.home, "subvolumes")
|
||||
if err := os.MkdirAll(subvolumes, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
if parent == "" {
|
||||
if err := subvolCreate(subvolumes, id); err != nil {
|
||||
if err := subvolCreate(subvolumes, id, mountLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/label"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -827,7 +828,7 @@ func (devices *DeviceSet) Shutdown() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSet) MountDevice(hash, path string) error {
|
||||
func (devices *DeviceSet) MountDevice(hash, path string, mountLabel string) error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
|
@ -859,9 +860,11 @@ func (devices *DeviceSet) MountDevice(hash, path string) error {
|
|||
|
||||
var flags uintptr = sysMsMgcVal
|
||||
|
||||
err := sysMount(info.DevName(), path, "ext4", flags, "discard")
|
||||
mountOptions := label.FormatMountLabel("discard", mountLabel)
|
||||
err := sysMount(info.DevName(), path, "ext4", flags, mountOptions)
|
||||
if err != nil && err == sysEInval {
|
||||
err = sysMount(info.DevName(), path, "ext4", flags, "")
|
||||
mountOptions = label.FormatMountLabel(mountLabel, "")
|
||||
err = sysMount(info.DevName(), path, "ext4", flags, mountOptions)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
|
||||
|
|
|
@ -22,7 +22,8 @@ func init() {
|
|||
|
||||
type Driver struct {
|
||||
*DeviceSet
|
||||
home string
|
||||
home string
|
||||
MountLabel string
|
||||
}
|
||||
|
||||
var Init = func(home string) (graphdriver.Driver, error) {
|
||||
|
@ -60,13 +61,13 @@ func (d *Driver) Cleanup() error {
|
|||
return d.DeviceSet.Shutdown()
|
||||
}
|
||||
|
||||
func (d *Driver) Create(id, parent string) error {
|
||||
func (d *Driver) Create(id, parent string, mountLabel string) error {
|
||||
d.MountLabel = mountLabel
|
||||
if err := d.DeviceSet.AddDevice(id, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mp := path.Join(d.home, "mnt", id)
|
||||
if err := d.mount(id, mp); err != nil {
|
||||
if err := d.mount(id, mp, d.MountLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -116,7 +117,7 @@ func (d *Driver) Remove(id string) error {
|
|||
|
||||
func (d *Driver) Get(id string) (string, error) {
|
||||
mp := path.Join(d.home, "mnt", id)
|
||||
if err := d.mount(id, mp); err != nil {
|
||||
if err := d.mount(id, mp, d.MountLabel); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
@ -129,13 +130,13 @@ func (d *Driver) Put(id string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *Driver) mount(id, mountPoint string) error {
|
||||
func (d *Driver) mount(id, mountPoint string, mountLabel string) error {
|
||||
// Create the target directories if they don't exist
|
||||
if err := osMkdirAll(mountPoint, 0755); err != nil && !osIsExist(err) {
|
||||
return err
|
||||
}
|
||||
// Mount the device
|
||||
return d.DeviceSet.MountDevice(id, mountPoint)
|
||||
return d.DeviceSet.MountDevice(id, mountPoint, mountLabel)
|
||||
}
|
||||
|
||||
func (d *Driver) Exists(id string) bool {
|
||||
|
|
|
@ -494,7 +494,7 @@ func TestDriverCreate(t *testing.T) {
|
|||
"?ioctl.loopctlgetfree",
|
||||
)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
calls.Assert(t,
|
||||
|
@ -612,7 +612,7 @@ func TestDriverRemove(t *testing.T) {
|
|||
"?ioctl.loopctlgetfree",
|
||||
)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -668,7 +668,7 @@ func TestCleanup(t *testing.T) {
|
|||
|
||||
mountPoints := make([]string, 2)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Mount the id
|
||||
|
@ -678,7 +678,7 @@ func TestCleanup(t *testing.T) {
|
|||
}
|
||||
mountPoints[0] = p
|
||||
|
||||
if err := d.Create("2", "1"); err != nil {
|
||||
if err := d.Create("2", "1", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -731,7 +731,7 @@ func TestNotMounted(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer cleanup(d)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -749,7 +749,7 @@ func TestMounted(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer cleanup(d)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := d.Get("1"); err != nil {
|
||||
|
@ -769,7 +769,7 @@ func TestInitCleanedDriver(t *testing.T) {
|
|||
t.Skip("FIXME: not a unit test")
|
||||
d := newDriver(t)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := d.Get("1"); err != nil {
|
||||
|
@ -797,7 +797,7 @@ func TestMountMountedDriver(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer cleanup(d)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -816,7 +816,7 @@ func TestGetReturnsValidDevice(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer cleanup(d)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -844,7 +844,7 @@ func TestDriverGetSize(t *testing.T) {
|
|||
d := newDriver(t)
|
||||
defer cleanup(d)
|
||||
|
||||
if err := d.Create("1", ""); err != nil {
|
||||
if err := d.Create("1", "", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ type InitFunc func(root string) (Driver, error)
|
|||
type Driver interface {
|
||||
String() string
|
||||
|
||||
Create(id, parent string) error
|
||||
Create(id, parent string, mountLabel string) error
|
||||
Remove(id string) error
|
||||
|
||||
Get(id string) (dir string, err error)
|
||||
|
|
|
@ -42,7 +42,7 @@ func copyDir(src, dst string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) Create(id string, parent string) error {
|
||||
func (d *Driver) Create(id string, parent string, mountLabel string) error {
|
||||
dir := d.dir(id)
|
||||
if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
|
||||
return err
|
||||
|
|
|
@ -467,7 +467,7 @@ func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Containe
|
|||
}
|
||||
|
||||
initID := fmt.Sprintf("%s-init", container.ID)
|
||||
if err := runtime.driver.Create(initID, img.ID); err != nil {
|
||||
if err := runtime.driver.Create(initID, img.ID, config.Context["mount_label"]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
initPath, err := runtime.driver.Get(initID)
|
||||
|
@ -480,7 +480,7 @@ func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Containe
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := runtime.driver.Create(container.ID, initID); err != nil {
|
||||
if err := runtime.driver.Create(container.ID, initID, config.Context["mount_label"]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resolvConf, err := utils.GetResolvConf()
|
||||
|
|
Loading…
Add table
Reference in a new issue