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  }