Browse Source

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 <dwalsh@redhat.com> (github: rhatdan)
Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: crosbymichael)
Dan Walsh 11 years ago
parent
commit
b7942ec2ca

+ 11 - 7
daemon/container.go

@@ -11,7 +11,7 @@ import (
 	"github.com/dotcloud/docker/image"
 	"github.com/dotcloud/docker/image"
 	"github.com/dotcloud/docker/links"
 	"github.com/dotcloud/docker/links"
 	"github.com/dotcloud/docker/nat"
 	"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/runconfig"
 	"github.com/dotcloud/docker/utils"
 	"github.com/dotcloud/docker/utils"
 	"io"
 	"io"
@@ -66,7 +66,7 @@ type Container struct {
 	stdinPipe io.WriteCloser
 	stdinPipe io.WriteCloser
 
 
 	daemon                   *Daemon
 	daemon                   *Daemon
-	mountLabel, processLabel string
+	MountLabel, ProcessLabel string
 
 
 	waitLock chan struct{}
 	waitLock chan struct{}
 	Volumes  map[string]string
 	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") {
 	if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") {
 		return err
 		return err
 	}
 	}
+	label.ReserveLabel(container.ProcessLabel)
 	return container.readHostConfig()
 	return container.readHostConfig()
 }
 }
 
 
@@ -325,8 +326,8 @@ func populateCommand(c *Container, env []string) {
 		en      *execdriver.Network
 		en      *execdriver.Network
 		context = make(map[string][]string)
 		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{
 	en = &execdriver.Network{
 		Mtu:       c.daemon.config.Mtu,
 		Mtu:       c.daemon.config.Mtu,
@@ -388,10 +389,13 @@ func (container *Container) Start() (err error) {
 		return err
 		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 {
 	if err := container.Mount(); err != nil {
 		return err
 		return err

+ 3 - 1
daemon/daemon.go

@@ -289,6 +289,8 @@ func (daemon *Daemon) Destroy(container *Container) error {
 	if err := os.RemoveAll(container.root); err != nil {
 	if err := os.RemoveAll(container.root); err != nil {
 		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
 		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
 	}
 	}
+	selinux.FreeLxcContexts(container.ProcessLabel)
+
 	return nil
 	return nil
 }
 }
 
 
@@ -839,7 +841,7 @@ func (daemon *Daemon) Close() error {
 }
 }
 
 
 func (daemon *Daemon) Mount(container *Container) 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 {
 	if err != nil {
 		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err)
 		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err)
 	}
 	}

+ 1 - 1
daemonconfig/config.go

@@ -47,7 +47,7 @@ func ConfigFromJob(job *engine.Job) *Config {
 		InterContainerCommunication: job.GetenvBool("InterContainerCommunication"),
 		InterContainerCommunication: job.GetenvBool("InterContainerCommunication"),
 		GraphDriver:                 job.Getenv("GraphDriver"),
 		GraphDriver:                 job.Getenv("GraphDriver"),
 		ExecDriver:                  job.Getenv("ExecDriver"),
 		ExecDriver:                  job.Getenv("ExecDriver"),
-		EnableSelinuxSupport:        job.GetenvBool("SelinuxEnabled"),
+		EnableSelinuxSupport:        job.GetenvBool("EnableSelinuxSupport"),
 	}
 	}
 	if dns := job.GetenvList("Dns"); dns != nil {
 	if dns := job.GetenvList("Dns"); dns != nil {
 		config.Dns = dns
 		config.Dns = dns

+ 1 - 1
docker/docker.go

@@ -149,7 +149,7 @@ func main() {
 			job.Setenv("GraphDriver", *flGraphDriver)
 			job.Setenv("GraphDriver", *flGraphDriver)
 			job.Setenv("ExecDriver", *flExecDriver)
 			job.Setenv("ExecDriver", *flExecDriver)
 			job.SetenvInt("Mtu", *flMtu)
 			job.SetenvInt("Mtu", *flMtu)
-			job.SetenvBool("SelinuxEnabled", *flSelinuxEnabled)
+			job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled)
 			if err := job.Run(); err != nil {
 			if err := job.Run(); err != nil {
 				log.Fatal(err)
 				log.Fatal(err)
 			}
 			}

+ 4 - 0
pkg/label/label.go

@@ -24,3 +24,7 @@ func GetPidCon(pid int) (string, error) {
 
 
 func Init() {
 func Init() {
 }
 }
+
+func ReserveLabel(label string) error {
+	return nil
+}

+ 4 - 0
pkg/label/label_selinux.go

@@ -75,3 +75,7 @@ func GetPidCon(pid int) (string, error) {
 func Init() {
 func Init() {
 	selinux.SelinuxEnabled()
 	selinux.SelinuxEnabled()
 }
 }
+
+func ReserveLabel(label string) {
+	selinux.ReserveLabel(label)
+}

+ 24 - 4
pkg/selinux/selinux.go

@@ -204,6 +204,13 @@ func NewContext(scon string) SELinuxContext {
 	return c
 	return c
 }
 }
 
 
+func ReserveLabel(scon string) {
+	if len(scon) != 0 {
+		con := strings.SplitN(scon, ":", 4)
+		mcsAdd(con[3])
+	}
+}
+
 func SelinuxGetEnforce() int {
 func SelinuxGetEnforce() int {
 	var enforce int
 	var enforce int
 
 
@@ -229,8 +236,12 @@ func SelinuxGetEnforceMode() int {
 	return Disabled
 	return Disabled
 }
 }
 
 
-func mcsAdd(mcs string) {
+func mcsAdd(mcs string) error {
+	if mcsList[mcs] {
+		return fmt.Errorf("MCS Label already exists")
+	}
 	mcsList[mcs] = true
 	mcsList[mcs] = true
+	return nil
 }
 }
 
 
 func mcsDelete(mcs string) {
 func mcsDelete(mcs string) {
@@ -283,15 +294,21 @@ func uniqMcs(catRange uint32) string {
 			}
 			}
 		}
 		}
 		mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
 		mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
-		if mcsExists(mcs) {
+		if err := mcsAdd(mcs); err != nil {
 			continue
 			continue
 		}
 		}
-		mcsAdd(mcs)
 		break
 		break
 	}
 	}
 	return mcs
 	return mcs
 }
 }
 
 
