From 48d893cc6b57ebff7bcf2b51aaa6855acd4c113d Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 17 Apr 2014 23:47:27 +0000 Subject: [PATCH 1/5] Initial work on selinux patch This has every container using the docker daemon's pid for the processes label so it does not work correctly. Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- label/label_selinux.go | 8 ++++---- libcontainer/nsinit/init.go | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/label/label_selinux.go b/label/label_selinux.go index 9f7463f..2f67ee4 100644 --- a/label/label_selinux.go +++ b/label/label_selinux.go @@ -32,13 +32,13 @@ func GenLabels(options string) (string, string, error) { return processLabel, mountLabel, err } -func FormatMountLabel(src string, mountLabel string) string { - if selinux.SelinuxEnabled() && mountLabel != "" { +func FormatMountLabel(src, mountLabel string) string { + if mountLabel != "" { switch src { case "": - src = fmt.Sprintf("%s,context=%s", src, mountLabel) + src = fmt.Sprintf("context=%q", mountLabel) default: - src = fmt.Sprintf("context=%s", mountLabel) + src = fmt.Sprintf("%s,context=%q", src, mountLabel) } } return src diff --git a/libcontainer/nsinit/init.go b/libcontainer/nsinit/init.go index 4e50bc5..36c8cd1 100644 --- a/libcontainer/nsinit/init.go +++ b/libcontainer/nsinit/init.go @@ -75,8 +75,9 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol } } runtime.LockOSThread() + if err := label.SetProcessLabel(container.Context["process_label"]); err != nil { - return fmt.Errorf("SetProcessLabel label %s", err) + return fmt.Errorf("set process label %s", err) } ns.logger.Printf("execing %s\n", args[0]) return system.Execv(args[0], args[0:], container.Env) From d0559e92af5a7d7a4441b6a8cab39accab6e29bc Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Mon, 21 Apr 2014 17:09:26 -0400 Subject: [PATCH 2/5] This patch reworks the SELinux patch to be only run on demand by the daemon Added --selinux-enable switch to daemon to enable SELinux labeling. The daemon will now generate a new unique random SELinux label when a container starts, and remove it when the container is removed. The MCS labels will be stored in the daemon memory. The labels of containers will be stored in the container.json file. When the daemon restarts on boot or if done by an admin, it will read all containers json files and reserve the MCS labels. A potential problem would be conflicts if you setup thousands of containers, current scheme would handle ~500,000 containers. Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: rhatdan) Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: crosbymichael) --- label/label.go | 4 ++++ label/label_selinux.go | 4 ++++ selinux/selinux.go | 28 ++++++++++++++++++++++++---- selinux/selinux_test.go | 2 ++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/label/label.go b/label/label.go index 38f026b..434e1c5 100644 --- a/label/label.go +++ b/label/label.go @@ -24,3 +24,7 @@ func GetPidCon(pid int) (string, error) { func Init() { } + +func ReserveLabel(label string) error { + return nil +} diff --git a/label/label_selinux.go b/label/label_selinux.go index 2f67ee4..9361a71 100644 --- a/label/label_selinux.go +++ b/label/label_selinux.go @@ -75,3 +75,7 @@ func GetPidCon(pid int) (string, error) { func Init() { selinux.SelinuxEnabled() } + +func ReserveLabel(label string) { + selinux.ReserveLabel(label) +} diff --git a/selinux/selinux.go b/selinux/selinux.go index edabc4f..422c39b 100644 --- a/selinux/selinux.go +++ b/selinux/selinux.go @@ -204,6 +204,13 @@ func NewContext(scon string) SELinuxContext { return c } +func ReserveLabel(scon string) { + if len(scon) != 0 { + con := strings.SplitN(scon, ":", 4) + mcsAdd(con[3]) + } +} + func SelinuxGetEnforce() int { var enforce int @@ -229,8 +236,12 @@ func SelinuxGetEnforceMode() int { return Disabled } -func mcsAdd(mcs string) { +func mcsAdd(mcs string) error { + if mcsList[mcs] { + return fmt.Errorf("MCS Label already exists") + } mcsList[mcs] = true + return nil } func mcsDelete(mcs string) { @@ -283,15 +294,21 @@ func uniqMcs(catRange uint32) string { } } mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) - if mcsExists(mcs) { + if err := mcsAdd(mcs); err != nil { continue } - mcsAdd(mcs) break } return mcs } +func FreeLxcContexts(scon string) { + if len(scon) != 0 { + con := strings.SplitN(scon, ":", 4) + mcsDelete(con[3]) + } +} + func GetLxcContexts() (processLabel string, fileLabel string) { var ( val, key string @@ -344,7 +361,8 @@ func GetLxcContexts() (processLabel string, fileLabel string) { } exit: - mcs := IntToMcs(os.Getpid(), 1024) + // mcs := IntToMcs(os.Getpid(), 1024) + mcs := uniqMcs(1024) scon := NewContext(processLabel) scon["level"] = mcs processLabel = scon.Get() @@ -373,6 +391,8 @@ func CopyLevel(src, dest string) (string, error) { } scon := NewContext(src) tcon := NewContext(dest) + mcsDelete(tcon["level"]) + mcsAdd(scon["level"]) tcon["level"] = scon["level"] return tcon.Get(), nil } diff --git a/selinux/selinux_test.go b/selinux/selinux_test.go index fde6ab1..9a3a552 100644 --- a/selinux/selinux_test.go +++ b/selinux/selinux_test.go @@ -31,9 +31,11 @@ func TestSELinux(t *testing.T) { plabel, flabel = selinux.GetLxcContexts() t.Log(plabel) t.Log(flabel) + selinux.FreeLxcContexts(plabel) plabel, flabel = selinux.GetLxcContexts() t.Log(plabel) t.Log(flabel) + selinux.FreeLxcContexts(plabel) t.Log("getenforce ", selinux.SelinuxGetEnforce()) t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode()) pid := os.Getpid() From 2b713061f5100659afb5d8ccec77e435c4e50b9a Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Fri, 25 Apr 2014 14:34:42 -0400 Subject: [PATCH 3/5] Fix SELinux errors caused by multi-threading Occasionally the selinux_test program will fail because we are setting file context based on the Process ID but not the TID. THis change will always use the TID to set SELinux labels. Docker-DCO-1.1-Signed-off-by: Daniel Walsh (github: rhatdan) Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: crosbymichael) --- selinux/selinux.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selinux/selinux.go b/selinux/selinux.go index 422c39b..6cf7bd7 100644 --- a/selinux/selinux.go +++ b/selinux/selinux.go @@ -146,15 +146,15 @@ func Setfilecon(path string, scon string) error { } func Setfscreatecon(scon string) error { - return writeCon("/proc/self/attr/fscreate", scon) + return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", system.Gettid()), scon) } func Getfscreatecon() (string, error) { - return readCon("/proc/self/attr/fscreate") + return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", system.Gettid())) } func getcon() (string, error) { - return readCon("/proc/self/attr/current") + return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", system.Gettid())) } func Getpidcon(pid int) (string, error) { From 50cc71ca29aa898f037d8b1ccf45578b38677bdf Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 28 Apr 2014 14:36:04 -0700 Subject: [PATCH 4/5] Update process labels to be set at create not start Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- label/label_selinux.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/label/label_selinux.go b/label/label_selinux.go index 9361a71..926f7ff 100644 --- a/label/label_selinux.go +++ b/label/label_selinux.go @@ -4,8 +4,9 @@ package label import ( "fmt" - "github.com/dotcloud/docker/pkg/selinux" "strings" + + "github.com/dotcloud/docker/pkg/selinux" ) func GenLabels(options string) (string, string, error) { @@ -76,6 +77,7 @@ func Init() { selinux.SelinuxEnabled() } -func ReserveLabel(label string) { +func ReserveLabel(label string) error { selinux.ReserveLabel(label) + return nil } From 7b566eab437bcc759de55281311c72a290a53647 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 29 Apr 2014 03:41:44 -0700 Subject: [PATCH 5/5] Add mountlabel to dev Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- libcontainer/mount/init.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libcontainer/mount/init.go b/libcontainer/mount/init.go index 06b2c82..735970c 100644 --- a/libcontainer/mount/init.go +++ b/libcontainer/mount/init.go @@ -4,14 +4,15 @@ package mount import ( "fmt" + "os" + "path/filepath" + "syscall" + "github.com/dotcloud/docker/pkg/label" "github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer/mount/nodes" "github.com/dotcloud/docker/pkg/libcontainer/security/restrict" "github.com/dotcloud/docker/pkg/system" - "os" - "path/filepath" - "syscall" ) // default mount point flags @@ -130,11 +131,12 @@ func newSystemMounts(rootfs, mountLabel string, mounts libcontainer.Mounts) []mo } if len(mounts.OfType("devtmpfs")) == 1 { - systemMounts = append(systemMounts, mount{source: "tmpfs", path: filepath.Join(rootfs, "dev"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, data: "mode=755"}) + systemMounts = append(systemMounts, mount{source: "tmpfs", path: filepath.Join(rootfs, "dev"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, data: label.FormatMountLabel("mode=755", mountLabel)}) } systemMounts = append(systemMounts, mount{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: label.FormatMountLabel("mode=1777,size=65536k", mountLabel)}, - mount{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)}) + mount{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 len(mounts.OfType("sysfs")) == 1 { systemMounts = append(systemMounts, mount{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaultMountFlags})