Skip to content

Commit

Permalink
Block obsolete socket families in the default seccomp profile
Browse files Browse the repository at this point in the history
Linux supports many obsolete address families, which are usually available in
common distro kernels, but they are less likely to be properly audited and
may have security issues

This blocks all socket families in the socket (and socketcall where applicable) syscall
except
- AF_UNIX - Unix domain sockets
- AF_INET - IPv4
- AF_INET6 - IPv6
- AF_NETLINK - Netlink sockets for communicating with the ekrnel
- AF_PACKET - raw sockets, which are only allowed with CAP_NET_RAW

All other socket families are blocked, including Appletalk (native, not
over IP), IPX (remember that!), VSOCK and HVSOCK, which should not generally
be used in containers, etc.

Note that users can of course provide a profile per container or in the daemon
config if they have unusual use cases that require these.

Signed-off-by: Justin Cormack <[email protected]>
justincormack committed Jan 17, 2017
1 parent f63d1a6 commit 7e3a596
Showing 6 changed files with 392 additions and 7 deletions.
3 changes: 2 additions & 1 deletion contrib/syscall-test/Dockerfile
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ RUN gcc -g -Wall -static userns.c -o /usr/bin/userns-test \
&& gcc -g -Wall -static setuid.c -o /usr/bin/setuid-test \
&& gcc -g -Wall -static setgid.c -o /usr/bin/setgid-test \
&& gcc -g -Wall -static socket.c -o /usr/bin/socket-test \
&& gcc -g -Wall -static raw.c -o /usr/bin/raw-test
&& gcc -g -Wall -static raw.c -o /usr/bin/raw-test \
&& gcc -g -Wall -static appletalk.c -o /usr/bin/appletalk-test

RUN [ "$(uname -m)" = "x86_64" ] && gcc -s -m32 -nostdlib exit32.s -o /usr/bin/exit32-test || true
12 changes: 12 additions & 0 deletions contrib/syscall-test/appletalk.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <stdio.h>
#include <sys/socket.h>

int main() {

if (socket(AF_APPLETALK, SOCK_DGRAM, 0) != -1) {
fprintf(stderr, "Opening Appletalk socket worked, should be blocked\n");
return 1;
}

return 0;
}
14 changes: 13 additions & 1 deletion integration-cli/docker_cli_run_unix_test.go
Original file line number Diff line number Diff line change
@@ -978,7 +978,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
}

// TestRunSeccompProfileDenyUnshareUserns checks that 'docker run debian:jessie unshare --map-root-user --user sh -c whoami' with a specific profile to
// deny unhare of a userns exits with operation not permitted.
// deny unshare of a userns exits with operation not permitted.
func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor)
// from sched.h
@@ -1015,6 +1015,18 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
})
}

// TestRunSeccompProfileDenyUnusualSocketFamilies checks that rarely used socket families such as Appletalk are blocked by the default profile
func (s *DockerSuite) TestRunSeccompProfileDenyUnusualSocketFamilies(c *check.C) {
testRequires(c, SameHostDaemon, seccompEnabled)
ensureSyscallTest(c)

runCmd := exec.Command(dockerBinary, "run", "syscall-test", "appletalk-test")
_, _, err := runCommandWithOutput(runCmd)
if err != nil {
c.Fatal("expected opening appletalk socket family to fail")
}
}

// TestRunSeccompProfileDenyCloneUserns checks that 'docker run syscall-test'
// with a the default seccomp profile exits with operation not permitted.
func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) {
2 changes: 1 addition & 1 deletion integration-cli/fixtures_linux_daemon_test.go
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ func ensureSyscallTest(c *check.C) {
gcc, err := exec.LookPath("gcc")
c.Assert(err, checker.IsNil, check.Commentf("could not find gcc"))

tests := []string{"userns", "ns", "acct", "setuid", "setgid", "socket", "raw"}
tests := []string{"userns", "ns", "acct", "setuid", "setgid", "socket", "raw", "appletalk"}
for _, test := range tests {
out, err := exec.Command(gcc, "-g", "-Wall", "-static", fmt.Sprintf("../contrib/syscall-test/%s.c", test), "-o", fmt.Sprintf("%s/%s-test", tmp, test)).CombinedOutput()
c.Assert(err, checker.IsNil, check.Commentf(string(out)))
219 changes: 217 additions & 2 deletions profiles/seccomp/default.json
Original file line number Diff line number Diff line change
@@ -312,8 +312,6 @@
"signalfd",
"signalfd4",
"sigreturn",
"socket",
"socketcall",
"socketpair",
"splice",
"stat",
@@ -415,6 +413,223 @@
"includes": {},
"excludes": {}
},
{
"names": [
"socket"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socket"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 2,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socket"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 10,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socket"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 16,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socket"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 17,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socketcall"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_GT"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socketcall"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
},
{
"index": 1,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socketcall"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
},
{
"index": 1,
"value": 2,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socketcall"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
},
{
"index": 1,
"value": 10,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socketcall"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
},
{
"index": 1,
"value": 16,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"socketcall"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 1,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
},
{
"index": 1,
"value": 17,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"breakpoint",
149 changes: 147 additions & 2 deletions profiles/seccomp/seccomp_default.go
Original file line number Diff line number Diff line change
@@ -306,8 +306,6 @@ func DefaultProfile() *types.Seccomp {
"signalfd",
"signalfd4",
"sigreturn",
"socket",
"socketcall",
"socketpair",
"splice",
"stat",
@@ -388,6 +386,153 @@ func DefaultProfile() *types.Seccomp {
},
},
},
{
Names: []string{"socket"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: syscall.AF_UNIX,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socket"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: syscall.AF_INET,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socket"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: syscall.AF_INET6,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socket"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: syscall.AF_NETLINK,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socket"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: syscall.AF_PACKET,
Op: types.OpEqualTo,
},
},
},
// socketcall(1, ...) is equivalent to socket(...) on some architectures eg i386
{
Names: []string{"socketcall"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: 1,
Op: types.OpGreaterThan,
},
},
},
{
Names: []string{"socketcall"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: 1,
Op: types.OpEqualTo,
},
{
Index: 1,
Value: syscall.AF_UNIX,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socketcall"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: 1,
Op: types.OpEqualTo,
},
{
Index: 1,
Value: syscall.AF_INET,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socketcall"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: 1,
Op: types.OpEqualTo,
},
{
Index: 1,
Value: syscall.AF_INET6,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socketcall"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: 1,
Op: types.OpEqualTo,
},
{
Index: 1,
Value: syscall.AF_NETLINK,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{"socketcall"},
Action: types.ActAllow,
Args: []*types.Arg{
{
Index: 0,
Value: 1,
Op: types.OpEqualTo,
},
{
Index: 1,
Value: syscall.AF_PACKET,
Op: types.OpEqualTo,
},
},
},
{
Names: []string{
"breakpoint",

0 comments on commit 7e3a596

Please sign in to comment.