This repository has been archived by the owner on Dec 13, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 316
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce support for syscall filtering in containers #237
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. There's a similar feature present in LXC already, with the significant difference that LXC uses a whitelist of system calls, whereas these patches use a blacklist. The blacklist approach ensures no difference in functionality to clients not explicitly aware of seccomp support (the restricted syscalls list in the container config is left empty, and the seccomp init function exits without taking action). 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. Presently missing: integration tests, documentation Docker-DCO-1.1-Signed-off-by: Matt Heon <[email protected]> (github: mheon) Docker-DCO-1.1-Signed-off-by: Dan Walsh <[email protected]> (github: rhatdan) Conflicts: config.go
- Loading branch information
Showing
16 changed files
with
2,367 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// +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.Seccomps = append(config.Seccomps, seccomp.Seccomp{Syscall: "getcwd"}) | ||
|
||
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.Seccomps = append(config.Seccomps, seccomp.Secomp{Syscall: "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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// +build selinux,linux | ||
// +build selinux,linux,cgo | ||
|
||
package label | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// +build linux,cgo,seccomp | ||
|
||
package seccomp | ||
|
||
import ( | ||
"fmt" | ||
"syscall" | ||
|
||
"sourceforge.net/seccomp" | ||
) | ||
|
||
type Seccomp struct { | ||
Architecture string | ||
Syscall string | ||
Args []string | ||
} | ||
|
||
var ( | ||
// Match action: deny a syscall with -EPERM return code | ||
actDeny seccomp.ScmpAction = seccomp.ActErrno.SetReturnCode(int16(syscall.EPERM)) | ||
) | ||
|
||
// Filters given syscalls in a container, preventing them from being used | ||
// Started in the container init process, and carried over to all child processes | ||
func InitSeccomp(secomps []Seccomp) error { | ||
if len(secomps) == 0 { | ||
return nil | ||
} | ||
|
||
archNative, err := seccomp.GetNativeArch() | ||
if err != nil { | ||
return fmt.Errorf("Error getting native architecture: %s", err) | ||
} | ||
|
||
filter, err := seccomp.NewFilter(seccomp.ActAllow) | ||
if err != nil { | ||
return fmt.Errorf("Error creating filter: %s", err) | ||
} | ||
|
||
// Unset no new privs bit | ||
if err = filter.SetNoNewPrivsBit(false); err != nil { | ||
return fmt.Errorf("Error setting no new privileges: %s", err) | ||
} | ||
|
||
// If native arch is AMD64, add X86 to filter | ||
if archNative == seccomp.ArchAMD64 { | ||
if err = filter.AddArch(seccomp.ArchX86); err != nil { | ||
return fmt.Errorf("Error adding x86 arch to filter: %s", err) | ||
} | ||
} | ||
|
||
for _, call := range secomps { | ||
if len(call.Architecture) > 0 { | ||
archNum, err := seccomp.GetArchFromName(call.Architecture) | ||
if err != nil { | ||
return fmt.Errorf("Could not resolve Archietecture name %q: %s", call.Architecture, err) | ||
} | ||
if err = filter.AddArch(archNum); err != nil { | ||
return fmt.Errorf("Error adding %q arch to filter: %s", call.Architecture, err) | ||
} | ||
continue | ||
} | ||
if len(call.Syscall) == 0 { | ||
return fmt.Errorf("Empty string is not a valid syscall!") | ||
} | ||
|
||
callNum, err := seccomp.GetSyscallFromName(call.Syscall) | ||
if err != nil { | ||
return fmt.Errorf("Could not resolve syscall name %s: %s", call.Syscall, err) | ||
} | ||
|
||
if len(call.Args) == 0 { | ||
if err = filter.AddRule(callNum, actDeny); err != nil { | ||
return fmt.Errorf("Error adding rule to filter for syscall %s: %s", call, err) | ||
} | ||
} | ||
} | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error initializing filter: %s", err) | ||
} | ||
|
||
if err = filter.Load(); err != nil { | ||
return fmt.Errorf("Error loading seccomp filter into kernel: %s", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// +build seccomp,linux,cgo | ||
|
||
package seccomp | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"sourceforge.net/seccomp" | ||
) | ||
|
||
func TestInitSeccomp(t *testing.T) { | ||
var seccomps []Seccomps | ||
RestrictSyscalls := []string{"kexec_load", "open_by_handle_at", "init_module", "finit_module", "delete_module", "iopl", "ioperm", "swapon", "swapoff", "sysfs", "sysctl", "adjtimex", "clock_adjtime", "lookup_dcookie", "perf_event_open", "fanotify_init", "kcmp"} | ||
for s := range RestrictSyscalls { | ||
seccomps = append(seccomps, Seccomp{Syscall: s}) | ||
} | ||
if err := InitSeccomp(nil); err != nil { | ||
t.Log("InitLabels Failed") | ||
t.Fatal(err) | ||
} | ||
|
||
if err := InitSeccomp(seccomps); err != nil { | ||
t.Log("InitLabels Failed") | ||
t.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// +build !linux !cgo !seccomp | ||
|
||
package seccomp | ||
|
||
type Seccomp struct { | ||
Architecture string | ||
Syscall string | ||
Args []string | ||
} | ||
|
||
func InitSeccomp(secomps []Seccomp) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.