From b7942ec2ca7c7568df0c3b7eb554b05e2c3a3081 Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Mon, 21 Apr 2014 17:09:26 -0400 Subject: [PATCH] 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) --- daemon/container.go | 18 +++++++++++------- daemon/daemon.go | 4 +++- daemonconfig/config.go | 2 +- docker/docker.go | 2 +- pkg/label/label.go | 4 ++++ pkg/label/label_selinux.go | 4 ++++ pkg/selinux/selinux.go | 28 ++++++++++++++++++++++++---- pkg/selinux/selinux_test.go | 2 ++ 8 files changed, 50 insertions(+), 14 deletions(-) diff --git a/daemon/container.go b/daemon/container.go index 4416a4c21..2190869da 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -11,7 +11,7 @@ import ( "github.com/dotcloud/docker/image" "github.com/dotcloud/docker/links" "github.com/dotcloud/docker/nat" - "github.com/dotcloud/docker/pkg/selinux" + "github.com/dotcloud/docker/pkg/label" "github.com/dotcloud/docker/runconfig" "github.com/dotcloud/docker/utils" "io" @@ -66,7 +66,7 @@ type Container struct { stdinPipe io.WriteCloser daemon *Daemon - mountLabel, processLabel string + MountLabel, ProcessLabel string waitLock chan struct{} Volumes map[string]string @@ -124,6 +124,7 @@ func (container *Container) FromDisk() error { if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") { return err } + label.ReserveLabel(container.ProcessLabel) return container.readHostConfig() } @@ -325,8 +326,8 @@ func populateCommand(c *Container, env []string) { en *execdriver.Network context = make(map[string][]string) ) - context["process_label"] = []string{c.processLabel} - context["mount_label"] = []string{c.mountLabel} + context["process_label"] = []string{c.ProcessLabel} + context["mount_label"] = []string{c.MountLabel} en = &execdriver.Network{ Mtu: c.daemon.config.Mtu, @@ -388,10 +389,13 @@ func (container *Container) Start() (err error) { return err } - process, mount := selinux.GetLxcContexts() + process, mount, err := label.GenLabels("") + if err != nil { + return err + } - container.mountLabel = mount - container.processLabel = process + container.MountLabel = mount + container.ProcessLabel = process if err := container.Mount(); err != nil { return err diff --git a/daemon/daemon.go b/daemon/daemon.go index 50707fbc9..2aac52107 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -289,6 +289,8 @@ func (daemon *Daemon) Destroy(container *Container) error { if err := os.RemoveAll(container.root); err != nil { return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err) } + selinux.FreeLxcContexts(container.ProcessLabel) + return nil } @@ -839,7 +841,7 @@ func (daemon *Daemon) Close() error { } func (daemon *Daemon) Mount(container *Container) error { - dir, err := daemon.driver.Get(container.ID, container.mountLabel) + dir, err := daemon.driver.Get(container.ID, container.MountLabel) if err != nil { return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err) } diff --git a/daemonconfig/config.go b/daemonconfig/config.go index 87ac52224..619bfe582 100644 --- a/daemonconfig/config.go +++ b/daemonconfig/config.go @@ -47,7 +47,7 @@ func ConfigFromJob(job *engine.Job) *Config { InterContainerCommunication: job.GetenvBool("InterContainerCommunication"), GraphDriver: job.Getenv("GraphDriver"), ExecDriver: job.Getenv("ExecDriver"), - EnableSelinuxSupport: job.GetenvBool("SelinuxEnabled"), + EnableSelinuxSupport: job.GetenvBool("EnableSelinuxSupport"), } if dns := job.GetenvList("Dns"); dns != nil { config.Dns = dns diff --git a/docker/docker.go b/docker/docker.go index ce3c54dac..7c366001b 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -149,7 +149,7 @@ func main() { job.Setenv("GraphDriver", *flGraphDriver) job.Setenv("ExecDriver", *flExecDriver) job.SetenvInt("Mtu", *flMtu) - job.SetenvBool("SelinuxEnabled", *flSelinuxEnabled) + job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled) if err := job.Run(); err != nil { log.Fatal(err) } diff --git a/pkg/label/label.go b/pkg/label/label.go index 38f026bc5..434e1c572 100644 --- a/pkg/label/label.go +++ b/pkg/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/pkg/label/label_selinux.go b/pkg/label/label_selinux.go index 2f67ee458..9361a7142 100644 --- a/pkg/label/label_selinux.go +++ b/pkg/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/pkg/selinux/selinux.go b/pkg/selinux/selinux.go index edabc4f7d..422c39bab 100644 --- a/pkg/selinux/selinux.go +++ b/pkg/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/pkg/selinux/selinux_test.go b/pkg/selinux/selinux_test.go index fde6ab147..9a3a5525e 100644 --- a/pkg/selinux/selinux_test.go +++ b/pkg/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()