From f156fb7be5e23128a1dc682f2c86a7f2f2907e98 Mon Sep 17 00:00:00 2001 From: Eric Windisch Date: Thu, 30 Jul 2015 12:54:21 -0400 Subject: [PATCH] Only explicitly deny ptrace for container-originated procs The 'deny ptrace' statement was supposed to only ignore ptrace failures in the AUDIT log. However, ptrace was implicitly allowed from unconfined processes (such as the docker daemon and its integration tests) due to the abstractions/base include. This rule narrows the definition such that it will only ignore the failures originating inside of the container and will not cause denials when the daemon or its tests ptrace inside processes. Introduces positive and negative tests for ptrace /w apparmor. Signed-off-by: Eric Windisch (cherry picked from commit f5c388b35a9ddd699b3dbbe85b80fa02234f8355) --- daemon/execdriver/native/apparmor.go | 2 +- integration-cli/docker_cli_run_test.go | 39 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/daemon/execdriver/native/apparmor.go b/daemon/execdriver/native/apparmor.go index ecbaf3351..9d166fb93 100644 --- a/daemon/execdriver/native/apparmor.go +++ b/daemon/execdriver/native/apparmor.go @@ -50,7 +50,7 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { deny @{PROC}/sys/kernel/*/** wklx, deny mount, - deny ptrace, + deny ptrace (trace) peer=docker-default, deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 841480e9f..2c27cd9d7 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -2729,3 +2729,42 @@ func (s *DockerTrustSuite) TestTrustedRunFromBadTrustServer(c *check.C) { c.Fatalf("Missing expected output on trusted push:\n%s", out) } } + +func (s *DockerSuite) TestPtraceContainerProcsFromHost(c *check.C) { + testRequires(c, SameHostDaemon) + + out, _ := dockerCmd(c, "run", "-d", "busybox", "top") + id := strings.TrimSpace(out) + if err := waitRun(id); err != nil { + c.Fatal(err) + } + pid1, err := inspectField(id, "State.Pid") + c.Assert(err, check.IsNil) + + _, err = os.Readlink(fmt.Sprintf("/proc/%s/ns/net", pid1)) + if err != nil { + c.Fatal(err) + } +} + +func (s *DockerSuite) TestAppArmorDeniesPtrace(c *check.C) { + testRequires(c, SameHostDaemon) + testRequires(c, Apparmor) + + // Run through 'sh' so we are NOT pid 1. Pid 1 may be able to trace + // itself, but pid>1 should not be able to trace pid1. + _, exitCode, _ := dockerCmdWithError("run", "busybox", "sh", "-c", "readlink /proc/1/ns/net") + if exitCode == 0 { + c.Fatal("ptrace was not successfully restricted by AppArmor") + } +} + +func (s *DockerSuite) TestAppArmorTraceSelf(c *check.C) { + testRequires(c, SameHostDaemon) + testRequires(c, Apparmor) + + _, exitCode, _ := dockerCmdWithError("run", "busybox", "readlink", "/proc/1/ns/net") + if exitCode != 0 { + c.Fatal("ptrace of self failed.") + } +}