github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/sandbox/seccomp/compiler_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package seccomp_test 21 22 import ( 23 "errors" 24 "fmt" 25 "testing" 26 27 . "gopkg.in/check.v1" 28 29 seccomp "github.com/snapcore/snapd/sandbox/seccomp" 30 "github.com/snapcore/snapd/testutil" 31 ) 32 33 type compilerSuite struct{} 34 35 var _ = Suite(&compilerSuite{}) 36 37 func TestSeccomp(t *testing.T) { TestingT(t) } 38 39 func fromCmd(c *C, cmd *testutil.MockCmd) func(string) (string, error) { 40 return func(name string) (string, error) { 41 c.Check(name, Equals, "snap-seccomp") 42 return cmd.Exe(), nil 43 } 44 } 45 46 func (s *compilerSuite) TestVersionInfoValidate(c *C) { 47 48 for i, tc := range []struct { 49 v string 50 exp string 51 err string 52 }{ 53 // all valid 54 // 20-byte sha1 build ID added by GNU ld 55 {"7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c bpf-actlog", "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c bpf-actlog", ""}, 56 {"7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c foo:bar", "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c foo:bar", ""}, 57 {"7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", ""}, 58 // 16-byte md5/uuid build ID added by GNU ld 59 {"3817b197e7abe71a952c1245e8bdf8d9 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", "3817b197e7abe71a952c1245e8bdf8d9 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", ""}, 60 // 83-byte Go build ID 61 {"4e444571495f482d30796b5f57307065544e47692f594c61795f384b7a5258362d6a6f4272736e38302f773374475869496e433176527749797a457a4b532f3967324d4f76556f3130323644572d56326e6248 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", "4e444571495f482d30796b5f57307065544e47692f594c61795f384b7a5258362d6a6f4272736e38302f773374475869496e433176527749797a457a4b532f3967324d4f76556f3130323644572d56326e6248 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", ""}, 62 // sanity 63 {"abcdef 0.0.0 abcd bpf-actlog", "abcdef 0.0.0 abcd bpf-actlog", ""}, 64 {"abcdef 0.0.0 abcd -", "abcdef 0.0.0 abcd -", ""}, 65 66 // invalid all the way down from here 67 // this is over/under the sane length limit for the fields 68 {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 2.4.1 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 69 {"0000000000000000000000000000000000000000 123456.0.0 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 70 {"0000000000000000000000000000000000000000 0.123456.0 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 71 {"0000000000000000000000000000000000000000 0.0.123456 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 72 {"0000000000000000000000000000000000000000 2.4.1 00000000000000000000000000000000000000000000000000000000000000001 -", "", "invalid format of version-info: .*"}, 73 {"0000000000000000000000000000000000000000 2.4.1 0000000000000000000000000000000000000000000000000000000000000000 012345678901234567890123456789a", "", "invalid format of version-info: .*"}, 74 {"0000000000000000000000000000000000000000 .4.1 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 75 {"0000000000000000000000000000000000000000 2.4 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 76 {"0000000000000000000000000000000000000000 2.4. 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 77 {"0000000000000000000000000000000000000000 2..1 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"}, 78 {"0000000000000000000000000000000000000000 2.4.1 0000000000000000000000000000000000000000000000000000000000000000 ", "", "invalid format of version-info: .*"}, 79 // incorrect format 80 {"abcd 0.0.0 fg", "", "invalid format of version-info: .*"}, 81 {"ggg 0.0.0 abc", "", "invalid format of version-info: .*"}, 82 {"foo", "", "invalid format of version-info: .*"}, 83 {"1", "", "invalid format of version-info: .*"}, 84 {"i\ncan\nhave\nnewlines", "", "invalid format of version-info: .*"}, 85 {"# invalid", "", "invalid format of version-info: .*"}, 86 {"-1", "", "invalid format of version-info: .*"}, 87 } { 88 c.Logf("tc: %v", i) 89 cmd := testutil.MockCommand(c, "snap-seccomp", fmt.Sprintf("echo \"%s\"", tc.v)) 90 compiler, err := seccomp.NewCompiler(fromCmd(c, cmd)) 91 c.Assert(err, IsNil) 92 93 v, err := compiler.VersionInfo() 94 if tc.err != "" { 95 c.Check(err, ErrorMatches, tc.err) 96 c.Check(v, Equals, seccomp.VersionInfo("")) 97 } else { 98 c.Check(err, IsNil) 99 c.Check(v, Equals, seccomp.VersionInfo(tc.exp)) 100 _, err := seccomp.VersionInfo(v).LibseccompVersion() 101 c.Check(err, IsNil) 102 _, err = seccomp.VersionInfo(v).Features() 103 c.Check(err, IsNil) 104 } 105 c.Check(cmd.Calls(), DeepEquals, [][]string{ 106 {"snap-seccomp", "version-info"}, 107 }) 108 cmd.Restore() 109 } 110 111 } 112 113 func (s *compilerSuite) TestCompilerVersionInfo(c *C) { 114 const vi = "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c bpf-actlog" 115 cmd := testutil.MockCommand(c, "snap-seccomp", fmt.Sprintf(`echo "%s"`, vi)) 116 117 vi1, err := seccomp.CompilerVersionInfo(fromCmd(c, cmd)) 118 c.Check(err, IsNil) 119 c.Check(vi1, Equals, seccomp.VersionInfo(vi)) 120 } 121 122 func (s *compilerSuite) TestEmptyVersionInfo(c *C) { 123 vi := seccomp.VersionInfo("") 124 125 _, err := vi.LibseccompVersion() 126 c.Check(err, ErrorMatches, "empty version-info") 127 128 _, err = vi.Features() 129 c.Check(err, ErrorMatches, "empty version-info") 130 } 131 132 func (s *compilerSuite) TestVersionInfoUnhappy(c *C) { 133 cmd := testutil.MockCommand(c, "snap-seccomp", ` 134 if [ "$1" = "version-info" ]; then echo "unknown command version-info"; exit 1; fi 135 exit 0 136 `) 137 defer cmd.Restore() 138 compiler, err := seccomp.NewCompiler(fromCmd(c, cmd)) 139 c.Assert(err, IsNil) 140 141 _, err = compiler.VersionInfo() 142 c.Assert(err, ErrorMatches, "unknown command version-info") 143 c.Check(cmd.Calls(), DeepEquals, [][]string{ 144 {"snap-seccomp", "version-info"}, 145 }) 146 } 147 148 func (s *compilerSuite) TestCompileEasy(c *C) { 149 cmd := testutil.MockCommand(c, "snap-seccomp", ` 150 if [ "$1" = "compile" ]; then exit 0; fi 151 exit 1 152 `) 153 defer cmd.Restore() 154 compiler, err := seccomp.NewCompiler(fromCmd(c, cmd)) 155 c.Assert(err, IsNil) 156 157 err = compiler.Compile("foo.src", "foo.bin") 158 c.Assert(err, IsNil) 159 c.Check(cmd.Calls(), DeepEquals, [][]string{ 160 {"snap-seccomp", "compile", "foo.src", "foo.bin"}, 161 }) 162 } 163 164 func (s *compilerSuite) TestCompileUnhappy(c *C) { 165 cmd := testutil.MockCommand(c, "snap-seccomp", ` 166 if [ "$1" = "compile" ]; then echo "i will not"; exit 1; fi 167 exit 0 168 `) 169 defer cmd.Restore() 170 compiler, err := seccomp.NewCompiler(fromCmd(c, cmd)) 171 c.Assert(err, IsNil) 172 173 err = compiler.Compile("foo.src", "foo.bin") 174 c.Assert(err, ErrorMatches, "i will not") 175 c.Check(cmd.Calls(), DeepEquals, [][]string{ 176 {"snap-seccomp", "compile", "foo.src", "foo.bin"}, 177 }) 178 } 179 180 func (s *compilerSuite) TestCompilerNewUnhappy(c *C) { 181 compiler, err := seccomp.NewCompiler(func(name string) (string, error) { return "", errors.New("failed") }) 182 c.Assert(err, ErrorMatches, "failed") 183 c.Assert(compiler, IsNil) 184 185 c.Assert(func() { seccomp.NewCompiler(nil) }, PanicMatches, "lookup tool func not provided") 186 } 187 188 func (s *compilerSuite) TestLibseccompVersion(c *C) { 189 v, err := seccomp.VersionInfo("a 2.4.1 b -").LibseccompVersion() 190 c.Assert(err, IsNil) 191 c.Check(v, Equals, "2.4.1") 192 193 v, err = seccomp.VersionInfo("a phooey b -").LibseccompVersion() 194 c.Assert(err, ErrorMatches, "invalid format of version-info: .*") 195 c.Check(v, Equals, "") 196 } 197 198 func (s *compilerSuite) TestGetGoSeccompFeatures(c *C) { 199 for _, tc := range []struct { 200 v string 201 exp string 202 err string 203 }{ 204 // valid 205 {"a 2.4.1 b -", "-", ""}, 206 {"a 2.4.1 b foo", "foo", ""}, 207 {"a 2.4.1 b foo:bar", "foo:bar", ""}, 208 // invalid 209 {"a 2.4.1 b b@rf", "", "invalid format of version-info: .*"}, 210 } { 211 v, err := seccomp.VersionInfo(tc.v).Features() 212 if err == nil { 213 c.Assert(err, IsNil) 214 c.Check(v, Equals, tc.exp) 215 } else { 216 c.Assert(err, ErrorMatches, "invalid format of version-info: .*") 217 c.Check(v, Equals, tc.exp) 218 } 219 } 220 } 221 222 func (s *compilerSuite) TestHasFeature(c *C) { 223 for _, tc := range []struct { 224 v string 225 f string 226 exp bool 227 err string 228 }{ 229 // valid negative 230 {"a 2.4.1 b -", "foo", false, ""}, 231 {"a 2.4.1 b foo:bar", "foo:bar", false, ""}, 232 // valid affirmative 233 {"a 2.4.1 b foo", "foo", true, ""}, 234 {"a 2.4.1 b foo:bar", "foo", true, ""}, 235 {"a 2.4.1 b foo:bar", "bar", true, ""}, 236 // invalid 237 {"a 1.2.3 b b@rf", "b@rf", false, "invalid format of version-info: .*"}, 238 } { 239 v, err := seccomp.VersionInfo(tc.v).HasFeature(tc.f) 240 if err == nil { 241 c.Assert(err, IsNil) 242 c.Check(v, Equals, tc.exp) 243 } else { 244 c.Assert(err, ErrorMatches, "invalid format of version-info: .*") 245 c.Check(v, Equals, tc.exp) 246 } 247 } 248 } 249 250 func (s *compilerSuite) TestSupportsRobustArgumentFiltering(c *C) { 251 for _, tc := range []struct { 252 v string 253 err string 254 }{ 255 // libseccomp < 2.3.3 and golang-seccomp < 0.9.1 256 {"a 2.3.3 b -", "robust argument filtering requires a snapd built against libseccomp >= 2.4, golang-seccomp >= 0.9.1"}, 257 // libseccomp < 2.3.3 258 {"a 2.3.3 b bpf-actlog", "robust argument filtering requires a snapd built against libseccomp >= 2.4"}, 259 // golang-seccomp < 0.9.1 260 {"a 2.4.1 b -", "robust argument filtering requires a snapd built against golang-seccomp >= 0.9.1"}, 261 {"a 2.4.1 b bpf-other", "robust argument filtering requires a snapd built against golang-seccomp >= 0.9.1"}, 262 // libseccomp >= 2.4.1 and golang-seccomp >= 0.9.1 263 {"a 2.4.1 b bpf-actlog", ""}, 264 {"a 3.0.0 b bpf-actlog", ""}, 265 // invalid 266 {"a 1.2.3 b b@rf", "invalid format of version-info: .*"}, 267 } { 268 err := seccomp.VersionInfo(tc.v).SupportsRobustArgumentFiltering() 269 if tc.err == "" { 270 c.Assert(err, IsNil) 271 } else { 272 c.Assert(err, ErrorMatches, tc.err) 273 } 274 } 275 } 276 277 func (s *compilerSuite) TestCompilerStdoutOnly(c *C) { 278 const vi = "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c bpf-actlog" 279 cmd := testutil.MockCommand(c, "snap-seccomp", fmt.Sprintf(` 280 echo "this goes to stderr" >&2 281 # this goes to stdout 282 echo "%s" 283 `, vi)) 284 285 vi1, err := seccomp.CompilerVersionInfo(fromCmd(c, cmd)) 286 c.Check(err, IsNil) 287 c.Check(vi1, Equals, seccomp.VersionInfo(vi)) 288 } 289 290 func (s *compilerSuite) TestCompilerStderrErr(c *C) { 291 cmd := testutil.MockCommand(c, "snap-seccomp", fmt.Sprintf(` 292 echo "this goes to stderr" >&2 293 # this goes to stdout 294 echo "this goes to stdout" 295 exit 1`)) 296 297 _, err := seccomp.CompilerVersionInfo(fromCmd(c, cmd)) 298 c.Assert(err, ErrorMatches, "this goes to stderr") 299 }