Browse code

add default seccomp profile tests

Signed-off-by: Jessica Frazelle <acidburn@docker.com>

Jessica Frazelle authored on 2015/12/22 07:42:58
Showing 8 changed files
... ...
@@ -197,6 +197,7 @@ RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
197 197
 COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
198 198
 RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
199 199
 	busybox:latest@sha256:eb3c0d4680f9213ee5f348ea6d39489a1f85a318a2ae09e012c426f78252a6d2 \
200
+	debian:jessie@sha256:24a900d1671b269d6640b4224e7b63801880d8e3cb2bcbfaa10a5dddcf4469ed \
200 201
 	hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 \
201 202
 	jess/unshare:latest@sha256:2e3a8c0591c4690b82d4eba7e5ef8f49f2ddfe9f867f3e865198db9bd1436c5b
202 203
 # see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
203 204
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+FROM debian:jessie
1
+COPY userns-test .
2
+ENTRYPOINT ["./userns-test"]
0 3
new file mode 100644
... ...
@@ -0,0 +1,54 @@
0
+#define _GNU_SOURCE
1
+#include <sched.h>
2
+#include <unistd.h>
3
+#include <stdlib.h>
4
+#include <sys/wait.h>
5
+#include <signal.h>
6
+#include <fcntl.h>
7
+#include <stdio.h>
8
+#include <string.h>
9
+#include <limits.h>
10
+#include <errno.h>
11
+
12
+#define STACKSIZE (1024*1024)
13
+static char child_stack[STACKSIZE];
14
+
15
+struct clone_args {
16
+	char **argv;
17
+};
18
+
19
+// child_exec is the func that will be executed as the result of clone
20
+static int child_exec(void *stuff)
21
+{
22
+	struct clone_args *args = (struct clone_args *)stuff;
23
+	if (execvp(args->argv[0], args->argv) != 0) {
24
+		fprintf(stderr, "failed to execvp argments %s\n",
25
+			strerror(errno));
26
+		exit(-1);
27
+	}
28
+	// we should never reach here!
29
+	exit(EXIT_FAILURE);
30
+}
31
+
32
+int main(int argc, char **argv)
33
+{
34
+	struct clone_args args;
35
+	args.argv = &argv[1];
36
+
37
+	int clone_flags = CLONE_NEWUSER | SIGCHLD;
38
+
39
+	// the result of this call is that our child_exec will be run in another
40
+	// process returning it's pid
41
+	pid_t pid =
42
+	    clone(child_exec, child_stack + STACKSIZE, clone_flags, &args);
43
+	if (pid < 0) {
44
+		fprintf(stderr, "clone failed: %s\n", strerror(errno));
45
+		exit(EXIT_FAILURE);
46
+	}
47
+	// lets wait on our child process here before we, the parent, exits
48
+	if (waitpid(pid, NULL, 0) == -1) {
49
+		fprintf(stderr, "failed to wait pid %d\n", pid);
50
+		exit(EXIT_FAILURE);
51
+	}
52
+	exit(EXIT_SUCCESS);
53
+}
... ...
@@ -27,6 +27,7 @@ case "$DOCKER_ENGINE_OSARCH" in
27 27
 	*)
28 28
 		images=(
29 29
 			busybox:latest
30
+			debian:jessie
30 31
 			hello-world:latest
31 32
 			jess/unshare:latest
32 33
 		)
33 34
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+#!/bin/bash
1
+set -e
2
+
3
+# Build a C binary for cloning a userns for seccomp tests
4
+# and compile it for target daemon
5
+
6
+dir="$DEST/userns-test"
7
+mkdir -p "$dir"
8
+(
9
+	GOOS=${DOCKER_ENGINE_GOOS:="linux"}
10
+	if [ "$GOOS" = "linux" ]; then
11
+		cd "$dir"
12
+		gcc -g -Wall -static ../../../../contrib/userns-test/main.c -o ./userns-test
13
+		cp ../../../../contrib/userns-test/Dockerfile .
14
+		docker build -qt userns-test . > /dev/null
15
+	fi
16
+)
17
+rm -rf "$dir"
... ...
@@ -3,3 +3,4 @@
3 3
 bundle .ensure-emptyfs
4 4
 bundle .ensure-frozen-images
5 5
 bundle .ensure-httpserver
6
+bundle .ensure-userns-test
... ...
@@ -2858,7 +2858,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
2858 2858
 	testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace)
2859 2859
 
2860 2860
 	name := "acidburn"
