mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
* plugin sandboxing * remove unused type * better symlink handling, better remounting, better test, whitespace fixes, and comment on the remounting * fix test compile error * big simplification for getting mount flags * mask statfs flags to the ones we're interested in
211 lines
5.8 KiB
Go
211 lines
5.8 KiB
Go
// 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)
|
|
}
|
|
})
|
|
}
|
|
}
|