+func FreeLxcContexts(scon string) {
+	if len(scon) != 0 {
+		con := strings.SplitN(scon, ":", 4)
+		mcsDelete(con[3])
+	}
+}
+
 func GetLxcContexts() (processLabel string, fileLabel string) {
 func GetLxcContexts() (processLabel string, fileLabel string) {
 	var (
 	var (
 		val, key string
 		val, key string
@@ -344,7 +361,8 @@ func GetLxcContexts() (processLabel string, fileLabel string) {
 	}
 	}
 
 
 exit:
 exit:
-	mcs := IntToMcs(os.Getpid(), 1024)
+	//	mcs := IntToMcs(os.Getpid(), 1024)
+	mcs := uniqMcs(1024)
 	scon := NewContext(processLabel)
 	scon := NewContext(processLabel)
 	scon["level"] = mcs
 	scon["level"] = mcs
 	processLabel = scon.Get()
 	processLabel = scon.Get()
@@ -373,6 +391,8 @@ func CopyLevel(src, dest string) (string, error) {
 	}
 	}
 	scon := NewContext(src)
 	scon := NewContext(src)
 	tcon := NewContext(dest)
 	tcon := NewContext(dest)
+	mcsDelete(tcon["level"])
+	mcsAdd(scon["level"])
 	tcon["level"] = scon["level"]
 	tcon["level"] = scon["level"]
 	return tcon.Get(), nil
 	return tcon.Get(), nil
 }
 }

+ 2 - 0
pkg/selinux/selinux_test.go

@@ -31,9 +31,11 @@ func TestSELinux(t *testing.T) {
 		plabel, flabel = selinux.GetLxcContexts()
 		plabel, flabel = selinux.GetLxcContexts()
 		t.Log(plabel)
 		t.Log(plabel)
 		t.Log(flabel)
 		t.Log(flabel)
+		selinux.FreeLxcContexts(plabel)
 		plabel, flabel = selinux.GetLxcContexts()
 		plabel, flabel = selinux.GetLxcContexts()
 		t.Log(plabel)
 		t.Log(plabel)
 		t.Log(flabel)
 		t.Log(flabel)
+		selinux.FreeLxcContexts(plabel)
 		t.Log("getenforce ", selinux.SelinuxGetEnforce())
 		t.Log("getenforce ", selinux.SelinuxGetEnforce())
 		t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
 		t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
 		pid := os.Getpid()
 		pid := os.Getpid()