ABC-22: Plugin sandboxing for linux/amd64 (#8068)
* 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
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
7e5ce97668
Коммит
f5c8a71698
210
plugin/rpcplugin/sandbox/seccomp_linux_test.go
Обычный файл
210
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user