Browse code

add check for invalid caps

Docker-DCO-1.1-Signed-off-by: Victor Vieux <vieux@docker.com> (github: vieux)

Victor Vieux authored on 2014/07/11 08:38:11
Showing 4 changed files
... ...
@@ -49,7 +49,10 @@ func finalizeNamespace(args *execdriver.InitArgs) error {
49 49
 			return fmt.Errorf("clear keep caps %s", err)
50 50
 		}
51 51
 
52
-		caps := execdriver.TweakCapabilities(container.Capabilities, strings.Split(args.CapAdd, " "), strings.Split(args.CapDrop, " "))
52
+		caps, err := execdriver.TweakCapabilities(container.Capabilities, strings.Split(args.CapAdd, " "), strings.Split(args.CapDrop, " "))
53
+		if err != nil {
54
+			return err
55
+		}
53 56
 
54 57
 		// drop all other capabilities
55 58
 		if err := capabilities.DropCapabilities(caps); err != nil {
... ...
@@ -43,7 +43,9 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e
43 43
 			return nil, err
44 44
 		}
45 45
 	} else {
46
-		d.setCapabilities(container, c)
46
+		if err := d.setCapabilities(container, c); err != nil {
47
+			return nil, err
48
+		}
47 49
 	}
48 50
 
49 51
 	if err := d.setupCgroups(container, c); err != nil {
... ...
@@ -138,8 +140,9 @@ func (d *driver) setPrivileged(container *libcontainer.Config) (err error) {
138 138
 	return nil
139 139
 }
140 140
 
141
-func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) {
142
-	container.Capabilities = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
141
+func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) (err error) {
142
+	container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
143
+	return err
143 144
 }
144 145
 
145 146
 func (d *driver) setupCgroups(container *libcontainer.Config, c *execdriver.Command) error {
... ...
@@ -1,34 +1,63 @@
1 1
 package execdriver
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"strings"
5 6
 
6 7
 	"github.com/docker/libcontainer/security/capabilities"
7 8
 	"github.com/dotcloud/docker/utils"
8 9
 )
9 10
 
10
-func TweakCapabilities(basics, adds, drops []string) []string {
11
-	var caps []string
11
+func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
12
+	var (
13
+		newCaps []string
14
+		allCaps = capabilities.GetAllCapabilities()
15
+	)
12 16
 
17
+	// look for invalid cap in the drop list
18
+	for _, cap := range drops {
19
+		if strings.ToLower(cap) == "all" {
20
+			continue
21
+		}
22
+		if !utils.StringsContainsNoCase(allCaps, cap) {
23
+			return nil, fmt.Errorf("Unknown capability: %s", cap)
24
+		}
25
+	}
26
+
27
+	// handle --cap-add=all
13 28
 	if utils.StringsContainsNoCase(adds, "all") {
14 29
 		basics = capabilities.GetAllCapabilities()
15 30
 	}
16 31
 
17 32
 	if !utils.StringsContainsNoCase(drops, "all") {
18 33
 		for _, cap := range basics {
34
+			// skip `all` aready handled above
35
+			if strings.ToLower(cap) == "all" {
36
+				continue
37
+			}
38
+
39
+			// if we don't drop `all`, add back all the non-dropped caps
19 40
 			if !utils.StringsContainsNoCase(drops, cap) {
20
-				caps = append(caps, cap)
41
+				newCaps = append(newCaps, cap)
21 42
 			}
22 43
 		}
23 44
 	}
24 45
 
25 46
 	for _, cap := range adds {
47
+		// skip `all` aready handled above
26 48
 		if strings.ToLower(cap) == "all" {
27 49
 			continue
28 50
 		}
29
-		if !utils.StringsContainsNoCase(caps, cap) {
30
-			caps = append(caps, cap)
51
+
52
+		// look for invalid cap in the drop list
53
+		if !utils.StringsContainsNoCase(allCaps, cap) {
54
+			return nil, fmt.Errorf("Unknown capability: %s", cap)
55
+		}
56
+
57
+		// add cap if not already in the list
58
+		if !utils.StringsContainsNoCase(newCaps, cap) {
59
+			newCaps = append(newCaps, cap)
31 60
 		}
32 61
 	}
33
-	return caps
62
+	return newCaps, nil
34 63
 }
... ...
@@ -783,6 +783,16 @@ func TestUnPrivilegedCanMknod(t *testing.T) {
783 783
 	logDone("run - test un-privileged can mknod")
784 784
 }
785 785
 
786
+func TestCapDropInvalid(t *testing.T) {
787
+	cmd := exec.Command(dockerBinary, "run", "--cap-drop=CHPASS", "busybox", "ls")
788
+	out, _, err := runCommandWithOutput(cmd)
789
+	if err == nil {
790
+		t.Fatal(err, out)
791
+	}
792
+
793
+	logDone("run - test --cap-drop=CHPASS invalid")
794
+}
795
+
786 796
 func TestCapDropCannotMknod(t *testing.T) {
787 797
 	cmd := exec.Command(dockerBinary, "run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
788 798
 	out, _, err := runCommandWithOutput(cmd)
... ...
@@ -814,7 +824,7 @@ func TestCapDropALLCannotMknod(t *testing.T) {
814 814
 }
815 815
 
816 816
 func TestCapDropALLAddMknodCannotMknod(t *testing.T) {
817
-	cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL --cap-add=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
817
+	cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
818 818
 	out, _, err := runCommandWithOutput(cmd)
819 819
 	if err != nil {
820 820
 		t.Fatal(err, out)
... ...
@@ -828,6 +838,16 @@ func TestCapDropALLAddMknodCannotMknod(t *testing.T) {
828 828
 	logDone("run - test --cap-drop=ALL --cap-add=MKNOD can mknod")
829 829
 }
830 830
 
831
+func TestCapAddInvalid(t *testing.T) {
832
+	cmd := exec.Command(dockerBinary, "run", "--cap-add=CHPASS", "busybox", "ls")
833
+	out, _, err := runCommandWithOutput(cmd)
834
+	if err == nil {
835
+		t.Fatal(err, out)
836
+	}
837
+
838
+	logDone("run - test --cap-add=CHPASS invalid")
839
+}
840
+
831 841
 func TestCapAddCanDownInterface(t *testing.T) {
832 842
 	cmd := exec.Command(dockerBinary, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
833 843
 	out, _, err := runCommandWithOutput(cmd)
... ...
@@ -859,7 +879,7 @@ func TestCapAddALLCanDownInterface(t *testing.T) {
859 859
 }
860 860
 
861 861
 func TestCapAddALLDropNetAdminCanDownInterface(t *testing.T) {
862
-	cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL --cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
862
+	cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
863 863
 	out, _, err := runCommandWithOutput(cmd)
864 864
 	if err == nil {
865 865
 		t.Fatal(err, out)