diff --git a/contrib/syscall-test/Dockerfile b/contrib/syscall-test/Dockerfile index f95f1758c0..fcf5892be4 100644 --- a/contrib/syscall-test/Dockerfile +++ b/contrib/syscall-test/Dockerfile @@ -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 diff --git a/contrib/syscall-test/appletalk.c b/contrib/syscall-test/appletalk.c new file mode 100644 index 0000000000..0001dd4247 --- /dev/null +++ b/contrib/syscall-test/appletalk.c @@ -0,0 +1,12 @@ +#include +#include + +int main() { + + if (socket(AF_APPLETALK, SOCK_DGRAM, 0) != -1) { + fprintf(stderr, "Opening Appletalk socket worked, should be blocked\n"); + return 1; + } + + return 0; +} diff --git a/integration-cli/docker_cli_run_unix_test.go b/integration-cli/docker_cli_run_unix_test.go index 172368e793..147ca598f0 100644 --- a/integration-cli/docker_cli_run_unix_test.go +++ b/integration-cli/docker_cli_run_unix_test.go @@ -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) { diff --git a/integration-cli/fixtures_linux_daemon_test.go b/integration-cli/fixtures_linux_daemon_test.go index 9b76724194..ed3db7fe4b 100644 --- a/integration-cli/fixtures_linux_daemon_test.go +++ b/integration-cli/fixtures_linux_daemon_test.go @@ -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))) diff --git a/profiles/seccomp/default.json b/profiles/seccomp/default.json index 804d8e5c68..066dc9a7c5 100755 --- a/profiles/seccomp/default.json +++ b/profiles/seccomp/default.json @@ -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", diff --git a/profiles/seccomp/seccomp_default.go b/profiles/seccomp/seccomp_default.go index b392640c92..9527793a45 100644 --- a/profiles/seccomp/seccomp_default.go +++ b/profiles/seccomp/seccomp_default.go @@ -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",