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  }