From d87da59c79eabb794087f731d3ad51ea98f7a3cc Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 20 Apr 2015 11:58:24 -0700 Subject: [PATCH 1/8] Prevent write access to /proc/asound Signed-off-by: Michael Crosby Conflicts: integration-cli/docker_cli_run_test.go --- .../native/template/default_template.go | 6 +++++- integration-cli/docker_cli_run_test.go | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/daemon/execdriver/native/template/default_template.go b/daemon/execdriver/native/template/default_template.go index 76e3cea787..530bd95960 100644 --- a/daemon/execdriver/native/template/default_template.go +++ b/daemon/execdriver/native/template/default_template.go @@ -84,7 +84,11 @@ func New() *configs.Config { "/proc/kcore", }, ReadonlyPaths: []string{ - "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", + "/proc/asound", + "/proc/bus", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger", }, } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 626cc3583a..3e01fb1a29 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3056,3 +3056,24 @@ func (s *DockerSuite) TestRunPidHostWithChildIsKillable(c *check.C) { c.Fatal("Kill container timed out") } } + +func TestRunWithTooSmallMemoryLimit(t *testing.T) { + defer deleteAllContainers() + // this memory limit is 1 byte less than the min, which is 4MB + // https://github.com/docker/docker/blob/v1.5.0/daemon/create.go#L22 + out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-m", "4194303", "busybox")) + if err == nil || !strings.Contains(out, "Minimum memory limit allowed is 4MB") { + t.Fatalf("expected run to fail when using too low a memory limit: %q", out) + } + + logDone("run - can't set too low memory limit") +} + +func TestRunWriteToProcAsound(t *testing.T) { + defer deleteAllContainers() + code, err := runCommand(exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo 111 >> /proc/asound/version")) + if err == nil || code == 0 { + t.Fatal("standard container should not be able to write to /proc/asound") + } + logDone("run - ro write to /proc/asound") +} From 42c8c1b0b884c91efa518568181d276afd9d866f Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 20 Apr 2015 13:33:51 -0700 Subject: [PATCH 2/8] Mount /proc/fs as readonly Signed-off-by: Michael Crosby --- daemon/execdriver/native/template/default_template.go | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon/execdriver/native/template/default_template.go b/daemon/execdriver/native/template/default_template.go index 530bd95960..5e48e623ef 100644 --- a/daemon/execdriver/native/template/default_template.go +++ b/daemon/execdriver/native/template/default_template.go @@ -86,6 +86,7 @@ func New() *configs.Config { ReadonlyPaths: []string{ "/proc/asound", "/proc/bus", + "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger", From 27ae108b4eda48a621afc5bf2157ef11c314a858 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 20 Apr 2015 13:54:49 -0700 Subject: [PATCH 3/8] Mount RO for timer_stats and latency_stats in proc Signed-off-by: Michael Crosby --- .../native/template/default_template.go | 2 ++ integration-cli/docker_cli_run_test.go | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/daemon/execdriver/native/template/default_template.go b/daemon/execdriver/native/template/default_template.go index 5e48e623ef..e14be6aee5 100644 --- a/daemon/execdriver/native/template/default_template.go +++ b/daemon/execdriver/native/template/default_template.go @@ -88,8 +88,10 @@ func New() *configs.Config { "/proc/bus", "/proc/fs", "/proc/irq", + "/proc/latency_stats", "/proc/sys", "/proc/sysrq-trigger", + "/proc/timer_stats", }, } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 3e01fb1a29..d94ebe7851 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3077,3 +3077,21 @@ func TestRunWriteToProcAsound(t *testing.T) { } logDone("run - ro write to /proc/asound") } + +func TestRunWriteToProcTimer(t *testing.T) { + defer deleteAllContainers() + code, err := runCommand(exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo 1 >> /proc/timer_stats")) + if err == nil || code == 0 { + t.Fatal("standard container should not be able to write to /proc/timer_stats") + } + logDone("run - ro write to /proc/timer_stats") +} + +func TestRunWriteToProcLatency(t *testing.T) { + defer deleteAllContainers() + code, err := runCommand(exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo 1 >> /proc/latency_stats")) + if err == nil || code == 0 { + t.Fatal("standard container should not be able to write to /proc/latency_stats") + } + logDone("run - ro write to /proc/latency_stats") +} From a7a51306b1459a67da3a9cbbe8c9f80d3950c084 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 29 Apr 2015 11:20:31 -0700 Subject: [PATCH 4/8] Mask reads from timer_stats and latency_stats These files in /proc should not be able to be read as well as written to. Signed-off-by: Michael Crosby --- .../native/template/default_template.go | 4 +-- integration-cli/docker_cli_run_test.go | 34 +++++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/daemon/execdriver/native/template/default_template.go b/daemon/execdriver/native/template/default_template.go index e14be6aee5..ecedcfc8cb 100644 --- a/daemon/execdriver/native/template/default_template.go +++ b/daemon/execdriver/native/template/default_template.go @@ -82,16 +82,16 @@ func New() *configs.Config { }, MaskPaths: []string{ "/proc/kcore", + "/proc/latency_stats", + "/proc/timer_stats", }, ReadonlyPaths: []string{ "/proc/asound", "/proc/bus", "/proc/fs", "/proc/irq", - "/proc/latency_stats", "/proc/sys", "/proc/sysrq-trigger", - "/proc/timer_stats", }, } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index d94ebe7851..3b6c2e77e7 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3078,20 +3078,32 @@ func TestRunWriteToProcAsound(t *testing.T) { logDone("run - ro write to /proc/asound") } -func TestRunWriteToProcTimer(t *testing.T) { +func TestRunReadProcTimer(t *testing.T) { defer deleteAllContainers() - code, err := runCommand(exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo 1 >> /proc/timer_stats")) - if err == nil || code == 0 { - t.Fatal("standard container should not be able to write to /proc/timer_stats") + out, code, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "busybox", "cat", "/proc/timer_stats")) + if err != nil || code != 0 { + t.Fatal(err) } - logDone("run - ro write to /proc/timer_stats") + if strings.Trim(out, "\n ") != "" { + t.Fatalf("expected to receive no output from /proc/timer_stats but received %q", out) + } + logDone("run - read /proc/timer_stats") } -func TestRunWriteToProcLatency(t *testing.T) { - defer deleteAllContainers() - code, err := runCommand(exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo 1 >> /proc/latency_stats")) - if err == nil || code == 0 { - t.Fatal("standard container should not be able to write to /proc/latency_stats") +func TestRunReadProcLatency(t *testing.T) { + // some kernels don't have this configured so skip the test if this file is not found + // on the host running the tests. + if _, err := os.Stat("/proc/latency_stats"); err != nil { + t.Skip() + return } - logDone("run - ro write to /proc/latency_stats") + defer deleteAllContainers() + out, code, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "busybox", "cat", "/proc/latency_stats")) + if err != nil || code != 0 { + t.Fatal(err) + } + if strings.Trim(out, "\n ") != "" { + t.Fatalf("expected to receive no output from /proc/latency_stats but received %q", out) + } + logDone("run - read /proc/latency_stats") } From 2f54c1a352e23de04a4535d0fc1bd0cad66c7c15 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 30 Apr 2015 13:42:56 -0700 Subject: [PATCH 5/8] Update libcontainer to 1b471834b45063b61e0aedefbb1 Signed-off-by: Michael Crosby --- hack/vendor.sh | 2 +- .../github.com/docker/libcontainer/SPEC.md | 15 +----- .../docker/libcontainer/apparmor/gen.go | 15 +----- .../docker/libcontainer/rootfs_linux.go | 50 ++++++++++++++++--- .../docker/libcontainer/rootfs_linux_test.go | 37 ++++++++++++++ 5 files changed, 82 insertions(+), 37 deletions(-) create mode 100644 vendor/src/github.com/docker/libcontainer/rootfs_linux_test.go diff --git a/hack/vendor.sh b/hack/vendor.sh index 68d04f544a..d1c098f692 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -67,7 +67,7 @@ mv tmp-digest src/github.com/docker/distribution/digest mkdir -p src/github.com/docker/distribution/registry mv tmp-api src/github.com/docker/distribution/registry/api -clone git github.com/docker/libcontainer 6607689b1d06743003a45a722d9fe0bef36b274e +clone git github.com/docker/libcontainer 1b471834b45063b61e0aedefbb1739a8f34b414e # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file) rm -rf src/github.com/docker/libcontainer/vendor eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')" diff --git a/vendor/src/github.com/docker/libcontainer/SPEC.md b/vendor/src/github.com/docker/libcontainer/SPEC.md index d83d758ddd..3ca90d6cd2 100644 --- a/vendor/src/github.com/docker/libcontainer/SPEC.md +++ b/vendor/src/github.com/docker/libcontainer/SPEC.md @@ -217,17 +217,6 @@ profile flags=(attach_disconnected,mediate_deleted) { file, umount, - mount fstype=tmpfs, - mount fstype=mqueue, - mount fstype=fuse.*, - mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/, - mount fstype=efivarfs -> /sys/firmware/efi/efivars/, - mount fstype=fusectl -> /sys/fs/fuse/connections/, - mount fstype=securityfs -> /sys/kernel/security/, - mount fstype=debugfs -> /sys/kernel/debug/, - mount fstype=proc -> /proc/, - mount fstype=sysfs -> /sys/, - deny @{PROC}/sys/fs/** wklx, deny @{PROC}/sysrq-trigger rwklx, deny @{PROC}/mem rwklx, @@ -235,9 +224,7 @@ profile flags=(attach_disconnected,mediate_deleted) { deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, deny @{PROC}/sys/kernel/*/** wklx, - deny mount options=(ro, remount) -> /, - deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/, - deny mount fstype=devpts, + deny mount, deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, diff --git a/vendor/src/github.com/docker/libcontainer/apparmor/gen.go b/vendor/src/github.com/docker/libcontainer/apparmor/gen.go index 4565f6dfec..a3192e23b2 100644 --- a/vendor/src/github.com/docker/libcontainer/apparmor/gen.go +++ b/vendor/src/github.com/docker/libcontainer/apparmor/gen.go @@ -27,17 +27,6 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { file, umount, - mount fstype=tmpfs, - mount fstype=mqueue, - mount fstype=fuse.*, - mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/, - mount fstype=efivarfs -> /sys/firmware/efi/efivars/, - mount fstype=fusectl -> /sys/fs/fuse/connections/, - mount fstype=securityfs -> /sys/kernel/security/, - mount fstype=debugfs -> /sys/kernel/debug/, - mount fstype=proc -> /proc/, - mount fstype=sysfs -> /sys/, - deny @{PROC}/sys/fs/** wklx, deny @{PROC}/sysrq-trigger rwklx, deny @{PROC}/mem rwklx, @@ -45,9 +34,7 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, deny @{PROC}/sys/kernel/*/** wklx, - deny mount options=(ro, remount) -> /, - deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/, - deny mount fstype=devpts, + deny mount, deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, diff --git a/vendor/src/github.com/docker/libcontainer/rootfs_linux.go b/vendor/src/github.com/docker/libcontainer/rootfs_linux.go index d8c61e97a0..0cd60373c8 100644 --- a/vendor/src/github.com/docker/libcontainer/rootfs_linux.go +++ b/vendor/src/github.com/docker/libcontainer/rootfs_linux.go @@ -13,6 +13,7 @@ import ( "syscall" "time" + "github.com/docker/docker/pkg/symlink" "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/label" @@ -48,11 +49,6 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { if err := setupPtmx(config, console); err != nil { return newSystemError(err) } - // stdin, stdout and stderr could be pointing to /dev/null from parent namespace. - // re-open them inside this namespace. - if err := reOpenDevNull(config.Rootfs); err != nil { - return newSystemError(err) - } if err := setupDevSymlinks(config.Rootfs); err != nil { return newSystemError(err) } @@ -67,6 +63,9 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { if err != nil { return newSystemError(err) } + if err := reOpenDevNull(config.Rootfs); err != nil { + return newSystemError(err) + } if config.Readonlyfs { if err := setReadonly(); err != nil { return newSystemError(err) @@ -139,6 +138,16 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { // unable to bind anything to it. return err } + // ensure that the destination of the bind mount is resolved of symlinks at mount time because + // any previous mounts can invalidate the next mount's destination. + // this can happen when a user specifies mounts within other mounts to cause breakouts or other + // evil stuff to try to escape the container's rootfs. + if dest, err = symlink.FollowSymlinkInScope(filepath.Join(rootfs, m.Destination), rootfs); err != nil { + return err + } + if err := checkMountDestination(rootfs, dest); err != nil { + return err + } if err := createIfNotExists(dest, stat.IsDir()); err != nil { return err } @@ -197,6 +206,29 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { return nil } +// checkMountDestination checks to ensure that the mount destination is not over the +// top of /proc or /sys. +// dest is required to be an abs path and have any symlinks resolved before calling this function. +func checkMountDestination(rootfs, dest string) error { + if filepath.Clean(rootfs) == filepath.Clean(dest) { + return fmt.Errorf("mounting into / is prohibited") + } + invalidDestinations := []string{ + "/proc", + "/sys", + } + for _, invalid := range invalidDestinations { + path, err := filepath.Rel(filepath.Join(rootfs, invalid), dest) + if err != nil { + return err + } + if path == "." || !strings.HasPrefix(path, "..") { + return fmt.Errorf("%q cannot be mounted because it is located inside %q", dest, invalid) + } + } + return nil +} + func setupDevSymlinks(rootfs string) error { var links = [][2]string{ {"/proc/self/fd", "/dev/fd"}, @@ -221,11 +253,13 @@ func setupDevSymlinks(rootfs string) error { return nil } -// If stdin, stdout or stderr are pointing to '/dev/null' in the global mount namespace, -// this method will make them point to '/dev/null' in this namespace. +// If stdin, stdout, and/or stderr are pointing to `/dev/null` in the parent's rootfs +// this method will make them point to `/dev/null` in this container's rootfs. This +// needs to be called after we chroot/pivot into the container's rootfs so that any +// symlinks are resolved locally. func reOpenDevNull(rootfs string) error { var stat, devNullStat syscall.Stat_t - file, err := os.Open(filepath.Join(rootfs, "/dev/null")) + file, err := os.Open("/dev/null") if err != nil { return fmt.Errorf("Failed to open /dev/null - %s", err) } diff --git a/vendor/src/github.com/docker/libcontainer/rootfs_linux_test.go b/vendor/src/github.com/docker/libcontainer/rootfs_linux_test.go new file mode 100644 index 0000000000..54df065ccc --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/rootfs_linux_test.go @@ -0,0 +1,37 @@ +// +build linux + +package libcontainer + +import "testing" + +func TestCheckMountDestOnProc(t *testing.T) { + dest := "/rootfs/proc/" + err := checkMountDestination("/rootfs", dest) + if err == nil { + t.Fatal("destination inside proc should return an error") + } +} + +func TestCheckMountDestInSys(t *testing.T) { + dest := "/rootfs//sys/fs/cgroup" + err := checkMountDestination("/rootfs", dest) + if err == nil { + t.Fatal("destination inside proc should return an error") + } +} + +func TestCheckMountDestFalsePositive(t *testing.T) { + dest := "/rootfs/sysfiles/fs/cgroup" + err := checkMountDestination("/rootfs", dest) + if err != nil { + t.Fatal(err) + } +} + +func TestCheckMountRoot(t *testing.T) { + dest := "/rootfs" + err := checkMountDestination("/rootfs", dest) + if err == nil { + t.Fatal(err) + } +} From f25bbedc85e8a99c1389dbe8f48436907ce24526 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 21 Apr 2015 17:31:05 -0700 Subject: [PATCH 6/8] Allow libcontainer to eval symlink destination Signed-off-by: Michael Crosby Add tests for mounting into /proc and /sys These two locations should be prohibited from mounting volumes into those destinations. Signed-off-by: Michael Crosby --- daemon/execdriver/native/create.go | 9 +-------- integration-cli/docker_cli_run_test.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index fbad9f1301..ffec5ec6c3 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -6,12 +6,10 @@ import ( "errors" "fmt" "net" - "path/filepath" "strings" "syscall" "github.com/docker/docker/daemon/execdriver" - "github.com/docker/docker/pkg/symlink" "github.com/docker/libcontainer/apparmor" "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/devices" @@ -231,10 +229,6 @@ func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) e container.Mounts = defaultMounts for _, m := range c.Mounts { - dest, err := symlink.FollowSymlinkInScope(filepath.Join(c.Rootfs, m.Destination), c.Rootfs) - if err != nil { - return err - } flags := syscall.MS_BIND | syscall.MS_REC if !m.Writable { flags |= syscall.MS_RDONLY @@ -242,10 +236,9 @@ func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) e if m.Slave { flags |= syscall.MS_SLAVE } - container.Mounts = append(container.Mounts, &configs.Mount{ Source: m.Source, - Destination: dest, + Destination: m.Destination, Device: "bind", Flags: flags, }) diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 3b6c2e77e7..e343007b0c 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3107,3 +3107,21 @@ func TestRunReadProcLatency(t *testing.T) { } logDone("run - read /proc/latency_stats") } + +func TestMountIntoProc(t *testing.T) { + defer deleteAllContainers() + code, err := runCommand(exec.Command(dockerBinary, "run", "-v", "/proc//sys", "busybox", "true")) + if err == nil || code == 0 { + t.Fatal("container should not be able to mount into /proc") + } + logDone("run - mount into proc") +} + +func TestMountIntoSys(t *testing.T) { + defer deleteAllContainers() + code, err := runCommand(exec.Command(dockerBinary, "run", "-v", "/sys/", "busybox", "true")) + if err == nil || code == 0 { + t.Fatal("container should not be able to mount into /sys") + } + logDone("run - mount into sys") +} From 5b1edfed9da4529babc23fc864b71da0440823b8 Mon Sep 17 00:00:00 2001 From: Jessica Frazelle Date: Thu, 30 Apr 2015 11:22:57 -0700 Subject: [PATCH 7/8] Bump version to 1.6.1 Signed-off-by: Jessica Frazelle (cherry picked from commit 97cd073598275fa468fb3051952bd11002830c8e) Conflicts: VERSION --- CHANGELOG.md | 12 ++++++++++++ VERSION | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d168ad280a..eda6497892 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 1.6.1 (2015-05-07) + +#### Security +- Fix read/write /proc paths (CVE-2015-3630) +- Prohibit VOLUME /proc and VOLUME / (CVE-2015-3631) +- Fix opening of file-descriptor 1 (CVE-2015-3627) +- Fix symlink traversal on container respawn allowing local privilege escalation (CVE-2015-3629) +- Prohibit mount of /sys + +#### Runtime +- Update Apparmor policy to not allow mounts + ## 1.6.0 (2015-04-07) #### Builder diff --git a/VERSION b/VERSION index de023c91b1..9c6d6293b1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.7.0-dev +1.6.1 From 2c2f6fd2728067a5d3ab6ea393d8b5593de4bc0c Mon Sep 17 00:00:00 2001 From: Jessica Frazelle Date: Thu, 7 May 2015 15:02:08 -0700 Subject: [PATCH 8/8] bump version back to 1.7.0-dev Signed-off-by: Jessica Frazelle --- VERSION | 2 +- integration-cli/docker_cli_run_test.go | 37 +++++++++++--------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/VERSION b/VERSION index 9c6d6293b1..de023c91b1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.1 +1.7.0-dev diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index e343007b0c..8849a2d1b1 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3057,71 +3057,64 @@ func (s *DockerSuite) TestRunPidHostWithChildIsKillable(c *check.C) { } } -func TestRunWithTooSmallMemoryLimit(t *testing.T) { +func (s *DockerSuite) TestRunWithTooSmallMemoryLimit(c *check.C) { defer deleteAllContainers() // this memory limit is 1 byte less than the min, which is 4MB // https://github.com/docker/docker/blob/v1.5.0/daemon/create.go#L22 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-m", "4194303", "busybox")) if err == nil || !strings.Contains(out, "Minimum memory limit allowed is 4MB") { - t.Fatalf("expected run to fail when using too low a memory limit: %q", out) + c.Fatalf("expected run to fail when using too low a memory limit: %q", out) } - - logDone("run - can't set too low memory limit") } -func TestRunWriteToProcAsound(t *testing.T) { +func (s *DockerSuite) TestRunWriteToProcAsound(c *check.C) { defer deleteAllContainers() code, err := runCommand(exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo 111 >> /proc/asound/version")) if err == nil || code == 0 { - t.Fatal("standard container should not be able to write to /proc/asound") + c.Fatal("standard container should not be able to write to /proc/asound") } - logDone("run - ro write to /proc/asound") } -func TestRunReadProcTimer(t *testing.T) { +func (s *DockerSuite) TestRunReadProcTimer(c *check.C) { defer deleteAllContainers() out, code, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "busybox", "cat", "/proc/timer_stats")) if err != nil || code != 0 { - t.Fatal(err) + c.Fatal(err) } if strings.Trim(out, "\n ") != "" { - t.Fatalf("expected to receive no output from /proc/timer_stats but received %q", out) + c.Fatalf("expected to receive no output from /proc/timer_stats but received %q", out) } - logDone("run - read /proc/timer_stats") } -func TestRunReadProcLatency(t *testing.T) { +func (s *DockerSuite) TestRunReadProcLatency(c *check.C) { // some kernels don't have this configured so skip the test if this file is not found // on the host running the tests. if _, err := os.Stat("/proc/latency_stats"); err != nil { - t.Skip() + c.Skip("kernel doesnt have latency_stats configured") return } defer deleteAllContainers() out, code, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "busybox", "cat", "/proc/latency_stats")) if err != nil || code != 0 { - t.Fatal(err) + c.Fatal(err) } if strings.Trim(out, "\n ") != "" { - t.Fatalf("expected to receive no output from /proc/latency_stats but received %q", out) + c.Fatalf("expected to receive no output from /proc/latency_stats but received %q", out) } - logDone("run - read /proc/latency_stats") } -func TestMountIntoProc(t *testing.T) { +func (s *DockerSuite) TestMountIntoProc(c *check.C) { defer deleteAllContainers() code, err := runCommand(exec.Command(dockerBinary, "run", "-v", "/proc//sys", "busybox", "true")) if err == nil || code == 0 { - t.Fatal("container should not be able to mount into /proc") + c.Fatal("container should not be able to mount into /proc") } - logDone("run - mount into proc") } -func TestMountIntoSys(t *testing.T) { +func (s *DockerSuite) TestMountIntoSys(c *check.C) { defer deleteAllContainers() code, err := runCommand(exec.Command(dockerBinary, "run", "-v", "/sys/", "busybox", "true")) if err == nil || code == 0 { - t.Fatal("container should not be able to mount into /sys") + c.Fatal("container should not be able to mount into /sys") } - logDone("run - mount into sys") }