github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/profiles/seccomp/seccomp_test.go (about) 1 // +build linux 2 3 package seccomp // import "github.com/docker/docker/profiles/seccomp" 4 5 import ( 6 "encoding/json" 7 "io/ioutil" 8 "strings" 9 "testing" 10 11 "github.com/opencontainers/runtime-spec/specs-go" 12 "gotest.tools/v3/assert" 13 ) 14 15 func TestLoadProfile(t *testing.T) { 16 f, err := ioutil.ReadFile("fixtures/example.json") 17 if err != nil { 18 t.Fatal(err) 19 } 20 rs := createSpec() 21 p, err := LoadProfile(string(f), &rs) 22 if err != nil { 23 t.Fatal(err) 24 } 25 var expectedErrno uint = 12345 26 expected := specs.LinuxSeccomp{ 27 DefaultAction: "SCMP_ACT_ERRNO", 28 Syscalls: []specs.LinuxSyscall{ 29 { 30 Names: []string{"clone"}, 31 Action: "SCMP_ACT_ALLOW", 32 Args: []specs.LinuxSeccompArg{{ 33 Index: 0, 34 Value: 2114060288, 35 ValueTwo: 0, 36 Op: "SCMP_CMP_MASKED_EQ", 37 }}, 38 }, 39 { 40 41 Names: []string{"open"}, 42 Action: "SCMP_ACT_ALLOW", 43 Args: []specs.LinuxSeccompArg{}, 44 }, 45 { 46 Names: []string{"close"}, 47 Action: "SCMP_ACT_ALLOW", 48 Args: []specs.LinuxSeccompArg{}, 49 }, 50 { 51 Names: []string{"syslog"}, 52 Action: "SCMP_ACT_ERRNO", 53 ErrnoRet: &expectedErrno, 54 Args: []specs.LinuxSeccompArg{}, 55 }, 56 }, 57 } 58 59 assert.DeepEqual(t, expected, *p) 60 } 61 62 // TestLoadLegacyProfile tests loading a seccomp profile in the old format 63 // (before https://github.com/docker/docker/pull/24510) 64 func TestLoadLegacyProfile(t *testing.T) { 65 f, err := ioutil.ReadFile("fixtures/default-old-format.json") 66 if err != nil { 67 t.Fatal(err) 68 } 69 rs := createSpec() 70 if _, err := LoadProfile(string(f), &rs); err != nil { 71 t.Fatal(err) 72 } 73 } 74 75 func TestLoadDefaultProfile(t *testing.T) { 76 f, err := ioutil.ReadFile("default.json") 77 if err != nil { 78 t.Fatal(err) 79 } 80 rs := createSpec() 81 if _, err := LoadProfile(string(f), &rs); err != nil { 82 t.Fatal(err) 83 } 84 } 85 86 func TestUnmarshalDefaultProfile(t *testing.T) { 87 expected := DefaultProfile() 88 if expected == nil { 89 t.Skip("seccomp not supported") 90 } 91 92 f, err := ioutil.ReadFile("default.json") 93 if err != nil { 94 t.Fatal(err) 95 } 96 var profile Seccomp 97 err = json.Unmarshal(f, &profile) 98 if err != nil { 99 t.Fatal(err) 100 } 101 assert.DeepEqual(t, expected.Architectures, profile.Architectures) 102 assert.DeepEqual(t, expected.ArchMap, profile.ArchMap) 103 assert.DeepEqual(t, expected.DefaultAction, profile.DefaultAction) 104 assert.DeepEqual(t, expected.Syscalls, profile.Syscalls) 105 } 106 107 func TestMarshalUnmarshalFilter(t *testing.T) { 108 t.Parallel() 109 tests := []struct { 110 in string 111 out string 112 error bool 113 }{ 114 {in: `{"arches":["s390x"],"minKernel":3}`, error: true}, 115 {in: `{"arches":["s390x"],"minKernel":3.12}`, error: true}, 116 {in: `{"arches":["s390x"],"minKernel":true}`, error: true}, 117 {in: `{"arches":["s390x"],"minKernel":"0.0"}`, error: true}, 118 {in: `{"arches":["s390x"],"minKernel":"3"}`, error: true}, 119 {in: `{"arches":["s390x"],"minKernel":".3"}`, error: true}, 120 {in: `{"arches":["s390x"],"minKernel":"3."}`, error: true}, 121 {in: `{"arches":["s390x"],"minKernel":"true"}`, error: true}, 122 {in: `{"arches":["s390x"],"minKernel":"3.12.1\""}`, error: true}, 123 {in: `{"arches":["s390x"],"minKernel":"4.15abc"}`, error: true}, 124 {in: `{"arches":["s390x"],"minKernel":null}`, out: `{"arches":["s390x"]}`}, 125 {in: `{"arches":["s390x"],"minKernel":""}`, out: `{"arches":["s390x"],"minKernel":""}`}, // FIXME: try to fix omitempty for this 126 {in: `{"arches":["s390x"],"minKernel":"0.5"}`, out: `{"arches":["s390x"],"minKernel":"0.5"}`}, 127 {in: `{"arches":["s390x"],"minKernel":"0.50"}`, out: `{"arches":["s390x"],"minKernel":"0.50"}`}, 128 {in: `{"arches":["s390x"],"minKernel":"5.0"}`, out: `{"arches":["s390x"],"minKernel":"5.0"}`}, 129 {in: `{"arches":["s390x"],"minKernel":"50.0"}`, out: `{"arches":["s390x"],"minKernel":"50.0"}`}, 130 {in: `{"arches":["s390x"],"minKernel":"4.15"}`, out: `{"arches":["s390x"],"minKernel":"4.15"}`}, 131 } 132 for _, tc := range tests { 133 tc := tc 134 t.Run(tc.in, func(t *testing.T) { 135 var filter Filter 136 err := json.Unmarshal([]byte(tc.in), &filter) 137 if tc.error { 138 if err == nil { 139 t.Fatal("expected an error") 140 } else if !strings.Contains(err.Error(), "invalid kernel version") { 141 t.Fatal("unexpected error:", err) 142 } 143 return 144 } 145 if err != nil { 146 t.Fatal(err) 147 } 148 out, err := json.Marshal(filter) 149 if err != nil { 150 t.Fatal(err) 151 } 152 if string(out) != tc.out { 153 t.Fatalf("expected %s, got %s", tc.out, string(out)) 154 } 155 }) 156 } 157 } 158 159 func TestLoadConditional(t *testing.T) { 160 f, err := ioutil.ReadFile("fixtures/conditional_include.json") 161 if err != nil { 162 t.Fatal(err) 163 } 164 tests := []struct { 165 doc string 166 cap string 167 expected []string 168 }{ 169 {doc: "no caps", expected: []string{"chmod", "ptrace"}}, 170 {doc: "with syslog", cap: "CAP_SYSLOG", expected: []string{"chmod", "syslog", "ptrace"}}, 171 {doc: "no ptrace", cap: "CAP_SYS_ADMIN", expected: []string{"chmod"}}, 172 } 173 174 for _, tc := range tests { 175 tc := tc 176 t.Run(tc.doc, func(t *testing.T) { 177 rs := createSpec(tc.cap) 178 p, err := LoadProfile(string(f), &rs) 179 if err != nil { 180 t.Fatal(err) 181 } 182 if len(p.Syscalls) != len(tc.expected) { 183 t.Fatalf("expected %d syscalls in profile, have %d", len(tc.expected), len(p.Syscalls)) 184 } 185 for i, v := range p.Syscalls { 186 if v.Names[0] != tc.expected[i] { 187 t.Fatalf("expected %s syscall, have %s", tc.expected[i], v.Names[0]) 188 } 189 } 190 }) 191 } 192 } 193 194 // createSpec() creates a minimum spec for testing 195 func createSpec(caps ...string) specs.Spec { 196 rs := specs.Spec{ 197 Process: &specs.Process{ 198 Capabilities: &specs.LinuxCapabilities{}, 199 }, 200 } 201 if caps != nil { 202 rs.Process.Capabilities.Bounding = append(rs.Process.Capabilities.Bounding, caps...) 203 } 204 return rs 205 }