2861
-	out, _, err := dockerCmdWithError("run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
2861
+	out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
2862 2862
 	if err == nil ||
2863 2863
 		!(strings.Contains(strings.ToLower(out), "permission denied") ||
2864 2864
 			strings.Contains(strings.ToLower(out), "operation not permitted")) {
... ...
@@ -2866,7 +2866,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
2866 2866
 	}
2867 2867
 
2868 2868
 	name = "cereal"
2869
-	out, _, err = dockerCmdWithError("run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
2869
+	out, _, err = dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
2870 2870
 	if err == nil ||
2871 2871
 		!(strings.Contains(strings.ToLower(out), "permission denied") ||
2872 2872
 			strings.Contains(strings.ToLower(out), "operation not permitted")) {
... ...
@@ -2875,7 +2875,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
2875 2875
 
2876 2876
 	/* Ensure still fails if running privileged with the default policy */
2877 2877
 	name = "crashoverride"
2878
-	out, _, err = dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
2878
+	out, _, err = dockerCmdWithError("run", "--privileged", "--security-opt", "seccomp:unconfined", "--security-opt", "apparmor:docker-default", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
2879 2879
 	if err == nil || !(strings.Contains(strings.ToLower(out), "permission denied") || strings.Contains(strings.ToLower(out), "operation not permitted")) {
2880 2880
 		c.Fatalf("privileged unshare with apparmor should have failed with permission denied, got: %s, %v", out, err)
2881 2881
 	}
... ...
@@ -514,7 +514,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
514 514
 	if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
515 515
 		c.Fatal(err)
516 516
 	}
517
-	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:"+tmpFile.Name(), "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
517
+	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
518 518
 	out, _, _ := runCommandWithOutput(runCmd)
519 519
 	if !strings.Contains(out, "Operation not permitted") {
520 520
 		c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out)
... ...
@@ -549,8 +549,9 @@ func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
549 549
 	}
550 550
 }
551 551
 
552
-// TestRunSeccompProfileDenyUserns checks that 'docker run jess/unshare unshare --map-root-user --user sh -c whoami' exits with operation not permitted.
553
-func (s *DockerSuite) TestRunSeccompProfileDenyUserns(c *check.C) {
552
+// TestRunSeccompProfileDenyUnshareUserns checks that 'docker run jess/unshare unshare --map-root-user --user sh -c whoami' with a specific profile to
553
+// deny unhare of a userns exits with operation not permitted.
554
+func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
554 555
 	testRequires(c, SameHostDaemon, seccompEnabled)
555 556
 	// from sched.h
556 557
 	jsonData := fmt.Sprintf(`{
... ...
@@ -578,9 +579,44 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUserns(c *check.C) {
578 578
 	if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
579 579
 		c.Fatal(err)
580 580
 	}
581
-	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:"+tmpFile.Name(), "jess/unshare", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
581
+	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
582 582
 	out, _, _ := runCommandWithOutput(runCmd)
583 583
 	if !strings.Contains(out, "Operation not permitted") {
584 584
 		c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out)
585 585
 	}
586 586
 }
587
+
588
+// TestRunSeccompProfileDenyCloneUserns checks that 'docker run userns-test'
589
+// with a the default seccomp profile exits with operation not permitted.
590
+func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) {
591
+	testRequires(c, SameHostDaemon, seccompEnabled)
592
+
593
+	runCmd := exec.Command(dockerBinary, "run", "userns-test", "id")
594
+	out, _, err := runCommandWithOutput(runCmd)
595
+	if err == nil || !strings.Contains(out, "clone failed: Operation not permitted") {
596
+		c.Fatalf("expected clone userns with default seccomp profile denied to fail, got %s: %v", out, err)
597
+	}
598
+}
599
+
600
+// TestRunSeccompAllowPrivCloneUserns checks that 'docker run userns-test'
601
+// with a the default seccomp profile exits with operation not permitted.
602
+func (s *DockerSuite) TestRunSeccompAllowPrivCloneUserns(c *check.C) {
603
+	testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace)
604
+
605
+	// make sure running w privileged is ok
606
+	runCmd := exec.Command(dockerBinary, "run", "--privileged", "userns-test", "id")
607
+	if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") {
608
+		c.Fatalf("expected clone userns with --privileged to succeed, got %s: %v", out, err)
609
+	}
610
+}
611
+
612
+// TestRunSeccompAllowAptKey checks that 'docker run debian:jessie apt-key' succeeds.
613
+func (s *DockerSuite) TestRunSeccompAllowAptKey(c *check.C) {
614
+	testRequires(c, SameHostDaemon, seccompEnabled)
615
+
616
+	// apt-key uses setrlimit & getrlimit, so we want to make sure we don't break it
617
+	runCmd := exec.Command(dockerBinary, "run", "debian:jessie", "apt-key", "adv", "--keyserver", "hkp://p80.pool.sks-keyservers.net:80", "--recv-keys", "E871F18B51E0147C77796AC81196BA81F6B0FC61")
618
+	if out, _, err := runCommandWithOutput(runCmd); err != nil {
619
+		c.Fatalf("expected apt-key with seccomp to succeed, got %s: %v", out, err)
620
+	}
621
+}