summaryrefslogtreecommitdiffstats
path: root/plugin/rpcplugin/sandbox/seccomp_linux_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/rpcplugin/sandbox/seccomp_linux_test.go')
-rw-r--r--plugin/rpcplugin/sandbox/seccomp_linux_test.go210
1 files changed, 210 insertions, 0 deletions
diff --git a/plugin/rpcplugin/sandbox/seccomp_linux_test.go b/plugin/rpcplugin/sandbox/seccomp_linux_test.go
new file mode 100644
index 000000000..46fe38fe0
--- /dev/null
+++ b/plugin/rpcplugin/sandbox/seccomp_linux_test.go
@@ -0,0 +1,210 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package sandbox
+
+import (
+ "encoding/binary"
+ "syscall"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/net/bpf"
+)
+
+func seccompData(nr int32, arch uint32, ip uint64, args ...uint64) []byte {
+ var buf [64]byte
+ binary.BigEndian.PutUint32(buf[0:], uint32(nr))
+ binary.BigEndian.PutUint32(buf[4:], arch)
+ binary.BigEndian.PutUint64(buf[8:], ip)
+ for i := 0; i < 6 && i < len(args); i++ {
+ binary.BigEndian.PutUint64(buf[16+i*8:], args[i])
+ }
+ return buf[:]
+}
+
+func TestSeccompFilter(t *testing.T) {
+ for name, tc := range map[string]struct {
+ Filter []bpf.Instruction
+ Data []byte
+ Expected bool
+ }{
+ "Allowed": {
+ Filter: SeccompFilter(0xf00, []SeccompSyscall{
+ {Syscall: syscall.SYS_READ},
+ {Syscall: syscall.SYS_WRITE},
+ }),
+ Data: seccompData(syscall.SYS_READ, 0xf00, 0),
+ Expected: true,
+ },
+ "AllFail": {
+ Filter: SeccompFilter(0xf00, []SeccompSyscall{
+ {
+ Syscall: syscall.SYS_READ,
+ Any: []SeccompConditions{
+ {All: []SeccompCondition{
+ &SeccompArgHasAnyBit{Arg: 0, Mask: 2},
+ &SeccompArgHasAnyBit{Arg: 1, Mask: 2},
+ &SeccompArgHasAnyBit{Arg: 2, Mask: 2},
+ &SeccompArgHasAnyBit{Arg: 3, Mask: 2},
+ }},
+ },
+ },
+ {Syscall: syscall.SYS_WRITE},
+ }),
+ Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4),
+ Expected: false,
+ },
+ "AllPass": {
+ Filter: SeccompFilter(0xf00, []SeccompSyscall{
+ {
+ Syscall: syscall.SYS_READ,
+ Any: []SeccompConditions{
+ {All: []SeccompCondition{
+ &SeccompArgHasAnyBit{Arg: 0, Mask: 7},
+ &SeccompArgHasAnyBit{Arg: 1, Mask: 7},
+ &SeccompArgHasAnyBit{Arg: 2, Mask: 7},
+ &SeccompArgHasAnyBit{Arg: 3, Mask: 7},
+ }},
+ },
+ },
+ {Syscall: syscall.SYS_WRITE},
+ }),
+ Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4),
+ Expected: true,
+ },
+ "AnyFail": {
+ Filter: SeccompFilter(0xf00, []SeccompSyscall{
+ {
+ Syscall: syscall.SYS_READ,
+ Any: []SeccompConditions{
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 0, Mask: 8}}},
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 1, Mask: 8}}},
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 2, Mask: 8}}},
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 3, Mask: 8}}},
+ },
+ },
+ {Syscall: syscall.SYS_WRITE},
+ }),
+ Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4),
+ Expected: false,
+ },
+ "AnyPass": {
+ Filter: SeccompFilter(0xf00, []SeccompSyscall{
+ {
+ Syscall: syscall.SYS_READ,
+ Any: []SeccompConditions{
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 0, Mask: 2}}},
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 1, Mask: 2}}},
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 2, Mask: 2}}},
+ {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 3, Mask: 2}}},
+ },
+ },
+ {Syscall: syscall.SYS_WRITE},
+ }),
+ Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4),
+ Expected: true,
+ },
+ "BadArch": {
+ Filter: SeccompFilter(0xf00, []SeccompSyscall{
+ {Syscall: syscall.SYS_READ},
+ {Syscall: syscall.SYS_WRITE},
+ }),
+ Data: seccompData(syscall.SYS_MOUNT, 0xf01, 0),
+ Expected: false,
+ },
+ "BadSyscall": {
+ Filter: SeccompFilter(0xf00, []SeccompSyscall{
+ {Syscall: syscall.SYS_READ},
+ {Syscall: syscall.SYS_WRITE},
+ }),
+ Data: seccompData(syscall.SYS_MOUNT, 0xf00, 0),
+ Expected: false,
+ },
+ } {
+ t.Run(name, func(t *testing.T) {
+ vm, err := bpf.NewVM(tc.Filter)
+ require.NoError(t, err)
+ result, err := vm.Run(tc.Data)
+ require.NoError(t, err)
+ if tc.Expected {
+ assert.Equal(t, SECCOMP_RET_ALLOW, result)
+ } else {
+ assert.Equal(t, int(SECCOMP_RET_ERRNO|syscall.EPERM), result)
+ }
+ })
+ }
+}
+
+func TestSeccompFilter_Conditions(t *testing.T) {
+ for name, tc := range map[string]struct {
+ Condition SeccompCondition
+ Args []uint64
+ Expected bool
+ }{
+ "ArgHasAnyBitFail": {
+ Condition: SeccompArgHasAnyBit{Arg: 0, Mask: 0x0004},
+ Args: []uint64{0x0400008000},
+ Expected: false,
+ },
+ "ArgHasAnyBitPass1": {
+ Condition: SeccompArgHasAnyBit{Arg: 0, Mask: 0x400000004},
+ Args: []uint64{0x8000008004},
+ Expected: true,
+ },
+ "ArgHasAnyBitPass2": {
+ Condition: SeccompArgHasAnyBit{Arg: 0, Mask: 0x400000004},
+ Args: []uint64{0x8400008000},
+ Expected: true,
+ },
+ "ArgHasNoBitsFail1": {
+ Condition: SeccompArgHasNoBits{Arg: 0, Mask: 0x1100000011},
+ Args: []uint64{0x0000008007},
+ Expected: false,
+ },
+ "ArgHasNoBitsFail2": {
+ Condition: SeccompArgHasNoBits{Arg: 0, Mask: 0x1100000011},
+ Args: []uint64{0x0700008000},
+ Expected: false,
+ },
+ "ArgHasNoBitsPass": {
+ Condition: SeccompArgHasNoBits{Arg: 0, Mask: 0x400000004},
+ Args: []uint64{0x8000008000},
+ Expected: true,
+ },
+ "ArgEqualsPass": {
+ Condition: SeccompArgEquals{Arg: 0, Value: 0x123456789ABCDEF},
+ Args: []uint64{0x123456789ABCDEF},
+ Expected: true,
+ },
+ "ArgEqualsFail1": {
+ Condition: SeccompArgEquals{Arg: 0, Value: 0x123456789ABCDEF},
+ Args: []uint64{0x023456789ABCDEF},
+ Expected: false,
+ },
+ "ArgEqualsFail2": {
+ Condition: SeccompArgEquals{Arg: 0, Value: 0x123456789ABCDEF},
+ Args: []uint64{0x123456789ABCDE0},
+ Expected: false,
+ },
+ } {
+ t.Run(name, func(t *testing.T) {
+ filter := SeccompFilter(0xf00, []SeccompSyscall{
+ {
+ Syscall: 1,
+ Any: []SeccompConditions{{All: []SeccompCondition{tc.Condition}}},
+ },
+ })
+ vm, err := bpf.NewVM(filter)
+ require.NoError(t, err)
+ result, err := vm.Run(seccompData(1, 0xf00, 0, tc.Args...))
+ require.NoError(t, err)
+ if tc.Expected {
+ assert.Equal(t, SECCOMP_RET_ALLOW, result)
+ } else {
+ assert.Equal(t, int(SECCOMP_RET_ERRNO|syscall.EPERM), result)
+ }
+ })
+ }
+}