diff options
-rw-r--r-- | pkg/abi/linux/seccomp.go | 19 | ||||
-rw-r--r-- | pkg/abi/linux/signalfd.go | 4 | ||||
-rw-r--r-- | pkg/seccomp/BUILD | 2 | ||||
-rw-r--r-- | pkg/seccomp/seccomp_test.go | 246 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/signalfd/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/signalfd/signalfd.go | 14 | ||||
-rw-r--r-- | pkg/sentry/kernel/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/kernel/seccomp.go | 46 | ||||
-rw-r--r-- | pkg/sentry/kernel/signalfd/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/kernel/signalfd/signalfd.go | 14 | ||||
-rw-r--r-- | pkg/sentry/kernel/vdso.go | 19 | ||||
-rw-r--r-- | pkg/sentry/vfs/BUILD | 1 |
12 files changed, 196 insertions, 172 deletions
diff --git a/pkg/abi/linux/seccomp.go b/pkg/abi/linux/seccomp.go index b07cafe12..5be3f10f9 100644 --- a/pkg/abi/linux/seccomp.go +++ b/pkg/abi/linux/seccomp.go @@ -83,3 +83,22 @@ type SockFprog struct { pad [6]byte Filter *BPFInstruction } + +// SeccompData is equivalent to struct seccomp_data, which contains the data +// passed to seccomp-bpf filters. +// +// +marshal +type SeccompData struct { + // Nr is the system call number. + Nr int32 + + // Arch is an AUDIT_ARCH_* value indicating the system call convention. + Arch uint32 + + // InstructionPointer is the value of the instruction pointer at the time + // of the system call. + InstructionPointer uint64 + + // Args contains the first 6 system call arguments. + Args [6]uint64 +} diff --git a/pkg/abi/linux/signalfd.go b/pkg/abi/linux/signalfd.go index 85fad9956..468c6a387 100644 --- a/pkg/abi/linux/signalfd.go +++ b/pkg/abi/linux/signalfd.go @@ -23,6 +23,8 @@ const ( ) // SignalfdSiginfo is the siginfo encoding for signalfds. +// +// +marshal type SignalfdSiginfo struct { Signo uint32 Errno int32 @@ -41,5 +43,5 @@ type SignalfdSiginfo struct { STime uint64 Addr uint64 AddrLSB uint16 - _ [48]uint8 + _ [48]uint8 `marshal:"unaligned"` } diff --git a/pkg/seccomp/BUILD b/pkg/seccomp/BUILD index bdef7762c..e828894b0 100644 --- a/pkg/seccomp/BUILD +++ b/pkg/seccomp/BUILD @@ -49,7 +49,7 @@ go_test( library = ":seccomp", deps = [ "//pkg/abi/linux", - "//pkg/binary", "//pkg/bpf", + "//pkg/usermem", ], ) diff --git a/pkg/seccomp/seccomp_test.go b/pkg/seccomp/seccomp_test.go index 23f30678d..e1444d18b 100644 --- a/pkg/seccomp/seccomp_test.go +++ b/pkg/seccomp/seccomp_test.go @@ -28,17 +28,10 @@ import ( "time" "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/bpf" + "gvisor.dev/gvisor/pkg/usermem" ) -type seccompData struct { - nr uint32 - arch uint32 - instructionPointer uint64 - args [6]uint64 -} - // newVictim makes a victim binary. func newVictim() (string, error) { f, err := ioutil.TempFile("", "victim") @@ -58,9 +51,14 @@ func newVictim() (string, error) { return path, nil } -// asInput converts a seccompData to a bpf.Input. -func (d *seccompData) asInput() bpf.Input { - return bpf.InputBytes{binary.Marshal(nil, binary.LittleEndian, d), binary.LittleEndian} +// dataAsInput converts a linux.SeccompData to a bpf.Input. +func dataAsInput(d *linux.SeccompData) bpf.Input { + buf := make([]byte, d.SizeBytes()) + d.MarshalUnsafe(buf) + return bpf.InputBytes{ + Data: buf, + Order: usermem.ByteOrder, + } } func TestBasic(t *testing.T) { @@ -69,7 +67,7 @@ func TestBasic(t *testing.T) { desc string // data is the input data. - data seccompData + data linux.SeccompData // want is the expected return value of the BPF program. want linux.BPFAction @@ -95,12 +93,12 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "syscall allowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "syscall disallowed", - data: seccompData{nr: 2, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 2, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -131,22 +129,22 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "allowed (1a)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x1}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x1}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "allowed (1b)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, { desc: "syscall 1 matched 2nd rule", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, { desc: "no match", - data: seccompData{nr: 0, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 0, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_KILL_THREAD, }, }, @@ -168,42 +166,42 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "allowed (1)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "allowed (3)", - data: seccompData{nr: 3, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 3, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "allowed (5)", - data: seccompData{nr: 5, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 5, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "disallowed (0)", - data: seccompData{nr: 0, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 0, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, { desc: "disallowed (2)", - data: seccompData{nr: 2, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 2, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, { desc: "disallowed (4)", - data: seccompData{nr: 4, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 4, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, { desc: "disallowed (6)", - data: seccompData{nr: 6, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 6, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, { desc: "disallowed (100)", - data: seccompData{nr: 100, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 100, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -223,7 +221,7 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "arch (123)", - data: seccompData{nr: 1, arch: 123}, + data: linux.SeccompData{Nr: 1, Arch: 123}, want: linux.SECCOMP_RET_KILL_THREAD, }, }, @@ -243,7 +241,7 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "action trap", - data: seccompData{nr: 2, arch: LINUX_AUDIT_ARCH}, + data: linux.SeccompData{Nr: 2, Arch: LINUX_AUDIT_ARCH}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -268,12 +266,12 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "allowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0xf, 0xf}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xf}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "disallowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0xf, 0xe}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xe}}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -300,12 +298,12 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "match first rule", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0xf}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "match 2nd rule", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0xe}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xe}}, want: linux.SECCOMP_RET_ALLOW, }, }, @@ -331,28 +329,28 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "argument allowed (all match)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, - args: [6]uint64{0, math.MaxUint64 - 1, math.MaxUint32}, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, + Args: [6]uint64{0, math.MaxUint64 - 1, math.MaxUint32}, }, want: linux.SECCOMP_RET_ALLOW, }, { desc: "argument disallowed (one mismatch)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, - args: [6]uint64{0, math.MaxUint64, math.MaxUint32}, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, + Args: [6]uint64{0, math.MaxUint64, math.MaxUint32}, }, want: linux.SECCOMP_RET_TRAP, }, { desc: "argument disallowed (multiple mismatch)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, - args: [6]uint64{0, math.MaxUint64, math.MaxUint32 - 1}, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, + Args: [6]uint64{0, math.MaxUint64, math.MaxUint32 - 1}, }, want: linux.SECCOMP_RET_TRAP, }, @@ -379,28 +377,28 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "arg allowed", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, - args: [6]uint64{0, math.MaxUint64, math.MaxUint32 - 1}, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, + Args: [6]uint64{0, math.MaxUint64, math.MaxUint32 - 1}, }, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (one equal)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, - args: [6]uint64{0x7aabbccdd, math.MaxUint64, math.MaxUint32 - 1}, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, + Args: [6]uint64{0x7aabbccdd, math.MaxUint64, math.MaxUint32 - 1}, }, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (all equal)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, - args: [6]uint64{0x7aabbccdd, math.MaxUint64 - 1, math.MaxUint32}, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, + Args: [6]uint64{0x7aabbccdd, math.MaxUint64 - 1, math.MaxUint32}, }, want: linux.SECCOMP_RET_TRAP, }, @@ -429,27 +427,27 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "high 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000003_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits equal, low 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000003}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits equal, low 32bits equal", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits equal, low 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000001}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000001_00000003}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000003}}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -474,27 +472,27 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "arg allowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x10, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xffffffff}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (first arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0xf, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xffffffff}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (first arg smaller)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (second arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x10, 0xabcd000d}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xabcd000d}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (second arg smaller)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x10, 0xa000ffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xa000ffff}}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -522,27 +520,27 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "high 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000003_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits equal, low 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000003}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits equal, low 32bits equal", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits equal, low 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000001}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000001_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000002}}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -567,32 +565,32 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "arg allowed (both greater)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x10, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xffffffff}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg allowed (first arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0xf, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xffffffff}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (first arg smaller)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg allowed (second arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x10, 0xabcd000d}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xabcd000d}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (second arg smaller)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x10, 0xa000ffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xa000ffff}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (both arg smaller)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0xa000ffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xa000ffff}}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -620,27 +618,27 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "high 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000003_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits equal, low 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000003}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits equal, low 32bits equal", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits equal, low 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000001}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000001_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000002}}, want: linux.SECCOMP_RET_ALLOW, }, }, @@ -665,32 +663,32 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "arg allowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0x0}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0x0}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (first arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x1, 0x0}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x1, 0x0}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (first arg greater)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x2, 0x0}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0x0}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (second arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0xabcd000d}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xabcd000d}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (second arg greater)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (both arg greater)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x2, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0xffffffff}}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -718,27 +716,27 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "high 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000003_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits equal, low 32bits greater", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000003}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "high 32bits equal, low 32bits equal", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits equal, low 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000002_00000001}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "high 32bits less", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x00000001_00000002}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000002}}, want: linux.SECCOMP_RET_ALLOW, }, }, @@ -764,32 +762,32 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "arg allowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0x0}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0x0}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg allowed (first arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x1, 0x0}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x1, 0x0}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (first arg greater)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x2, 0x0}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0x0}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg allowed (second arg equal)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0xabcd000d}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xabcd000d}}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (second arg greater)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x0, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (both arg greater)", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{0x2, 0xffffffff}}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0xffffffff}}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -816,51 +814,51 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "arg allowed (low order mandatory bit)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, // 00000000 00000000 00000000 00000001 - args: [6]uint64{0x1}, + Args: [6]uint64{0x1}, }, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg allowed (low order optional bit)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, // 00000000 00000000 00000000 00000101 - args: [6]uint64{0x5}, + Args: [6]uint64{0x5}, }, want: linux.SECCOMP_RET_ALLOW, }, { desc: "arg disallowed (lowest order bit not set)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, // 00000000 00000000 00000000 00000010 - args: [6]uint64{0x2}, + Args: [6]uint64{0x2}, }, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (second lowest order bit set)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, // 00000000 00000000 00000000 00000011 - args: [6]uint64{0x3}, + Args: [6]uint64{0x3}, }, want: linux.SECCOMP_RET_TRAP, }, { desc: "arg disallowed (8th bit set)", - data: seccompData{ - nr: 1, - arch: LINUX_AUDIT_ARCH, + data: linux.SeccompData{ + Nr: 1, + Arch: LINUX_AUDIT_ARCH, // 00000000 00000000 00000001 00000000 - args: [6]uint64{0x100}, + Args: [6]uint64{0x100}, }, want: linux.SECCOMP_RET_TRAP, }, @@ -885,12 +883,12 @@ func TestBasic(t *testing.T) { specs: []spec{ { desc: "allowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{}, instructionPointer: 0x7aabbccdd}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{}, InstructionPointer: 0x7aabbccdd}, want: linux.SECCOMP_RET_ALLOW, }, { desc: "disallowed", - data: seccompData{nr: 1, arch: LINUX_AUDIT_ARCH, args: [6]uint64{}, instructionPointer: 0x711223344}, + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{}, InstructionPointer: 0x711223344}, want: linux.SECCOMP_RET_TRAP, }, }, @@ -906,7 +904,7 @@ func TestBasic(t *testing.T) { t.Fatalf("bpf.Compile() got error: %v", err) } for _, spec := range test.specs { - got, err := bpf.Exec(p, spec.data.asInput()) + got, err := bpf.Exec(p, dataAsInput(&spec.data)) if err != nil { t.Fatalf("%s: bpf.Exec() got error: %v", spec.desc, err) } @@ -947,8 +945,8 @@ func TestRandom(t *testing.T) { t.Fatalf("bpf.Compile() got error: %v", err) } for i := uint32(0); i < 200; i++ { - data := seccompData{nr: i, arch: LINUX_AUDIT_ARCH} - got, err := bpf.Exec(p, data.asInput()) + data := linux.SeccompData{Nr: int32(i), Arch: LINUX_AUDIT_ARCH} + got, err := bpf.Exec(p, dataAsInput(&data)) if err != nil { t.Errorf("bpf.Exec() got error: %v, for syscall %d", err, i) continue diff --git a/pkg/sentry/fsimpl/signalfd/BUILD b/pkg/sentry/fsimpl/signalfd/BUILD index 067c1657f..adb610213 100644 --- a/pkg/sentry/fsimpl/signalfd/BUILD +++ b/pkg/sentry/fsimpl/signalfd/BUILD @@ -8,7 +8,6 @@ go_library( visibility = ["//pkg/sentry:internal"], deps = [ "//pkg/abi/linux", - "//pkg/binary", "//pkg/context", "//pkg/sentry/kernel", "//pkg/sentry/vfs", diff --git a/pkg/sentry/fsimpl/signalfd/signalfd.go b/pkg/sentry/fsimpl/signalfd/signalfd.go index bf11b425a..10f1452ef 100644 --- a/pkg/sentry/fsimpl/signalfd/signalfd.go +++ b/pkg/sentry/fsimpl/signalfd/signalfd.go @@ -16,7 +16,6 @@ package signalfd import ( "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/sentry/kernel" "gvisor.dev/gvisor/pkg/sentry/vfs" @@ -95,8 +94,7 @@ func (sfd *SignalFileDescription) Read(ctx context.Context, dst usermem.IOSequen } // Copy out the signal info using the specified format. - var buf [128]byte - binary.Marshal(buf[:0], usermem.ByteOrder, &linux.SignalfdSiginfo{ + infoNative := linux.SignalfdSiginfo{ Signo: uint32(info.Signo), Errno: info.Errno, Code: info.Code, @@ -105,9 +103,13 @@ func (sfd *SignalFileDescription) Read(ctx context.Context, dst usermem.IOSequen Status: info.Status(), Overrun: uint32(info.Overrun()), Addr: info.Addr(), - }) - n, err := dst.CopyOut(ctx, buf[:]) - return int64(n), err + } + n, err := infoNative.WriteTo(dst.Writer(ctx)) + if err == usermem.ErrEndOfIOSequence { + // Partial copy-out ok. + err = nil + } + return n, err } // Readiness implements waiter.Waitable.Readiness. diff --git a/pkg/sentry/kernel/BUILD b/pkg/sentry/kernel/BUILD index 083071b5e..5de70aecb 100644 --- a/pkg/sentry/kernel/BUILD +++ b/pkg/sentry/kernel/BUILD @@ -204,7 +204,6 @@ go_library( "//pkg/abi", "//pkg/abi/linux", "//pkg/amutex", - "//pkg/binary", "//pkg/bits", "//pkg/bpf", "//pkg/context", diff --git a/pkg/sentry/kernel/seccomp.go b/pkg/sentry/kernel/seccomp.go index c38c5a40c..387edfa91 100644 --- a/pkg/sentry/kernel/seccomp.go +++ b/pkg/sentry/kernel/seccomp.go @@ -18,7 +18,6 @@ import ( "syscall" "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/bpf" "gvisor.dev/gvisor/pkg/sentry/arch" "gvisor.dev/gvisor/pkg/syserror" @@ -27,25 +26,18 @@ import ( const maxSyscallFilterInstructions = 1 << 15 -// seccompData is equivalent to struct seccomp_data, which contains the data -// passed to seccomp-bpf filters. -type seccompData struct { - // nr is the system call number. - nr int32 - - // arch is an AUDIT_ARCH_* value indicating the system call convention. - arch uint32 - - // instructionPointer is the value of the instruction pointer at the time - // of the system call. - instructionPointer uint64 - - // args contains the first 6 system call arguments. - args [6]uint64 -} - -func (d *seccompData) asBPFInput() bpf.Input { - return bpf.InputBytes{binary.Marshal(nil, usermem.ByteOrder, d), usermem.ByteOrder} +// dataAsBPFInput returns a serialized BPF program, only valid on the current task +// goroutine. +// +// Note: this is called for every syscall, which is a very hot path. +func dataAsBPFInput(t *Task, d *linux.SeccompData) bpf.Input { + buf := t.CopyScratchBuffer(d.SizeBytes()) + d.MarshalUnsafe(buf) + return bpf.InputBytes{ + Data: buf, + // Go-marshal always uses the native byte order. + Order: usermem.ByteOrder, + } } func seccompSiginfo(t *Task, errno, sysno int32, ip usermem.Addr) *arch.SignalInfo { @@ -112,20 +104,20 @@ func (t *Task) checkSeccompSyscall(sysno int32, args arch.SyscallArguments, ip u } func (t *Task) evaluateSyscallFilters(sysno int32, args arch.SyscallArguments, ip usermem.Addr) uint32 { - data := seccompData{ - nr: sysno, - arch: t.tc.st.AuditNumber, - instructionPointer: uint64(ip), + data := linux.SeccompData{ + Nr: sysno, + Arch: t.tc.st.AuditNumber, + InstructionPointer: uint64(ip), } // data.args is []uint64 and args is []arch.SyscallArgument (uintptr), so // we can't do any slicing tricks or even use copy/append here. for i, arg := range args { - if i >= len(data.args) { + if i >= len(data.Args) { break } - data.args[i] = arg.Uint64() + data.Args[i] = arg.Uint64() } - input := data.asBPFInput() + input := dataAsBPFInput(t, &data) ret := uint32(linux.SECCOMP_RET_ALLOW) f := t.syscallFilters.Load() diff --git a/pkg/sentry/kernel/signalfd/BUILD b/pkg/sentry/kernel/signalfd/BUILD index 3eb78e91b..76d472292 100644 --- a/pkg/sentry/kernel/signalfd/BUILD +++ b/pkg/sentry/kernel/signalfd/BUILD @@ -8,7 +8,6 @@ go_library( visibility = ["//pkg/sentry:internal"], deps = [ "//pkg/abi/linux", - "//pkg/binary", "//pkg/context", "//pkg/sentry/fs", "//pkg/sentry/fs/anon", diff --git a/pkg/sentry/kernel/signalfd/signalfd.go b/pkg/sentry/kernel/signalfd/signalfd.go index b07e1c1bd..78f718cfe 100644 --- a/pkg/sentry/kernel/signalfd/signalfd.go +++ b/pkg/sentry/kernel/signalfd/signalfd.go @@ -17,7 +17,6 @@ package signalfd import ( "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/sentry/fs" "gvisor.dev/gvisor/pkg/sentry/fs/anon" @@ -103,8 +102,7 @@ func (s *SignalOperations) Read(ctx context.Context, _ *fs.File, dst usermem.IOS } // Copy out the signal info using the specified format. - var buf [128]byte - binary.Marshal(buf[:0], usermem.ByteOrder, &linux.SignalfdSiginfo{ + infoNative := linux.SignalfdSiginfo{ Signo: uint32(info.Signo), Errno: info.Errno, Code: info.Code, @@ -113,9 +111,13 @@ func (s *SignalOperations) Read(ctx context.Context, _ *fs.File, dst usermem.IOS Status: info.Status(), Overrun: uint32(info.Overrun()), Addr: info.Addr(), - }) - n, err := dst.CopyOut(ctx, buf[:]) - return int64(n), err + } + n, err := infoNative.WriteTo(dst.Writer(ctx)) + if err == usermem.ErrEndOfIOSequence { + // Partial copy-out ok. + err = nil + } + return n, err } // Readiness implements waiter.Waitable.Readiness. diff --git a/pkg/sentry/kernel/vdso.go b/pkg/sentry/kernel/vdso.go index e44a139b3..9bc452e67 100644 --- a/pkg/sentry/kernel/vdso.go +++ b/pkg/sentry/kernel/vdso.go @@ -17,7 +17,6 @@ package kernel import ( "fmt" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/safemem" "gvisor.dev/gvisor/pkg/sentry/memmap" "gvisor.dev/gvisor/pkg/sentry/pgalloc" @@ -28,6 +27,8 @@ import ( // // They are exposed to the VDSO via a parameter page managed by VDSOParamPage, // which also includes a sequence counter. +// +// +marshal type vdsoParams struct { monotonicReady uint64 monotonicBaseCycles int64 @@ -68,6 +69,13 @@ type VDSOParamPage struct { // checked in state_test_util tests, causing this field to change across // save / restore. seq uint64 + + // copyScratchBuffer is a temporary buffer used to marshal the params before + // copying it to the real parameter page. The parameter page is typically + // updated at a moderate frequency of ~O(seconds) throughout the lifetime of + // the sentry, so reusing this buffer is a good tradeoff between memory + // usage and the cost of allocation. + copyScratchBuffer []byte } // NewVDSOParamPage returns a VDSOParamPage. @@ -79,7 +87,11 @@ type VDSOParamPage struct { // * VDSOParamPage must be the only writer to fr. // * mfp.MemoryFile().MapInternal(fr) must return a single safemem.Block. func NewVDSOParamPage(mfp pgalloc.MemoryFileProvider, fr memmap.FileRange) *VDSOParamPage { - return &VDSOParamPage{mfp: mfp, fr: fr} + return &VDSOParamPage{ + mfp: mfp, + fr: fr, + copyScratchBuffer: make([]byte, (*vdsoParams)(nil).SizeBytes()), + } } // access returns a mapping of the param page. @@ -133,7 +145,8 @@ func (v *VDSOParamPage) Write(f func() vdsoParams) error { // Get the new params. p := f() - buf := binary.Marshal(nil, usermem.ByteOrder, p) + buf := v.copyScratchBuffer[:p.SizeBytes()] + p.MarshalUnsafe(buf) // Skip the sequence counter. if _, err := safemem.Copy(paramPage.DropFirst(8), safemem.BlockFromSafeSlice(buf)); err != nil { diff --git a/pkg/sentry/vfs/BUILD b/pkg/sentry/vfs/BUILD index 8093ca55c..c855608db 100644 --- a/pkg/sentry/vfs/BUILD +++ b/pkg/sentry/vfs/BUILD @@ -92,7 +92,6 @@ go_library( visibility = ["//pkg/sentry:internal"], deps = [ "//pkg/abi/linux", - "//pkg/binary", "//pkg/context", "//pkg/fd", "//pkg/fdnotifier", |