github.com/rigado/snapd@v2.42.5-go-mod+incompatible/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  package seccomp_test
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"testing"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	seccomp "github.com/snapcore/snapd/sandbox/seccomp"
    29  	"github.com/snapcore/snapd/testutil"
    30  )
    31  
    32  type compilerSuite struct{}
    33  
    34  var _ = Suite(&compilerSuite{})
    35  
    36  func TestSeccomp(t *testing.T) { TestingT(t) }
    37  
    38  func fromCmd(c *C, cmd *testutil.MockCmd) func(string) (string, error) {
    39  	return func(name string) (string, error) {
    40  		c.Check(name, Equals, "snap-seccomp")
    41  		return cmd.Exe(), nil
    42  	}
    43  }
    44  
    45  func (s *compilerSuite) TestVersionInfoValidate(c *C) {
    46  
    47  	for i, tc := range []struct {
    48  		v   string
    49  		exp string
    50  		err string
    51  	}{
    52  		// all valid
    53  		// 20-byte sha1 build ID added by GNU ld
    54  		{"7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c bpf-actlog", "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c bpf-actlog", ""},
    55  		{"7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c foo:bar", "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c foo:bar", ""},
    56  		{"7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", ""},
    57  		// 16-byte md5/uuid build ID added by GNU ld
    58  		{"3817b197e7abe71a952c1245e8bdf8d9 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", "3817b197e7abe71a952c1245e8bdf8d9 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", ""},
    59  		// 83-byte Go build ID
    60  		{"4e444571495f482d30796b5f57307065544e47692f594c61795f384b7a5258362d6a6f4272736e38302f773374475869496e433176527749797a457a4b532f3967324d4f76556f3130323644572d56326e6248 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", "4e444571495f482d30796b5f57307065544e47692f594c61795f384b7a5258362d6a6f4272736e38302f773374475869496e433176527749797a457a4b532f3967324d4f76556f3130323644572d56326e6248 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c -", ""},
    61  		// sanity
    62  		{"abcdef 0.0.0 abcd bpf-actlog", "abcdef 0.0.0 abcd bpf-actlog", ""},
    63  		{"abcdef 0.0.0 abcd -", "abcdef 0.0.0 abcd -", ""},
    64  
    65  		// invalid all the way down from here
    66  		// this is over/under the sane length limit for the fields
    67  		{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 2.4.1 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    68  		{"0000000000000000000000000000000000000000 123456.0.0 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    69  		{"0000000000000000000000000000000000000000 0.123456.0 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    70  		{"0000000000000000000000000000000000000000 0.0.123456 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    71  		{"0000000000000000000000000000000000000000 2.4.1 00000000000000000000000000000000000000000000000000000000000000001 -", "", "invalid format of version-info: .*"},
    72  		{"0000000000000000000000000000000000000000 2.4.1 0000000000000000000000000000000000000000000000000000000000000000 012345678901234567890123456789a", "", "invalid format of version-info: .*"},
    73  		{"0000000000000000000000000000000000000000 .4.1 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    74  		{"0000000000000000000000000000000000000000 2.4 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    75  		{"0000000000000000000000000000000000000000 2.4. 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    76  		{"0000000000000000000000000000000000000000 2..1 0000000000000000000000000000000000000000000000000000000000000000 -", "", "invalid format of version-info: .*"},
    77  		{"0000000000000000000000000000000000000000 2.4.1 0000000000000000000000000000000000000000000000000000000000000000 ", "", "invalid format of version-info: .*"},
    78  		// incorrect format
    79  		{"abcd 0.0.0 fg", "", "invalid format of version-info: .*"},
    80  		{"ggg 0.0.0 abc", "", "invalid format of version-info: .*"},
    81  		{"foo", "", "invalid format of version-info: .*"},
    82  		{"1", "", "invalid format of version-info: .*"},
    83  		{"i\ncan\nhave\nnewlines", "", "invalid format of version-info: .*"},
    84  		{"# invalid", "", "invalid format of version-info: .*"},
    85  		{"-1", "", "invalid format of version-info: .*"},
    86  	} {
    87  		c.Logf("tc: %v", i)
    88  		cmd := testutil.MockCommand(c, "snap-seccomp", fmt.Sprintf("echo \"%s\"", tc.v))
    89  		compiler, err := seccomp.New(fromCmd(c, cmd))
    90  		c.Assert(err, IsNil)
    91  
    92  		v, err := compiler.VersionInfo()
    93  		if tc.err != "" {
    94  			c.Check(err, ErrorMatches, tc.err)
    95  			c.Check(v, Equals, seccomp.VersionInfo(""))
    96  		} else {
    97  			c.Check(err, IsNil)
    98  			c.Check(v, Equals, seccomp.VersionInfo(tc.exp))
    99  			_, err := seccomp.VersionInfo(v).LibseccompVersion()
   100  			c.Check(err, IsNil)
   101  			_, err = seccomp.VersionInfo(v).Features()
   102  			c.Check(err, IsNil)
   103  		}
   104  		c.Check(cmd.Calls(), DeepEquals, [][]string{
   105  			{"snap-seccomp", "version-info"},
   106  		})
   107  		cmd.Restore()
   108  	}
   109  
   110  }
   111  
   112  func (s *compilerSuite) TestCompilerVersionInfo(c *C) {
   113  	const vi = "7ac348ac9c934269214b00d1692dfa50d5d4a157 2.3.3 03e996919907bc7163bc83b95bca0ecab31300f20dfa365ea14047c698340e7c bpf-actlog"
   114  	cmd := testutil.MockCommand(c, "snap-seccomp", fmt.Sprintf(`echo "%s"`, vi))
   115  
   116  	vi1, err := seccomp.CompilerVersionInfo(fromCmd(c, cmd))
   117  	c.Check(err, IsNil)
   118  	c.Check(vi1, Equals, seccomp.VersionInfo(vi))
   119  }
   120  
   121  func (s *compilerSuite) TestEmptyVersionInfo(c *C) {
   122  	vi := seccomp.VersionInfo("")
   123  
   124  	_, err := vi.LibseccompVersion()
   125  	c.Check(err, ErrorMatches, "empty version-info")
   126  
   127  	_, err = vi.Features()
   128  	c.Check(err, ErrorMatches, "empty version-info")
   129  }
   130  
   131  func (s *compilerSuite) TestVersionInfoUnhappy(c *C) {
   132  	cmd := testutil.MockCommand(c, "snap-seccomp", `
   133  if [ "$1" = "version-info" ]; then echo "unknown command version-info"; exit 1; fi
   134  exit 0
   135  `)
   136  	defer cmd.Restore()
   137  	compiler, err := seccomp.New(fromCmd(c, cmd))
   138  	c.Assert(err, IsNil)
   139  
   140  	_, err = compiler.VersionInfo()
   141  	c.Assert(err, ErrorMatches, "unknown command version-info")
   142  	c.Check(cmd.Calls(), DeepEquals, [][]string{
   143  		{"snap-seccomp", "version-info"},
   144  	})
   145  }
   146  
   147  func (s *compilerSuite) TestCompileEasy(c *C) {
   148  	cmd := testutil.MockCommand(c, "snap-seccomp", `
   149  if [ "$1" = "compile" ]; then exit 0; fi
   150  exit 1
   151  `)
   152  	defer cmd.Restore()
   153  	compiler, err := seccomp.New(fromCmd(c, cmd))
   154  	c.Assert(err, IsNil)
   155  
   156  	err = compiler.Compile("foo.src", "foo.bin")
   157  	c.Assert(err, IsNil)
   158  	c.Check(cmd.Calls(), DeepEquals, [][]string{
   159  		{"snap-seccomp", "compile", "foo.src", "foo.bin"},
   160  	})
   161  }
   162  
   163  func (s *compilerSuite) TestCompileUnhappy(c *C) {
   164  	cmd := testutil.MockCommand(c, "snap-seccomp", `
   165  if [ "$1" = "compile" ]; then echo "i will not"; exit 1; fi
   166  exit 0
   167  `)
   168  	defer cmd.Restore()
   169  	compiler, err := seccomp.New(fromCmd(c, cmd))
   170  	c.Assert(err, IsNil)
   171  
   172  	err = compiler.Compile("foo.src", "foo.bin")
   173  	c.Assert(err, ErrorMatches, "i will not")
   174  	c.Check(cmd.Calls(), DeepEquals, [][]string{
   175  		{"snap-seccomp", "compile", "foo.src", "foo.bin"},
   176  	})
   177  }
   178  
   179  func (s *compilerSuite) TestCompilerNewUnhappy(c *C) {
   180  	compiler, err := seccomp.New(func(name string) (string, error) { return "", errors.New("failed") })
   181  	c.Assert(err, ErrorMatches, "failed")
   182  	c.Assert(compiler, IsNil)
   183  
   184  	c.Assert(func() { seccomp.New(nil) }, PanicMatches, "lookup tool func not provided")
   185  }
   186  
   187  func (s *compilerSuite) TestLibseccompVersion(c *C) {
   188  	v, err := seccomp.VersionInfo("a 2.4.1 b -").LibseccompVersion()
   189  	c.Assert(err, IsNil)
   190  	c.Check(v, Equals, "2.4.1")
   191  
   192  	v, err = seccomp.VersionInfo("a phooey b -").LibseccompVersion()
   193  	c.Assert(err, ErrorMatches, "invalid format of version-info: .*")
   194  	c.Check(v, Equals, "")
   195  }
   196  
   197  func (s *compilerSuite) TestGetGoSeccompFeatures(c *C) {
   198  	for _, tc := range []struct {
   199  		v   string
   200  		exp string
   201  		err string
   202  	}{
   203  		// valid
   204  		{"a 2.4.1 b -", "-", ""},
   205  		{"a 2.4.1 b foo", "foo", ""},
   206  		{"a 2.4.1 b foo:bar", "foo:bar", ""},
   207  		// invalid
   208  		{"a 2.4.1 b b@rf", "", "invalid format of version-info: .*"},
   209  	} {
   210  		v, err := seccomp.VersionInfo(tc.v).Features()
   211  		if err == nil {
   212  			c.Assert(err, IsNil)
   213  			c.Check(v, Equals, tc.exp)
   214  		} else {
   215  			c.Assert(err, ErrorMatches, "invalid format of version-info: .*")
   216  			c.Check(v, Equals, tc.exp)
   217  		}
   218  	}
   219  }
   220  
   221  func (s *compilerSuite) TestHasFeature(c *C) {
   222  	for _, tc := range []struct {
   223  		v   string
   224  		f   string
   225  		exp bool
   226  		err string
   227  	}{
   228  		// valid negative
   229  		{"a 2.4.1 b -", "foo", false, ""},
   230  		{"a 2.4.1 b foo:bar", "foo:bar", false, ""},
   231  		// valid affirmative
   232  		{"a 2.4.1 b foo", "foo", true, ""},
   233  		{"a 2.4.1 b foo:bar", "foo", true, ""},
   234  		{"a 2.4.1 b foo:bar", "bar", true, ""},
   235  		// invalid
   236  		{"a 1.2.3 b b@rf", "b@rf", false, "invalid format of version-info: .*"},
   237  	} {
   238  		v, err := seccomp.VersionInfo(tc.v).HasFeature(tc.f)
   239  		if err == nil {
   240  			c.Assert(err, IsNil)
   241  			c.Check(v, Equals, tc.exp)
   242  		} else {
   243  			c.Assert(err, ErrorMatches, "invalid format of version-info: .*")
   244  			c.Check(v, Equals, tc.exp)
   245  		}
   246  	}
   247  }
   248  
   249  func (s *compilerSuite) TestSupportsRobustArgumentFiltering(c *C) {
   250  	for _, tc := range []struct {
   251  		v   string
   252  		err string
   253  	}{
   254  		// libseccomp < 2.3.3 and golang-seccomp < 0.9.1
   255  		{"a 2.3.3 b -", "robust argument filtering requires a snapd built against libseccomp >= 2.4, golang-seccomp >= 0.9.1"},
   256  		// libseccomp < 2.3.3
   257  		{"a 2.3.3 b bpf-actlog", "robust argument filtering requires a snapd built against libseccomp >= 2.4"},
   258  		// golang-seccomp < 0.9.1
   259  		{"a 2.4.1 b -", "robust argument filtering requires a snapd built against golang-seccomp >= 0.9.1"},
   260  		{"a 2.4.1 b bpf-other", "robust argument filtering requires a snapd built against golang-seccomp >= 0.9.1"},
   261  		// libseccomp >= 2.4.1 and golang-seccomp >= 0.9.1
   262  		{"a 2.4.1 b bpf-actlog", ""},
   263  		{"a 3.0.0 b bpf-actlog", ""},
   264  		// invalid
   265  		{"a 1.2.3 b b@rf", "invalid format of version-info: .*"},
   266  	} {
   267  		err := seccomp.VersionInfo(tc.v).SupportsRobustArgumentFiltering()
   268  		if tc.err == "" {
   269  			c.Assert(err, IsNil)
   270  		} else {
   271  			c.Assert(err, ErrorMatches, tc.err)
   272  		}
   273  	}
   274  }