From bf2a577c131d8998eb6ecac986d80e1289e6c801 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 31 May 2016 09:27:28 -0400 Subject: [PATCH] Enable seccomp for s390x To implement seccomp for s390x the following changes are required: 1) seccomp_default: Add s390 compat mode On s390x (64 bit) we can run s390 (32 bit) programs in 32 bit compat mode. Therefore add this information to arches(). 2) seccomp_default: Use correct flags parameter for sys_clone on s390x On s390x the second parameter for the clone system call is the flags parameter. On all other architectures it is the first one. See kernel code kernel/fork.c: #elif defined(CONFIG_CLONE_BACKWARDS2) SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, So fix the docker default seccomp rule and check for the second parameter on s390/s390x. 3) seccomp_default: Add s390 specific syscalls For s390 we currently have three additional system calls that should be added to the seccomp whitelist: - Other architectures can read/write unprivileged from/to PCI MMIO memory. On s390 the instructions are privileged and therefore we need system calls for that purpose: * s390_pci_mmio_write() * s390_pci_mmio_read() - Runtime instrumentation: * s390_runtime_instr() 4) test_integration: Do not run seccomp default profile test on s390x The generated profile that we check in is for amd64 and i386 architectures and does not work correctly on s390x. See also: 75385dc216e ("Do not run the seccomp tests that use default.json on non x86 architectures") 5) Dockerfile.s390x: Add "seccomp" to DOCKER_BUILDTAGS Signed-off-by: Michael Holzheu --- Dockerfile.s390x | 2 +- integration-cli/docker_cli_run_unix_test.go | 2 +- integration-cli/requirements.go | 4 ++++ profiles/seccomp/seccomp_default.go | 25 ++++++++++++++++++++- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Dockerfile.s390x b/Dockerfile.s390x index 8784292296..7852a96f9a 100644 --- a/Dockerfile.s390x +++ b/Dockerfile.s390x @@ -161,7 +161,7 @@ RUN useradd --create-home --gid docker unprivilegeduser VOLUME /var/lib/docker WORKDIR /go/src/github.com/docker/docker -ENV DOCKER_BUILDTAGS apparmor selinux +ENV DOCKER_BUILDTAGS apparmor selinux seccomp # Let us use a .bashrc file RUN ln -sfv $PWD/.bashrc ~/.bashrc diff --git a/integration-cli/docker_cli_run_unix_test.go b/integration-cli/docker_cli_run_unix_test.go index 0ede9b9fa5..1fb6f3e1f2 100644 --- a/integration-cli/docker_cli_run_unix_test.go +++ b/integration-cli/docker_cli_run_unix_test.go @@ -1184,7 +1184,7 @@ func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) { // make sure the default profile can be successfully parsed (using unshare as it is // something which we know is blocked in the default profile) func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) { - testRequires(c, SameHostDaemon, seccompEnabled, NotArm, NotPpc64le) + testRequires(c, SameHostDaemon, seccompEnabled, NotArm, NotPpc64le, NotS390X) out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp=../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami") c.Assert(err, checker.NotNil, check.Commentf(out)) diff --git a/integration-cli/requirements.go b/integration-cli/requirements.go index 74c2679476..70275e9cd8 100644 --- a/integration-cli/requirements.go +++ b/integration-cli/requirements.go @@ -42,6 +42,10 @@ var ( func() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") != "ppc64le" }, "Test requires a daemon not running on ppc64le", } + NotS390X = testRequirement{ + func() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") != "s390x" }, + "Test requires a daemon not running on s390x", + } SameHostDaemon = testRequirement{ func() bool { return isLocalDaemon }, "Test requires docker daemon to run on the same machine as CLI", diff --git a/profiles/seccomp/seccomp_default.go b/profiles/seccomp/seccomp_default.go index a6e2c653be..87ae358ff5 100644 --- a/profiles/seccomp/seccomp_default.go +++ b/profiles/seccomp/seccomp_default.go @@ -29,6 +29,8 @@ func arches() []types.Arch { return []types.Arch{types.ArchMIPSEL, types.ArchMIPSEL64, types.ArchMIPSEL64N32} case "mipsel64n32": return []types.Arch{types.ArchMIPSEL, types.ArchMIPSEL64, types.ArchMIPSEL64N32} + case "s390x": + return []types.Arch{types.ArchS390, types.ArchS390X} default: return []types.Arch{} } @@ -1579,6 +1581,7 @@ func DefaultProfile(rs *specs.Spec) *types.Seccomp { }, } + var sysCloneFlagsIndex uint var arch string var native, err = libseccomp.GetNativeArch() if err == nil { @@ -1620,6 +1623,26 @@ func DefaultProfile(rs *specs.Spec) *types.Seccomp { Args: []*types.Arg{}, }, }...) + case "s390", "s390x": + syscalls = append(syscalls, []*types.Syscall{ + { + Name: "s390_pci_mmio_read", + Action: types.ActAllow, + Args: []*types.Arg{}, + }, + { + Name: "s390_pci_mmio_write", + Action: types.ActAllow, + Args: []*types.Arg{}, + }, + { + Name: "s390_runtime_instr", + Action: types.ActAllow, + Args: []*types.Arg{}, + }, + }...) + /* Flags parameter of the clone syscall is the 2nd on s390 */ + sysCloneFlagsIndex = 1 } capSysAdmin := false @@ -1841,7 +1864,7 @@ func DefaultProfile(rs *specs.Spec) *types.Seccomp { Action: types.ActAllow, Args: []*types.Arg{ { - Index: 0, + Index: sysCloneFlagsIndex, Value: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWUSER | syscall.CLONE_NEWPID | syscall.CLONE_NEWNET, ValueTwo: 0, Op: types.OpMaskedEqual,