mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
add default seccomp profile tests
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
This commit is contained in:
parent
947293a280
commit
a48fe62384
8 changed files with 121 additions and 7 deletions
|
@ -197,6 +197,7 @@ RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||||
busybox:latest@sha256:eb3c0d4680f9213ee5f348ea6d39489a1f85a318a2ae09e012c426f78252a6d2 \
|
busybox:latest@sha256:eb3c0d4680f9213ee5f348ea6d39489a1f85a318a2ae09e012c426f78252a6d2 \
|
||||||
|
debian:jessie@sha256:24a900d1671b269d6640b4224e7b63801880d8e3cb2bcbfaa10a5dddcf4469ed \
|
||||||
hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 \
|
hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 \
|
||||||
jess/unshare:latest@sha256:2e3a8c0591c4690b82d4eba7e5ef8f49f2ddfe9f867f3e865198db9bd1436c5b
|
jess/unshare:latest@sha256:2e3a8c0591c4690b82d4eba7e5ef8f49f2ddfe9f867f3e865198db9bd1436c5b
|
||||||
# see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
# see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||||
|
|
3
contrib/userns-test/Dockerfile
Normal file
3
contrib/userns-test/Dockerfile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
FROM debian:jessie
|
||||||
|
COPY userns-test .
|
||||||
|
ENTRYPOINT ["./userns-test"]
|
54
contrib/userns-test/main.c
Normal file
54
contrib/userns-test/main.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <sched.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define STACKSIZE (1024*1024)
|
||||||
|
static char child_stack[STACKSIZE];
|
||||||
|
|
||||||
|
struct clone_args {
|
||||||
|
char **argv;
|
||||||
|
};
|
||||||
|
|
||||||
|
// child_exec is the func that will be executed as the result of clone
|
||||||
|
static int child_exec(void *stuff)
|
||||||
|
{
|
||||||
|
struct clone_args *args = (struct clone_args *)stuff;
|
||||||
|
if (execvp(args->argv[0], args->argv) != 0) {
|
||||||
|
fprintf(stderr, "failed to execvp argments %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
// we should never reach here!
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct clone_args args;
|
||||||
|
args.argv = &argv[1];
|
||||||
|
|
||||||
|
int clone_flags = CLONE_NEWUSER | SIGCHLD;
|
||||||
|
|
||||||
|
// the result of this call is that our child_exec will be run in another
|
||||||
|
// process returning it's pid
|
||||||
|
pid_t pid =
|
||||||
|
clone(child_exec, child_stack + STACKSIZE, clone_flags, &args);
|
||||||
|
if (pid < 0) {
|
||||||
|
fprintf(stderr, "clone failed: %s\n", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
// lets wait on our child process here before we, the parent, exits
|
||||||
|
if (waitpid(pid, NULL, 0) == -1) {
|
||||||
|
fprintf(stderr, "failed to wait pid %d\n", pid);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ case "$DOCKER_ENGINE_OSARCH" in
|
||||||
*)
|
*)
|
||||||
images=(
|
images=(
|
||||||
busybox:latest
|
busybox:latest
|
||||||
|
debian:jessie
|
||||||
hello-world:latest
|
hello-world:latest
|
||||||
jess/unshare:latest
|
jess/unshare:latest
|
||||||
)
|
)
|
||||||
|
|
18
hack/make/.ensure-userns-test
Normal file
18
hack/make/.ensure-userns-test
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Build a C binary for cloning a userns for seccomp tests
|
||||||
|
# and compile it for target daemon
|
||||||
|
|
||||||
|
dir="$DEST/userns-test"
|
||||||
|
mkdir -p "$dir"
|
||||||
|
(
|
||||||
|
GOOS=${DOCKER_ENGINE_GOOS:="linux"}
|
||||||
|
if [ "$GOOS" = "linux" ]; then
|
||||||
|
cd "$dir"
|
||||||
|
gcc -g -Wall -static ../../../../contrib/userns-test/main.c -o ./userns-test
|
||||||
|
cp ../../../../contrib/userns-test/Dockerfile .
|
||||||
|
docker build -qt userns-test . > /dev/null
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
rm -rf "$dir"
|
|
@ -3,3 +3,4 @@
|
||||||
bundle .ensure-emptyfs
|
bundle .ensure-emptyfs
|
||||||
bundle .ensure-frozen-images
|
bundle .ensure-frozen-images
|
||||||
bundle .ensure-httpserver
|
bundle .ensure-httpserver
|
||||||
|
bundle .ensure-userns-test
|
||||||
|
|
|
@ -2858,7 +2858,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
|
||||||
testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace)
|
testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace)
|
||||||
|
|
||||||
name := "acidburn"
|
name := "acidburn"
|
||||||
out, _, err := dockerCmdWithError("run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
|
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
|
||||||
if err == nil ||
|
if err == nil ||
|
||||||
!(strings.Contains(strings.ToLower(out), "permission denied") ||
|
!(strings.Contains(strings.ToLower(out), "permission denied") ||
|
||||||
strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
||||||
|
@ -2866,7 +2866,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
name = "cereal"
|
name = "cereal"
|
||||||
out, _, err = dockerCmdWithError("run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
|
out, _, err = dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
|
||||||
if err == nil ||
|
if err == nil ||
|
||||||
!(strings.Contains(strings.ToLower(out), "permission denied") ||
|
!(strings.Contains(strings.ToLower(out), "permission denied") ||
|
||||||
strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
||||||
|
@ -2875,7 +2875,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
|
||||||
|
|
||||||
/* Ensure still fails if running privileged with the default policy */
|
/* Ensure still fails if running privileged with the default policy */
|
||||||
name = "crashoverride"
|
name = "crashoverride"
|
||||||
out, _, err = dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
|
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")
|
||||||
if err == nil || !(strings.Contains(strings.ToLower(out), "permission denied") || strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
if err == nil || !(strings.Contains(strings.ToLower(out), "permission denied") || strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
||||||
c.Fatalf("privileged unshare with apparmor should have failed with permission denied, got: %s, %v", out, err)
|
c.Fatalf("privileged unshare with apparmor should have failed with permission denied, got: %s, %v", out, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
|
||||||
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
||||||
c.Fatal(err)
|
c.Fatal(err)
|
||||||
}
|
}
|
||||||
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:"+tmpFile.Name(), "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
|
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")
|
||||||
out, _, _ := runCommandWithOutput(runCmd)
|
out, _, _ := runCommandWithOutput(runCmd)
|
||||||
if !strings.Contains(out, "Operation not permitted") {
|
if !strings.Contains(out, "Operation not permitted") {
|
||||||
c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out)
|
c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out)
|
||||||
|
@ -549,8 +549,9 @@ func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRunSeccompProfileDenyUserns checks that 'docker run jess/unshare unshare --map-root-user --user sh -c whoami' exits with operation not permitted.
|
// TestRunSeccompProfileDenyUnshareUserns checks that 'docker run jess/unshare unshare --map-root-user --user sh -c whoami' with a specific profile to
|
||||||
func (s *DockerSuite) TestRunSeccompProfileDenyUserns(c *check.C) {
|
// deny unhare of a userns exits with operation not permitted.
|
||||||
|
func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
|
||||||
testRequires(c, SameHostDaemon, seccompEnabled)
|
testRequires(c, SameHostDaemon, seccompEnabled)
|
||||||
// from sched.h
|
// from sched.h
|
||||||
jsonData := fmt.Sprintf(`{
|
jsonData := fmt.Sprintf(`{
|
||||||
|
@ -578,9 +579,44 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUserns(c *check.C) {
|
||||||
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
||||||
c.Fatal(err)
|
c.Fatal(err)
|
||||||
}
|
}
|
||||||
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:"+tmpFile.Name(), "jess/unshare", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
|
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
|
||||||
out, _, _ := runCommandWithOutput(runCmd)
|
out, _, _ := runCommandWithOutput(runCmd)
|
||||||
if !strings.Contains(out, "Operation not permitted") {
|
if !strings.Contains(out, "Operation not permitted") {
|
||||||
c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out)
|
c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRunSeccompProfileDenyCloneUserns checks that 'docker run userns-test'
|
||||||
|
// with a the default seccomp profile exits with operation not permitted.
|
||||||
|
func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) {
|
||||||
|
testRequires(c, SameHostDaemon, seccompEnabled)
|
||||||
|
|
||||||
|
runCmd := exec.Command(dockerBinary, "run", "userns-test", "id")
|
||||||
|
out, _, err := runCommandWithOutput(runCmd)
|
||||||
|
if err == nil || !strings.Contains(out, "clone failed: Operation not permitted") {
|
||||||
|
c.Fatalf("expected clone userns with default seccomp profile denied to fail, got %s: %v", out, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRunSeccompAllowPrivCloneUserns checks that 'docker run userns-test'
|
||||||
|
// with a the default seccomp profile exits with operation not permitted.
|
||||||
|
func (s *DockerSuite) TestRunSeccompAllowPrivCloneUserns(c *check.C) {
|
||||||
|
testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace)
|
||||||
|
|
||||||
|
// make sure running w privileged is ok
|
||||||
|
runCmd := exec.Command(dockerBinary, "run", "--privileged", "userns-test", "id")
|
||||||
|
if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") {
|
||||||
|
c.Fatalf("expected clone userns with --privileged to succeed, got %s: %v", out, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRunSeccompAllowAptKey checks that 'docker run debian:jessie apt-key' succeeds.
|
||||||
|
func (s *DockerSuite) TestRunSeccompAllowAptKey(c *check.C) {
|
||||||
|
testRequires(c, SameHostDaemon, seccompEnabled)
|
||||||
|
|
||||||
|
// apt-key uses setrlimit & getrlimit, so we want to make sure we don't break it
|
||||||
|
runCmd := exec.Command(dockerBinary, "run", "debian:jessie", "apt-key", "adv", "--keyserver", "hkp://p80.pool.sks-keyservers.net:80", "--recv-keys", "E871F18B51E0147C77796AC81196BA81F6B0FC61")
|
||||||
|
if out, _, err := runCommandWithOutput(runCmd); err != nil {
|
||||||
|
c.Fatalf("expected apt-key with seccomp to succeed, got %s: %v", out, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue