mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Enable automated marshalling for signals and the arch package.
PiperOrigin-RevId: 308472331
This commit is contained in:
committed by
gVisor bot
parent
17ac90a203
commit
3c67754663
@@ -44,6 +44,8 @@ go_library(
|
||||
"poll.go",
|
||||
"prctl.go",
|
||||
"ptrace.go",
|
||||
"ptrace_amd64.go",
|
||||
"ptrace_arm64.go",
|
||||
"rseq.go",
|
||||
"rusage.go",
|
||||
"sched.go",
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build amd64
|
||||
|
||||
package linux
|
||||
|
||||
// PtraceRegs is the set of CPU registers exposed by ptrace. Source:
|
||||
// syscall.PtraceRegs.
|
||||
//
|
||||
// +marshal
|
||||
// +stateify savable
|
||||
type PtraceRegs struct {
|
||||
R15 uint64
|
||||
R14 uint64
|
||||
R13 uint64
|
||||
R12 uint64
|
||||
Rbp uint64
|
||||
Rbx uint64
|
||||
R11 uint64
|
||||
R10 uint64
|
||||
R9 uint64
|
||||
R8 uint64
|
||||
Rax uint64
|
||||
Rcx uint64
|
||||
Rdx uint64
|
||||
Rsi uint64
|
||||
Rdi uint64
|
||||
Orig_rax uint64
|
||||
Rip uint64
|
||||
Cs uint64
|
||||
Eflags uint64
|
||||
Rsp uint64
|
||||
Ss uint64
|
||||
Fs_base uint64
|
||||
Gs_base uint64
|
||||
Ds uint64
|
||||
Es uint64
|
||||
Fs uint64
|
||||
Gs uint64
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 The gVisor Authors.
|
||||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -14,25 +14,16 @@
|
||||
|
||||
// +build arm64
|
||||
|
||||
package arch
|
||||
package linux
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type syscallPtraceRegs struct {
|
||||
// PtraceRegs is the set of CPU registers exposed by ptrace. Source:
|
||||
// syscall.PtraceRegs.
|
||||
//
|
||||
// +marshal
|
||||
// +stateify savable
|
||||
type PtraceRegs struct {
|
||||
Regs [31]uint64
|
||||
Sp uint64
|
||||
Pc uint64
|
||||
Pstate uint64
|
||||
}
|
||||
|
||||
// saveRegs is invoked by stateify.
|
||||
func (s *State) saveRegs() syscallPtraceRegs {
|
||||
return syscallPtraceRegs(s.Regs)
|
||||
}
|
||||
|
||||
// loadRegs is invoked by stateify.
|
||||
func (s *State) loadRegs(r syscallPtraceRegs) {
|
||||
s.Regs = syscall.PtraceRegs(r)
|
||||
}
|
||||
@@ -11,7 +11,6 @@ go_library(
|
||||
"arch_amd64.go",
|
||||
"arch_amd64.s",
|
||||
"arch_arm64.go",
|
||||
"arch_state_aarch64.go",
|
||||
"arch_state_x86.go",
|
||||
"arch_x86.go",
|
||||
"arch_x86_impl.go",
|
||||
@@ -26,11 +25,11 @@ go_library(
|
||||
"syscalls_amd64.go",
|
||||
"syscalls_arm64.go",
|
||||
],
|
||||
marshal = True,
|
||||
visibility = ["//:sandbox"],
|
||||
deps = [
|
||||
":registers_go_proto",
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/binary",
|
||||
"//pkg/context",
|
||||
"//pkg/cpuid",
|
||||
"//pkg/log",
|
||||
@@ -38,6 +37,7 @@ go_library(
|
||||
"//pkg/sync",
|
||||
"//pkg/syserror",
|
||||
"//pkg/usermem",
|
||||
"//tools/go_marshal/marshal",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -17,18 +17,20 @@
|
||||
package arch
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
rpb "gvisor.dev/gvisor/pkg/sentry/arch/registers_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// Registers represents the CPU registers for this architecture.
|
||||
type Registers = linux.PtraceRegs
|
||||
|
||||
const (
|
||||
// SyscallWidth is the width of insturctions.
|
||||
SyscallWidth = 4
|
||||
@@ -90,7 +92,7 @@ func NewFloatingPointData() *FloatingPointData {
|
||||
// file ensures it's only built on aarch64).
|
||||
type State struct {
|
||||
// The system registers.
|
||||
Regs syscall.PtraceRegs `state:".(syscallPtraceRegs)"`
|
||||
Regs Registers
|
||||
|
||||
// Our floating point state.
|
||||
aarch64FPState `state:"wait"`
|
||||
@@ -226,25 +228,27 @@ func (s *State) RegisterMap() (map[string]uintptr, error) {
|
||||
|
||||
// PtraceGetRegs implements Context.PtraceGetRegs.
|
||||
func (s *State) PtraceGetRegs(dst io.Writer) (int, error) {
|
||||
return dst.Write(binary.Marshal(nil, usermem.ByteOrder, s.ptraceGetRegs()))
|
||||
regs := s.ptraceGetRegs()
|
||||
n, err := regs.WriteTo(dst)
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
func (s *State) ptraceGetRegs() syscall.PtraceRegs {
|
||||
func (s *State) ptraceGetRegs() Registers {
|
||||
return s.Regs
|
||||
}
|
||||
|
||||
var ptraceRegsSize = int(binary.Size(syscall.PtraceRegs{}))
|
||||
var registersSize = (*Registers)(nil).SizeBytes()
|
||||
|
||||
// PtraceSetRegs implements Context.PtraceSetRegs.
|
||||
func (s *State) PtraceSetRegs(src io.Reader) (int, error) {
|
||||
var regs syscall.PtraceRegs
|
||||
buf := make([]byte, ptraceRegsSize)
|
||||
var regs Registers
|
||||
buf := make([]byte, registersSize)
|
||||
if _, err := io.ReadFull(src, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
binary.Unmarshal(buf, usermem.ByteOrder, ®s)
|
||||
regs.UnmarshalUnsafe(buf)
|
||||
s.Regs = regs
|
||||
return ptraceRegsSize, nil
|
||||
return registersSize, nil
|
||||
}
|
||||
|
||||
// PtraceGetFPRegs implements Context.PtraceGetFPRegs.
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"math/rand"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
"gvisor.dev/gvisor/pkg/sentry/limits"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
@@ -301,8 +300,10 @@ func (c *context64) PtracePeekUser(addr uintptr) (interface{}, error) {
|
||||
// PTRACE_PEEKUSER and PTRACE_POKEUSER are only effective on regs and
|
||||
// u_debugreg, returning 0 or silently no-oping for other fields
|
||||
// respectively.
|
||||
if addr < uintptr(ptraceRegsSize) {
|
||||
buf := binary.Marshal(nil, usermem.ByteOrder, c.ptraceGetRegs())
|
||||
if addr < uintptr(registersSize) {
|
||||
regs := c.ptraceGetRegs()
|
||||
buf := make([]byte, regs.SizeBytes())
|
||||
regs.MarshalUnsafe(buf)
|
||||
return c.Native(uintptr(usermem.ByteOrder.Uint64(buf[addr:]))), nil
|
||||
}
|
||||
// Note: x86 debug registers are missing.
|
||||
@@ -314,8 +315,10 @@ func (c *context64) PtracePokeUser(addr, data uintptr) error {
|
||||
if addr&7 != 0 || addr >= userStructSize {
|
||||
return syscall.EIO
|
||||
}
|
||||
if addr < uintptr(ptraceRegsSize) {
|
||||
buf := binary.Marshal(nil, usermem.ByteOrder, c.ptraceGetRegs())
|
||||
if addr < uintptr(registersSize) {
|
||||
regs := c.ptraceGetRegs()
|
||||
buf := make([]byte, regs.SizeBytes())
|
||||
regs.MarshalUnsafe(buf)
|
||||
usermem.ByteOrder.PutUint64(buf[addr:], uint64(data))
|
||||
_, err := c.PtraceSetRegs(bytes.NewBuffer(buf))
|
||||
return err
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build arm64
|
||||
|
||||
package arch
|
||||
|
||||
import (
|
||||
|
||||
@@ -18,7 +18,6 @@ package arch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
@@ -90,44 +89,3 @@ func (s *State) afterLoadFPState() {
|
||||
// Copy to the new, aligned location.
|
||||
copy(s.x86FPState, old)
|
||||
}
|
||||
|
||||
// +stateify savable
|
||||
type syscallPtraceRegs struct {
|
||||
R15 uint64
|
||||
R14 uint64
|
||||
R13 uint64
|
||||
R12 uint64
|
||||
Rbp uint64
|
||||
Rbx uint64
|
||||
R11 uint64
|
||||
R10 uint64
|
||||
R9 uint64
|
||||
R8 uint64
|
||||
Rax uint64
|
||||
Rcx uint64
|
||||
Rdx uint64
|
||||
Rsi uint64
|
||||
Rdi uint64
|
||||
Orig_rax uint64
|
||||
Rip uint64
|
||||
Cs uint64
|
||||
Eflags uint64
|
||||
Rsp uint64
|
||||
Ss uint64
|
||||
Fs_base uint64
|
||||
Gs_base uint64
|
||||
Ds uint64
|
||||
Es uint64
|
||||
Fs uint64
|
||||
Gs uint64
|
||||
}
|
||||
|
||||
// saveRegs is invoked by stateify.
|
||||
func (s *State) saveRegs() syscallPtraceRegs {
|
||||
return syscallPtraceRegs(s.Regs)
|
||||
}
|
||||
|
||||
// loadRegs is invoked by stateify.
|
||||
func (s *State) loadRegs(r syscallPtraceRegs) {
|
||||
s.Regs = syscall.PtraceRegs(r)
|
||||
}
|
||||
|
||||
+15
-10
@@ -21,7 +21,7 @@ import (
|
||||
"io"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
rpb "gvisor.dev/gvisor/pkg/sentry/arch/registers_go_proto"
|
||||
@@ -30,6 +30,9 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// Registers represents the CPU registers for this architecture.
|
||||
type Registers = linux.PtraceRegs
|
||||
|
||||
// System-related constants for x86.
|
||||
const (
|
||||
// SyscallWidth is the width of syscall, sysenter, and int 80 insturctions.
|
||||
@@ -267,10 +270,12 @@ func (s *State) RegisterMap() (map[string]uintptr, error) {
|
||||
|
||||
// PtraceGetRegs implements Context.PtraceGetRegs.
|
||||
func (s *State) PtraceGetRegs(dst io.Writer) (int, error) {
|
||||
return dst.Write(binary.Marshal(nil, usermem.ByteOrder, s.ptraceGetRegs()))
|
||||
regs := s.ptraceGetRegs()
|
||||
n, err := regs.WriteTo(dst)
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
func (s *State) ptraceGetRegs() syscall.PtraceRegs {
|
||||
func (s *State) ptraceGetRegs() Registers {
|
||||
regs := s.Regs
|
||||
// These may not be initialized.
|
||||
if regs.Cs == 0 || regs.Ss == 0 || regs.Eflags == 0 {
|
||||
@@ -306,16 +311,16 @@ func (s *State) ptraceGetRegs() syscall.PtraceRegs {
|
||||
return regs
|
||||
}
|
||||
|
||||
var ptraceRegsSize = int(binary.Size(syscall.PtraceRegs{}))
|
||||
var registersSize = (*Registers)(nil).SizeBytes()
|
||||
|
||||
// PtraceSetRegs implements Context.PtraceSetRegs.
|
||||
func (s *State) PtraceSetRegs(src io.Reader) (int, error) {
|
||||
var regs syscall.PtraceRegs
|
||||
buf := make([]byte, ptraceRegsSize)
|
||||
var regs Registers
|
||||
buf := make([]byte, registersSize)
|
||||
if _, err := io.ReadFull(src, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
binary.Unmarshal(buf, usermem.ByteOrder, ®s)
|
||||
regs.UnmarshalUnsafe(buf)
|
||||
// Truncate segment registers to 16 bits.
|
||||
regs.Cs = uint64(uint16(regs.Cs))
|
||||
regs.Ds = uint64(uint16(regs.Ds))
|
||||
@@ -369,7 +374,7 @@ func (s *State) PtraceSetRegs(src io.Reader) (int, error) {
|
||||
}
|
||||
regs.Eflags = (s.Regs.Eflags &^ eflagsPtraceMutable) | (regs.Eflags & eflagsPtraceMutable)
|
||||
s.Regs = regs
|
||||
return ptraceRegsSize, nil
|
||||
return registersSize, nil
|
||||
}
|
||||
|
||||
// isUserSegmentSelector returns true if the given segment selector specifies a
|
||||
@@ -538,7 +543,7 @@ const (
|
||||
func (s *State) PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int) (int, error) {
|
||||
switch regset {
|
||||
case _NT_PRSTATUS:
|
||||
if maxlen < ptraceRegsSize {
|
||||
if maxlen < registersSize {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
return s.PtraceGetRegs(dst)
|
||||
@@ -558,7 +563,7 @@ func (s *State) PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int) (int,
|
||||
func (s *State) PtraceSetRegSet(regset uintptr, src io.Reader, maxlen int) (int, error) {
|
||||
switch regset {
|
||||
case _NT_PRSTATUS:
|
||||
if maxlen < ptraceRegsSize {
|
||||
if maxlen < registersSize {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
return s.PtraceSetRegs(src)
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
package arch
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
)
|
||||
|
||||
@@ -28,7 +26,7 @@ import (
|
||||
// +stateify savable
|
||||
type State struct {
|
||||
// The system registers.
|
||||
Regs syscall.PtraceRegs `state:".(syscallPtraceRegs)"`
|
||||
Regs Registers
|
||||
|
||||
// Our floating point state.
|
||||
x86FPState `state:"wait"`
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
// SignalAct represents the action that should be taken when a signal is
|
||||
// delivered, and is equivalent to struct sigaction.
|
||||
//
|
||||
// +marshal
|
||||
// +stateify savable
|
||||
type SignalAct struct {
|
||||
Handler uint64
|
||||
@@ -43,6 +44,7 @@ func (s *SignalAct) DeserializeTo(other *SignalAct) {
|
||||
// SignalStack represents information about a user stack, and is equivalent to
|
||||
// stack_t.
|
||||
//
|
||||
// +marshal
|
||||
// +stateify savable
|
||||
type SignalStack struct {
|
||||
Addr uint64
|
||||
@@ -64,6 +66,7 @@ func (s *SignalStack) DeserializeTo(other *SignalStack) {
|
||||
// SignalInfo represents information about a signal being delivered, and is
|
||||
// equivalent to struct siginfo in linux kernel(linux/include/uapi/asm-generic/siginfo.h).
|
||||
//
|
||||
// +marshal
|
||||
// +stateify savable
|
||||
type SignalInfo struct {
|
||||
Signo int32 // Signal number
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package arch
|
||||
|
||||
import "gvisor.dev/gvisor/tools/go_marshal/marshal"
|
||||
|
||||
// Special values for SignalAct.Handler.
|
||||
const (
|
||||
// SignalActDefault is SIG_DFL and specifies that the default behavior for
|
||||
@@ -71,6 +73,8 @@ func (s SignalAct) HasRestorer() bool {
|
||||
// NativeSignalAct is a type that is equivalent to struct sigaction in the
|
||||
// guest architecture.
|
||||
type NativeSignalAct interface {
|
||||
marshal.Marshallable
|
||||
|
||||
// SerializeFrom copies the data in the host SignalAct s into this object.
|
||||
SerializeFrom(s *SignalAct)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package arch
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/tools/go_marshal/marshal"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -55,6 +56,8 @@ func (s *SignalStack) Contains(sp usermem.Addr) bool {
|
||||
// NativeSignalStack is a type that is equivalent to stack_t in the guest
|
||||
// architecture.
|
||||
type NativeSignalStack interface {
|
||||
marshal.Marshallable
|
||||
|
||||
// SerializeFrom copies the data in the host SignalStack s into this
|
||||
// object.
|
||||
SerializeFrom(s *SignalStack)
|
||||
|
||||
@@ -716,7 +716,7 @@ func (tg *ThreadGroup) SetSignalAct(sig linux.Signal, actptr *arch.SignalAct) (a
|
||||
func (t *Task) CopyOutSignalAct(addr usermem.Addr, s *arch.SignalAct) error {
|
||||
n := t.Arch().NewSignalAct()
|
||||
n.SerializeFrom(s)
|
||||
_, err := t.CopyOut(addr, n)
|
||||
_, err := n.CopyOut(t, addr)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -725,7 +725,7 @@ func (t *Task) CopyOutSignalAct(addr usermem.Addr, s *arch.SignalAct) error {
|
||||
func (t *Task) CopyInSignalAct(addr usermem.Addr) (arch.SignalAct, error) {
|
||||
n := t.Arch().NewSignalAct()
|
||||
var s arch.SignalAct
|
||||
if _, err := t.CopyIn(addr, n); err != nil {
|
||||
if _, err := n.CopyIn(t, addr); err != nil {
|
||||
return s, err
|
||||
}
|
||||
n.DeserializeTo(&s)
|
||||
@@ -737,7 +737,7 @@ func (t *Task) CopyInSignalAct(addr usermem.Addr) (arch.SignalAct, error) {
|
||||
func (t *Task) CopyOutSignalStack(addr usermem.Addr, s *arch.SignalStack) error {
|
||||
n := t.Arch().NewSignalStack()
|
||||
n.SerializeFrom(s)
|
||||
_, err := t.CopyOut(addr, n)
|
||||
_, err := n.CopyOut(t, addr)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -746,7 +746,7 @@ func (t *Task) CopyOutSignalStack(addr usermem.Addr, s *arch.SignalStack) error
|
||||
func (t *Task) CopyInSignalStack(addr usermem.Addr) (arch.SignalStack, error) {
|
||||
n := t.Arch().NewSignalStack()
|
||||
var s arch.SignalStack
|
||||
if _, err := t.CopyIn(addr, n); err != nil {
|
||||
if _, err := n.CopyIn(t, addr); err != nil {
|
||||
return s, err
|
||||
}
|
||||
n.DeserializeTo(&s)
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
package kvm
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/platform/ring0"
|
||||
)
|
||||
|
||||
@@ -37,7 +36,7 @@ type userFpsimdState struct {
|
||||
}
|
||||
|
||||
type userRegs struct {
|
||||
Regs syscall.PtraceRegs
|
||||
Regs arch.Registers
|
||||
sp_el1 uint64
|
||||
elr_el1 uint64
|
||||
spsr [KVM_NR_SPSR]uint64
|
||||
|
||||
@@ -117,10 +117,10 @@ func TestKernelFloatingPoint(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func applicationTest(t testHarness, useHostMappings bool, target func(), fn func(*vCPU, *syscall.PtraceRegs, *pagetables.PageTables) bool) {
|
||||
func applicationTest(t testHarness, useHostMappings bool, target func(), fn func(*vCPU, *arch.Registers, *pagetables.PageTables) bool) {
|
||||
// Initialize registers & page tables.
|
||||
var (
|
||||
regs syscall.PtraceRegs
|
||||
regs arch.Registers
|
||||
pt *pagetables.PageTables
|
||||
)
|
||||
testutil.SetTestTarget(®s, target)
|
||||
@@ -154,7 +154,7 @@ func applicationTest(t testHarness, useHostMappings bool, target func(), fn func
|
||||
}
|
||||
|
||||
func TestApplicationSyscall(t *testing.T) {
|
||||
applicationTest(t, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.SyscallLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
Registers: regs,
|
||||
@@ -168,7 +168,7 @@ func TestApplicationSyscall(t *testing.T) {
|
||||
}
|
||||
return false
|
||||
})
|
||||
applicationTest(t, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.SyscallLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
Registers: regs,
|
||||
@@ -184,7 +184,7 @@ func TestApplicationSyscall(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestApplicationFault(t *testing.T) {
|
||||
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
testutil.SetTouchTarget(regs, nil) // Cause fault.
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
@@ -199,7 +199,7 @@ func TestApplicationFault(t *testing.T) {
|
||||
}
|
||||
return false
|
||||
})
|
||||
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
testutil.SetTouchTarget(regs, nil) // Cause fault.
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
@@ -216,7 +216,7 @@ func TestApplicationFault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRegistersSyscall(t *testing.T) {
|
||||
applicationTest(t, true, testutil.TwiddleRegsSyscall, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.TwiddleRegsSyscall, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
testutil.SetTestRegs(regs) // Fill values for all registers.
|
||||
for {
|
||||
var si arch.SignalInfo
|
||||
@@ -239,7 +239,7 @@ func TestRegistersSyscall(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRegistersFault(t *testing.T) {
|
||||
applicationTest(t, true, testutil.TwiddleRegsFault, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.TwiddleRegsFault, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
testutil.SetTestRegs(regs) // Fill values for all registers.
|
||||
for {
|
||||
var si arch.SignalInfo
|
||||
@@ -263,7 +263,7 @@ func TestRegistersFault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSegments(t *testing.T) {
|
||||
applicationTest(t, true, testutil.TwiddleSegments, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.TwiddleSegments, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
testutil.SetTestSegments(regs)
|
||||
for {
|
||||
var si arch.SignalInfo
|
||||
@@ -287,7 +287,7 @@ func TestSegments(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBounce(t *testing.T) {
|
||||
applicationTest(t, true, testutil.SpinLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.SpinLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond)
|
||||
c.BounceToKernel()
|
||||
@@ -302,7 +302,7 @@ func TestBounce(t *testing.T) {
|
||||
}
|
||||
return false
|
||||
})
|
||||
applicationTest(t, true, testutil.SpinLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.SpinLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond)
|
||||
c.BounceToKernel()
|
||||
@@ -321,7 +321,7 @@ func TestBounce(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBounceStress(t *testing.T) {
|
||||
applicationTest(t, true, testutil.SpinLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.SpinLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
randomSleep := func() {
|
||||
// O(hundreds of microseconds) is appropriate to ensure
|
||||
// different overlaps and different schedules.
|
||||
@@ -357,7 +357,7 @@ func TestBounceStress(t *testing.T) {
|
||||
|
||||
func TestInvalidate(t *testing.T) {
|
||||
var data uintptr // Used below.
|
||||
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, true, testutil.Touch, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
testutil.SetTouchTarget(regs, &data) // Read legitimate value.
|
||||
for {
|
||||
var si arch.SignalInfo
|
||||
@@ -398,7 +398,7 @@ func IsFault(err error, si *arch.SignalInfo) bool {
|
||||
}
|
||||
|
||||
func TestEmptyAddressSpace(t *testing.T) {
|
||||
applicationTest(t, false, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, false, testutil.SyscallLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
Registers: regs,
|
||||
@@ -412,7 +412,7 @@ func TestEmptyAddressSpace(t *testing.T) {
|
||||
}
|
||||
return false
|
||||
})
|
||||
applicationTest(t, false, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(t, false, testutil.SyscallLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
Registers: regs,
|
||||
@@ -471,7 +471,7 @@ func BenchmarkApplicationSyscall(b *testing.B) {
|
||||
i int // Iteration includes machine.Get() / machine.Put().
|
||||
a int // Count for ErrContextInterrupt.
|
||||
)
|
||||
applicationTest(b, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(b, true, testutil.SyscallLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
Registers: regs,
|
||||
@@ -493,7 +493,7 @@ func BenchmarkApplicationSyscall(b *testing.B) {
|
||||
|
||||
func BenchmarkKernelSyscall(b *testing.B) {
|
||||
// Note that the target passed here is irrelevant, we never execute SwitchToUser.
|
||||
applicationTest(b, true, testutil.Getpid, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(b, true, testutil.Getpid, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
// iteration does not include machine.Get() / machine.Put().
|
||||
for i := 0; i < b.N; i++ {
|
||||
testutil.Getpid()
|
||||
@@ -508,7 +508,7 @@ func BenchmarkWorldSwitchToUserRoundtrip(b *testing.B) {
|
||||
i int
|
||||
a int
|
||||
)
|
||||
applicationTest(b, true, testutil.SyscallLoop, func(c *vCPU, regs *syscall.PtraceRegs, pt *pagetables.PageTables) bool {
|
||||
applicationTest(b, true, testutil.SyscallLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool {
|
||||
var si arch.SignalInfo
|
||||
if _, err := c.SwitchToUser(ring0.SwitchOpts{
|
||||
Registers: regs,
|
||||
|
||||
@@ -13,4 +13,5 @@ go_library(
|
||||
"testutil_arm64.s",
|
||||
],
|
||||
visibility = ["//pkg/sentry/platform/kvm:__pkg__"],
|
||||
deps = ["//pkg/sentry/arch"],
|
||||
)
|
||||
|
||||
@@ -18,19 +18,20 @@ package testutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
)
|
||||
|
||||
// TwiddleSegments reads segments into known registers.
|
||||
func TwiddleSegments()
|
||||
|
||||
// SetTestTarget sets the rip appropriately.
|
||||
func SetTestTarget(regs *syscall.PtraceRegs, fn func()) {
|
||||
func SetTestTarget(regs *arch.Registers, fn func()) {
|
||||
regs.Rip = uint64(reflect.ValueOf(fn).Pointer())
|
||||
}
|
||||
|
||||
// SetTouchTarget sets rax appropriately.
|
||||
func SetTouchTarget(regs *syscall.PtraceRegs, target *uintptr) {
|
||||
func SetTouchTarget(regs *arch.Registers, target *uintptr) {
|
||||
if target != nil {
|
||||
regs.Rax = uint64(reflect.ValueOf(target).Pointer())
|
||||
} else {
|
||||
@@ -39,12 +40,12 @@ func SetTouchTarget(regs *syscall.PtraceRegs, target *uintptr) {
|
||||
}
|
||||
|
||||
// RewindSyscall rewinds a syscall RIP.
|
||||
func RewindSyscall(regs *syscall.PtraceRegs) {
|
||||
func RewindSyscall(regs *arch.Registers) {
|
||||
regs.Rip -= 2
|
||||
}
|
||||
|
||||
// SetTestRegs initializes registers to known values.
|
||||
func SetTestRegs(regs *syscall.PtraceRegs) {
|
||||
func SetTestRegs(regs *arch.Registers) {
|
||||
regs.R15 = 0x15
|
||||
regs.R14 = 0x14
|
||||
regs.R13 = 0x13
|
||||
@@ -64,7 +65,7 @@ func SetTestRegs(regs *syscall.PtraceRegs) {
|
||||
}
|
||||
|
||||
// CheckTestRegs checks that registers were twiddled per TwiddleRegs.
|
||||
func CheckTestRegs(regs *syscall.PtraceRegs, full bool) (err error) {
|
||||
func CheckTestRegs(regs *arch.Registers, full bool) (err error) {
|
||||
if need := ^uint64(0x15); regs.R15 != need {
|
||||
err = addRegisterMismatch(err, "R15", regs.R15, need)
|
||||
}
|
||||
@@ -121,13 +122,13 @@ var fsData uint64 = 0x55
|
||||
var gsData uint64 = 0x85
|
||||
|
||||
// SetTestSegments initializes segments to known values.
|
||||
func SetTestSegments(regs *syscall.PtraceRegs) {
|
||||
func SetTestSegments(regs *arch.Registers) {
|
||||
regs.Fs_base = uint64(reflect.ValueOf(&fsData).Pointer())
|
||||
regs.Gs_base = uint64(reflect.ValueOf(&gsData).Pointer())
|
||||
}
|
||||
|
||||
// CheckTestSegments checks that registers were twiddled per TwiddleSegments.
|
||||
func CheckTestSegments(regs *syscall.PtraceRegs) (err error) {
|
||||
func CheckTestSegments(regs *arch.Registers) (err error) {
|
||||
if regs.Rax != fsData {
|
||||
err = addRegisterMismatch(err, "Rax", regs.Rax, fsData)
|
||||
}
|
||||
|
||||
@@ -19,16 +19,17 @@ package testutil
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
)
|
||||
|
||||
// SetTestTarget sets the rip appropriately.
|
||||
func SetTestTarget(regs *syscall.PtraceRegs, fn func()) {
|
||||
func SetTestTarget(regs *arch.Registers, fn func()) {
|
||||
regs.Pc = uint64(reflect.ValueOf(fn).Pointer())
|
||||
}
|
||||
|
||||
// SetTouchTarget sets rax appropriately.
|
||||
func SetTouchTarget(regs *syscall.PtraceRegs, target *uintptr) {
|
||||
func SetTouchTarget(regs *arch.Registers, target *uintptr) {
|
||||
if target != nil {
|
||||
regs.Regs[8] = uint64(reflect.ValueOf(target).Pointer())
|
||||
} else {
|
||||
@@ -37,19 +38,19 @@ func SetTouchTarget(regs *syscall.PtraceRegs, target *uintptr) {
|
||||
}
|
||||
|
||||
// RewindSyscall rewinds a syscall RIP.
|
||||
func RewindSyscall(regs *syscall.PtraceRegs) {
|
||||
func RewindSyscall(regs *arch.Registers) {
|
||||
regs.Pc -= 4
|
||||
}
|
||||
|
||||
// SetTestRegs initializes registers to known values.
|
||||
func SetTestRegs(regs *syscall.PtraceRegs) {
|
||||
func SetTestRegs(regs *arch.Registers) {
|
||||
for i := 0; i <= 30; i++ {
|
||||
regs.Regs[i] = uint64(i) + 1
|
||||
}
|
||||
}
|
||||
|
||||
// CheckTestRegs checks that registers were twiddled per TwiddleRegs.
|
||||
func CheckTestRegs(regs *syscall.PtraceRegs, full bool) (err error) {
|
||||
func CheckTestRegs(regs *arch.Registers, full bool) (err error) {
|
||||
for i := 0; i <= 30; i++ {
|
||||
if need := ^uint64(i + 1); regs.Regs[i] != need {
|
||||
err = addRegisterMismatch(err, fmt.Sprintf("R%d", i), regs.Regs[i], need)
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
package ptrace
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
)
|
||||
|
||||
// fpRegSet returns the GETREGSET/SETREGSET register set type to be used.
|
||||
@@ -28,12 +27,12 @@ func fpRegSet(useXsave bool) uintptr {
|
||||
return linux.NT_PRFPREG
|
||||
}
|
||||
|
||||
func stackPointer(r *syscall.PtraceRegs) uintptr {
|
||||
func stackPointer(r *arch.Registers) uintptr {
|
||||
return uintptr(r.Rsp)
|
||||
}
|
||||
|
||||
// x86 use the fs_base register to store the TLS pointer which can be
|
||||
// get/set in "func (t *thread) get/setRegs(regs *syscall.PtraceRegs)".
|
||||
// get/set in "func (t *thread) get/setRegs(regs *arch.Registers)".
|
||||
// So both of the get/setTLS() operations are noop here.
|
||||
|
||||
// getTLS gets the thread local storage register.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user