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 4416a4c212..2190869da0 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 50707fbc98..2aac521072 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 87ac52224d..619bfe582f 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 ce3c54dacd..7c366001b7 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 38f026bc5a..434e1c5725 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 2f67ee458f..9361a7142c 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 edabc4f7dd..422c39babd 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 fde6ab147d..9a3a5525e4 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()