diff --git a/Dockerfile b/Dockerfile index 9b6a79b025..9932d941e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -162,7 +162,8 @@ RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker COPY contrib/download-frozen-image.sh /go/src/github.com/docker/docker/contrib/ RUN ./contrib/download-frozen-image.sh /docker-frozen-images \ busybox:latest@4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125 \ - hello-world:frozen@e45a5af57b00862e5ef5782a9925979a02ba2b12dff832fd0991335f4a11e5c5 + hello-world:frozen@e45a5af57b00862e5ef5782a9925979a02ba2b12dff832fd0991335f4a11e5c5 \ + jess/unshare@5c9f6ea50341a2a8eb6677527f2bdedbf331ae894a41714fda770fb130f3314d # see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) # Download man page generator diff --git a/hack/make/.ensure-frozen-images b/hack/make/.ensure-frozen-images index 379f738495..deded80e76 100644 --- a/hack/make/.ensure-frozen-images +++ b/hack/make/.ensure-frozen-images @@ -5,6 +5,7 @@ set -e images=( busybox:latest hello-world:frozen + jess/unshare:latest ) if ! docker inspect "${images[@]}" &> /dev/null; then diff --git a/hack/make/.integration-daemon-start b/hack/make/.integration-daemon-start index 41f116f461..eecf682efa 100644 --- a/hack/make/.integration-daemon-start +++ b/hack/make/.integration-daemon-start @@ -27,6 +27,17 @@ if [ -n "$DOCKER_STORAGE_OPTS" ]; then fi if [ -z "$DOCKER_TEST_HOST" ]; then + # Start apparmor if it is enabled + if [ "$(cat /sys/module/apparmor/parameters/enabled)" == "Y" ]; then + # reset container variable so apparmor profile is applied to process + # see https://github.com/docker/libcontainer/blob/master/apparmor/apparmor.go#L16 + export container="" + ( + set -x + /etc/init.d/apparmor start + ) + fi + export DOCKER_HOST="unix://$(cd "$DEST" && pwd)/docker.sock" # "pwd" tricks to make sure $DEST is an absolute path, not a relative one ( set -x; exec \ docker --daemon --debug \ diff --git a/hack/make/.integration-daemon-stop b/hack/make/.integration-daemon-stop index 6e1dc844de..364490bdef 100644 --- a/hack/make/.integration-daemon-stop +++ b/hack/make/.integration-daemon-stop @@ -9,3 +9,13 @@ for pidFile in $(find "$DEST" -name docker.pid); do echo >&2 "warning: PID $pid from $pidFile had a nonzero exit code" fi done + +if [ -z "$DOCKER_TEST_HOST" ]; then + # Stop apparmor if it is enabled + if [ "$(cat /sys/module/apparmor/parameters/enabled)" == "Y" ]; then + ( + set -x + /etc/init.d/apparmor stop + ) + fi +fi diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 0b067b9785..7426549c87 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3211,3 +3211,19 @@ func (s *DockerSuite) TestTwoContainersInNetHost(c *check.C) { dockerCmd(c, "stop", "first") dockerCmd(c, "stop", "second") } + +func (s *DockerSuite) TestRunUnshareProc(c *check.C) { + testRequires(c, Apparmor) + + name := "acidburn" + runCmd := exec.Command(dockerBinary, "run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount") + if out, _, err := runCommandWithOutput(runCmd); err == nil || !strings.Contains(out, "Permission denied") { + c.Fatalf("unshare should have failed with permission denied, got: %s, %v", out, err) + } + + name = "cereal" + runCmd = exec.Command(dockerBinary, "run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc") + if out, _, err := runCommandWithOutput(runCmd); err == nil || !strings.Contains(out, "Permission denied") { + c.Fatalf("unshare should have failed with permission denied, got: %s, %v", out, err) + } +} diff --git a/integration-cli/requirements.go b/integration-cli/requirements.go index cc451bd886..fc4f5ee955 100644 --- a/integration-cli/requirements.go +++ b/integration-cli/requirements.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "fmt" + "io/ioutil" "log" "net/http" "os/exec" @@ -44,6 +45,13 @@ var ( }, "Test requires network availability, environment variable set to none to run in a non-network enabled mode.", } + Apparmor = TestRequirement{ + func() bool { + buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") + return err == nil && len(buf) > 1 && buf[0] == 'Y' + }, + "Test requires apparmor is enabled.", + } RegistryHosting = TestRequirement{ func() bool { // for now registry binary is built only if we're running inside @@ -78,7 +86,6 @@ var ( }, "Test requires the native (libcontainer) exec driver.", } - NotOverlay = TestRequirement{ func() bool { cmd := exec.Command("grep", "^overlay / overlay", "/proc/mounts")