Browse code

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 authored on 2014/04/22 06:09:26
Showing 8 changed files
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	"github.com/dotcloud/docker/image"
12 12
 	"github.com/dotcloud/docker/links"
13 13
 	"github.com/dotcloud/docker/nat"
14
-	"github.com/dotcloud/docker/pkg/selinux"
14
+	"github.com/dotcloud/docker/pkg/label"
15 15
 	"github.com/dotcloud/docker/runconfig"
16 16
 	"github.com/dotcloud/docker/utils"
17 17
 	"io"
... ...
@@ -66,7 +66,7 @@ type Container struct {
66 66
 	stdinPipe io.WriteCloser
67 67
 
68 68
 	daemon                   *Daemon
69
-	mountLabel, processLabel string
69
+	MountLabel, ProcessLabel string
70 70
 
71 71
 	waitLock chan struct{}
72 72
 	Volumes  map[string]string
... ...
@@ -124,6 +124,7 @@ func (container *Container) FromDisk() error {
124 124
 	if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") {
125 125
 		return err
126 126
 	}
127
+	label.ReserveLabel(container.ProcessLabel)
127 128
 	return container.readHostConfig()
128 129
 }
129 130
 
... ...
@@ -325,8 +326,8 @@ func populateCommand(c *Container, env []string) {
325 325
 		en      *execdriver.Network
326 326
 		context = make(map[string][]string)
327 327
 	)
328
-	context["process_label"] = []string{c.processLabel}
329
-	context["mount_label"] = []string{c.mountLabel}
328
+	context["process_label"] = []string{c.ProcessLabel}
329
+	context["mount_label"] = []string{c.MountLabel}
330 330
 
