blob: f4cfb4799bb5323400cc858e5e6e80a0ec4869d6 [file] [log] [blame]
// +build linux
package seccomp // import "github.com/docker/docker/profiles/seccomp"
import (
"encoding/json"
"io/ioutil"
"strings"
"testing"
"github.com/opencontainers/runtime-spec/specs-go"
"gotest.tools/v3/assert"
)
func TestLoadProfile(t *testing.T) {
f, err := ioutil.ReadFile("fixtures/example.json")
if err != nil {
t.Fatal(err)
}
rs := createSpec()
if _, err := LoadProfile(string(f), &rs); err != nil {
t.Fatal(err)
}
}
// TestLoadLegacyProfile tests loading a seccomp profile in the old format
// (before https://github.com/docker/docker/pull/24510)
func TestLoadLegacyProfile(t *testing.T) {
f, err := ioutil.ReadFile("fixtures/default-old-format.json")
if err != nil {
t.Fatal(err)
}
rs := createSpec()
if _, err := LoadProfile(string(f), &rs); err != nil {
t.Fatal(err)
}
}
func TestLoadDefaultProfile(t *testing.T) {
f, err := ioutil.ReadFile("default.json")
if err != nil {
t.Fatal(err)
}
rs := createSpec()
if _, err := LoadProfile(string(f), &rs); err != nil {
t.Fatal(err)
}
}
func TestUnmarshalDefaultProfile(t *testing.T) {
expected := DefaultProfile()
if expected == nil {
t.Skip("seccomp not supported")
}
f, err := ioutil.ReadFile("default.json")
if err != nil {
t.Fatal(err)
}
var profile Seccomp
err = json.Unmarshal(f, &profile)
if err != nil {
t.Fatal(err)
}
assert.DeepEqual(t, expected.Architectures, profile.Architectures)
assert.DeepEqual(t, expected.ArchMap, profile.ArchMap)
assert.DeepEqual(t, expected.DefaultAction, profile.DefaultAction)
assert.DeepEqual(t, expected.Syscalls, profile.Syscalls)
}
func TestMarshalUnmarshalFilter(t *testing.T) {
t.Parallel()
tests := []struct {
in string
out string
error bool
}{
{in: `{"arches":["s390x"],"minKernel":3}`, error: true},
{in: `{"arches":["s390x"],"minKernel":3.12}`, error: true},
{in: `{"arches":["s390x"],"minKernel":true}`, error: true},
{in: `{"arches":["s390x"],"minKernel":"0.0"}`, error: true},
{in: `{"arches":["s390x"],"minKernel":"3"}`, error: true},
{in: `{"arches":["s390x"],"minKernel":".3"}`, error: true},
{in: `{"arches":["s390x"],"minKernel":"3."}`, error: true},
{in: `{"arches":["s390x"],"minKernel":"true"}`, error: true},
{in: `{"arches":["s390x"],"minKernel":"3.12.1\""}`, error: true},
{in: `{"arches":["s390x"],"minKernel":"4.15abc"}`, error: true},
{in: `{"arches":["s390x"],"minKernel":null}`, out: `{"arches":["s390x"]}`},
{in: `{"arches":["s390x"],"minKernel":""}`, out: `{"arches":["s390x"],"minKernel":""}`}, // FIXME: try to fix omitempty for this
{in: `{"arches":["s390x"],"minKernel":"0.5"}`, out: `{"arches":["s390x"],"minKernel":"0.5"}`},
{in: `{"arches":["s390x"],"minKernel":"0.50"}`, out: `{"arches":["s390x"],"minKernel":"0.50"}`},
{in: `{"arches":["s390x"],"minKernel":"5.0"}`, out: `{"arches":["s390x"],"minKernel":"5.0"}`},
{in: `{"arches":["s390x"],"minKernel":"50.0"}`, out: `{"arches":["s390x"],"minKernel":"50.0"}`},
{in: `{"arches":["s390x"],"minKernel":"4.15"}`, out: `{"arches":["s390x"],"minKernel":"4.15"}`},
}
for _, tc := range tests {
tc := tc
t.Run(tc.in, func(t *testing.T) {
var filter Filter
err := json.Unmarshal([]byte(tc.in), &filter)
if tc.error {
if err == nil {
t.Fatal("expected an error")
} else if !strings.Contains(err.Error(), "invalid kernel version") {
t.Fatal("unexpected error:", err)
}
return
}
if err != nil {
t.Fatal(err)
}
out, err := json.Marshal(filter)
if err != nil {
t.Fatal(err)
}
if string(out) != tc.out {
t.Fatalf("expected %s, got %s", tc.out, string(out))
}
})
}
}
func TestLoadConditional(t *testing.T) {
f, err := ioutil.ReadFile("fixtures/conditional_include.json")
if err != nil {
t.Fatal(err)
}
tests := []struct {
doc string
cap string
expected []string
}{
{doc: "no caps", expected: []string{"chmod", "ptrace"}},
{doc: "with syslog", cap: "CAP_SYSLOG", expected: []string{"chmod", "syslog", "ptrace"}},
{doc: "no ptrace", cap: "CAP_SYS_ADMIN", expected: []string{"chmod"}},
}
for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) {
rs := createSpec(tc.cap)
p, err := LoadProfile(string(f), &rs)
if err != nil {
t.Fatal(err)
}
if len(p.Syscalls) != len(tc.expected) {
t.Fatalf("expected %d syscalls in profile, have %d", len(tc.expected), len(p.Syscalls))
}
for i, v := range p.Syscalls {
if v.Names[0] != tc.expected[i] {
t.Fatalf("expected %s syscall, have %s", tc.expected[i], v.Names[0])
}
}
})
}
}
// createSpec() creates a minimum spec for testing
func createSpec(caps ...string) specs.Spec {
rs := specs.Spec{
Process: &specs.Process{
Capabilities: &specs.LinuxCapabilities{},
},
}
if caps != nil {
rs.Process.Capabilities.Bounding = append(rs.Process.Capabilities.Bounding, caps...)
}
return rs
}