Skip to content
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.

Commit

Permalink
Introduce support for syscall filtering in containers #237
Browse files Browse the repository at this point in the history
This PR introduces the ability to filter system calls on a per-container basis on Linux, using libseccomp to support multiple architectures.

This adds another layer of security between containers and the kernel. System calls which are unnecessary in a container or problematic from a security perspective can be restricted to prevent their use. Most of the truly problematic syscalls are already restricted by dropping capabilities; this adds an additional, finer-grained layer of protection.

This PR adds a vendored library dependency (Go bindings for libseccomp) and a build dependency on libseccomp >= v2.1. The actual changes to libcontainer are fairly minimal, most of the delta is in the libseccomp bindings.

Docker-DCO-1.1-Signed-off-by: Dan Walsh <[email protected]> (github: rhatdan)
Docker-DCO-1.1-Signed-off-by: Matt Heon <[email protected]> (github: mheon)
  • Loading branch information
mheon committed Feb 20, 2015
1 parent 5b73860 commit 07b402f
Show file tree
Hide file tree
Showing 16 changed files with 2,530 additions and 7 deletions.
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
FROM golang:1.4

RUN apt-get update && apt-get install -y gcc make libseccomp2 libseccomp-dev
RUN go get golang.org/x/tools/cmd/cover

ENV GOPATH $GOPATH:/go/src/github.com/docker/libcontainer/vendor
Expand All @@ -17,7 +18,7 @@ WORKDIR /go/src/github.com/docker/libcontainer
RUN cp sample_configs/minimal.json /busybox/container.json

RUN go get -d -v ./...
RUN make direct-install
RUN TEST_TAGS="-tags seccomp" make direct-install

ENTRYPOINT ["/dind"]
CMD ["make", "direct-test"]
CMD ["make", "TEST_TAGS=-tags seccomp", "direct-test"]
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

all:
docker build -t dockercore/libcontainer .

Expand All @@ -18,9 +17,9 @@ direct-test-short:
go test $(TEST_TAGS) -cover -test.short -v $(GO_PACKAGES)

direct-build:
go build -v $(GO_PACKAGES)
go build $(TEST_TAGS) -v $(GO_PACKAGES)

direct-install:
go install -v $(GO_PACKAGES)
go install $(TEST_TAGS) -v $(GO_PACKAGES)
local:
go test -v
9 changes: 8 additions & 1 deletion configs/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package configs

import "fmt"
import (
"fmt"

"github.com/docker/libcontainer/security/seccomp"
)

type Rlimit struct {
Type int `json:"type"`
Expand Down Expand Up @@ -99,6 +103,9 @@ type Config struct {
// ReadonlyPaths specifies paths within the container's rootfs to remount as read-only
// so that these files prevent any writes.
ReadonlyPaths []string `json:"readonly_paths"`

// SeccompConfig holds information on system calls to be restricted in the container
SeccompConfig seccomp.SeccompConfig `json:"seccomp_config,omitempty"`
}

// Gets the root uid for the process on host which could be non-zero
Expand Down
92 changes: 92 additions & 0 deletions integration/seccomp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// +build seccomp,linux,cgo

package integration

import (
"strings"
"testing"

"github.com/docker/libcontainer/security/seccomp"
)

func TestSeccompDenyGetcwd(t *testing.T) {
if testing.Short() {
return
}

rootfs, err := newRootFs()
if err != nil {
t.Fatal(err)
}
defer remove(rootfs)

config := newTemplateConfig(rootfs)
config.SeccompConfig = seccomp.SeccompConfig{
Enable: true,
Whitelist: false,
Syscalls: []seccomp.BlockedSyscall{
{
Name: "getcwd",
},
},
}

buffers2, _, err := runContainer(config, "", "pwd")
if err != nil {
t.Fatal(err)
}
t.Logf("Buffer is %s", buffers2.Stdout.String())

buffers, exitCode, err := runContainer(config, "", "pwd")
if err != nil {
t.Fatal(err)
}

if exitCode != 1 {
t.Fatalf("Getcwd should fail with exit code 1, instead got %d!", exitCode)
}

expected := "pwd: getcwd: Operation not permitted"
actual := strings.Trim(buffers.Stderr.String(), "\n")
if actual != expected {
t.Fatalf("Expected output %s but got %s\n", expected, actual)
}
}

func TestSeccompDenyMmap(t *testing.T) {
if testing.Short() {
return
}

rootfs, err := newRootFs()
if err != nil {
t.Fatal(err)
}
defer remove(rootfs)

config := newTemplateConfig(rootfs)
config.SeccompConfig = seccomp.SeccompConfig{
Enable: true,
Whitelist: false,
Syscalls: []seccomp.BlockedSyscall{
{
Name: "mmap",
},
},
}

buffers, exitCode, err := runContainer(config, "", "echo", "hello world")
if err != nil {
t.Fatal(err)
}

if exitCode != 20 {
t.Fatalf("Busybox should fail to start with exit code 20, instead got %d!", exitCode)
}

expected := "mmap of a spare page failed!"
actual := strings.Trim(buffers.Stderr.String(), "\n")
if actual != expected {
t.Fatalf("Expected output %s but got %s\n", expected, actual)
}
}
2 changes: 1 addition & 1 deletion label/label_selinux_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build selinux,linux
// +build selinux,linux,cgo

package label

Expand Down
4 changes: 4 additions & 0 deletions linux_setns_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package libcontainer
import (
"github.com/docker/libcontainer/apparmor"
"github.com/docker/libcontainer/label"
"github.com/docker/libcontainer/security/seccomp"
"github.com/docker/libcontainer/system"
)

Expand All @@ -18,6 +19,9 @@ func (l *linuxSetnsInit) Init() error {
if err := setupRlimits(l.config.Config); err != nil {
return err
}
if err := seccomp.InitSeccomp(container.SeccompConfig); err != nil {
return err
}
if err := finalizeNamespace(l.config); err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions linux_standard_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/docker/libcontainer/apparmor"
"github.com/docker/libcontainer/configs"
"github.com/docker/libcontainer/label"
"github.com/docker/libcontainer/security/seccomp"
"github.com/docker/libcontainer/system"
)

Expand Down Expand Up @@ -76,6 +77,9 @@ func (l *linuxStandardInit) Init() error {
if err != nil {
return err
}
if err := seccomp.InitSeccomp(container.SeccompConfig); err != nil {
return err
}
if err := finalizeNamespace(l.config); err != nil {
return err
}
Expand Down
Loading

0 comments on commit 07b402f

Please sign in to comment.