331 331
 	en = &execdriver.Network{
332 332
 		Mtu:       c.daemon.config.Mtu,
... ...
@@ -388,10 +389,13 @@ func (container *Container) Start() (err error) {
388 388
 		return err
389 389
 	}
390 390
 
391
-	process, mount := selinux.GetLxcContexts()
391
+	process, mount, err := label.GenLabels("")
392
+	if err != nil {
393
+		return err
394
+	}
392 395
 
393
-	container.mountLabel = mount
394
-	container.processLabel = process
396
+	container.MountLabel = mount
397
+	container.ProcessLabel = process
395 398
 
396 399
 	if err := container.Mount(); err != nil {
397 400
 		return err
... ...
@@ -289,6 +289,8 @@ func (daemon *Daemon) Destroy(container *Container) error {
289 289
 	if err := os.RemoveAll(container.root); err != nil {
290 290
 		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
291 291
 	}
292
+	selinux.FreeLxcContexts(container.ProcessLabel)
293
+
292 294
 	return nil
293 295
 }
294 296
 
... ...
@@ -839,7 +841,7 @@ func (daemon *Daemon) Close() error {
839 839
 }
840 840
 
841 841
 func (daemon *Daemon) Mount(container *Container) error {
842
-	dir, err := daemon.driver.Get(container.ID, container.mountLabel)
842
+	dir, err := daemon.driver.Get(container.ID, container.MountLabel)
843 843
 	if err != nil {
844 844
 		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err)
845 845
 	}
... ...
@@ -47,7 +47,7 @@ func ConfigFromJob(job *engine.Job) *Config {
47 47
 		InterContainerCommunication: job.GetenvBool("InterContainerCommunication"),
48 48
 		GraphDriver:                 job.Getenv("GraphDriver"),
49 49
 		ExecDriver:                  job.Getenv("ExecDriver"),
50
-		EnableSelinuxSupport:        job.GetenvBool("SelinuxEnabled"),
50
+		EnableSelinuxSupport:        job.GetenvBool("EnableSelinuxSupport"),
51 51
 	}
52 52
 	if dns := job.GetenvList("Dns"); dns != nil {
53 53
 		config.Dns = dns
... ...
@@ -149,7 +149,7 @@ func main() {
149 149
 			job.Setenv("GraphDriver", *flGraphDriver)
150 150
 			job.Setenv("ExecDriver", *flExecDriver)
151 151
 			job.SetenvInt("Mtu", *flMtu)
152
-			job.SetenvBool("SelinuxEnabled", *flSelinuxEnabled)
152
+			job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled)
153 153
 			if err := job.Run(); err != nil {
154 154
 				log.Fatal(err)
155 155
 			}
... ...
@@ -24,3 +24,7 @@ func GetPidCon(pid int) (string, error) {
24 24
 
25 25
 func Init() {
26 26
 }
27
+
28
+func ReserveLabel(label string) error {
29
+	return nil
30
+}
... ...
@@ -75,3 +75,7 @@ func GetPidCon(pid int) (string, error) {
75 75
 func Init() {
76 76
 	selinux.SelinuxEnabled()
77 77
 }
78
+
79
+func ReserveLabel(label string) {
80
+	selinux.ReserveLabel(label)
81
+}
... ...
@@ -204,6 +204,13 @@ func NewContext(scon string) SELinuxContext {
204 204
 	return c
205 205
 }
206 206
 
207
+func ReserveLabel(scon string) {
208
+	if len(scon) != 0 {
209
+		con := strings.SplitN(scon, ":", 4)
210
+		mcsAdd(con[3])
211
+	}
212
+}
213
+
207 214
 func SelinuxGetEnforce() int {
208 215
 	var enforce int
209 216
 
... ...
@@ -229,8 +236,12 @@ func SelinuxGetEnforceMode() int {
229 229
 	return Disabled
230 230
 }
231 231
 
232
-func mcsAdd(mcs string) {
232
+func mcsAdd(mcs string) error {
233
+	if mcsList[mcs] {
234
+		return fmt.Errorf("MCS Label already exists")
235
+	}
233 236
 	mcsList[mcs] = true
237
+	return nil
234 238
 }
235 239
 
236 240
 func mcsDelete(mcs string) {
... ...
@@ -283,15 +294,21 @@ func uniqMcs(catRange uint32) string {
283 283
 			}
284 284
 		}
285 285
 		mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
286
-		if mcsExists(mcs) {
286
+		if err := mcsAdd(mcs); err != nil {
287 287
 			continue
288 288
 		}
289
-		mcsAdd(mcs)
290 289
 		break
291 290
 	}
292 291
 	return mcs
293 292
 }
294 293
 
294
+func FreeLxcContexts(scon string) {
295
+	if len(scon) != 0 {
296
+		con := strings.SplitN(scon, ":", 4)
297
+		mcsDelete(con[3])
298
+	}
299
+}
300
+
295 301
 func GetLxcContexts() (processLabel string, fileLabel string) {
296 302
 	var (
297 303
 		val, key string
... ...
@@ -344,7 +361,8 @@ func GetLxcContexts() (processLabel string, fileLabel string) {
344 344
 	}
345 345
 
346 346
 exit:
347
-	mcs := IntToMcs(os.Getpid(), 1024)
347
+	//	mcs := IntToMcs(os.Getpid(), 1024)
348
+	mcs := uniqMcs(1024)
348 349
 	scon := NewContext(processLabel)
349 350
 	scon["level"] = mcs
350 351
 	processLabel = scon.Get()
... ...
@@ -373,6 +391,8 @@ func CopyLevel(src, dest string) (string, error) {
373 373
 	}
374 374
 	scon := NewContext(src)
375 375
 	tcon := NewContext(dest)
376
+	mcsDelete(tcon["level"])
377
+	mcsAdd(scon["level"])
376 378
 	tcon["level"] = scon["level"]
377 379
 	return tcon.Get(), nil
378 380
 }
... ...
@@ -31,9 +31,11 @@ func TestSELinux(t *testing.T) {
31 31
 		plabel, flabel = selinux.GetLxcContexts()
32 32
 		t.Log(plabel)
33 33
 		t.Log(flabel)
34
+		selinux.FreeLxcContexts(plabel)
34 35
 		plabel, flabel = selinux.GetLxcContexts()
35 36
 		t.Log(plabel)
36 37
 		t.Log(flabel)
38
+		selinux.FreeLxcContexts(plabel)
37 39
 		t.Log("getenforce ", selinux.SelinuxGetEnforce())
38 40
 		t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
39 41
 		pid := os.Getpid()