2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-04-27 17:37:02 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
// Package arch provides abstractions around architecture-dependent details,
|
|
|
|
// such as syscall calling conventions, native types, etc.
|
|
|
|
package arch
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/abi/linux"
|
|
|
|
"gvisor.dev/gvisor/pkg/cpuid"
|
|
|
|
"gvisor.dev/gvisor/pkg/log"
|
|
|
|
"gvisor.dev/gvisor/pkg/sentry/limits"
|
|
|
|
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Arch describes an architecture.
|
|
|
|
type Arch int
|
|
|
|
|
|
|
|
const (
|
|
|
|
// AMD64 is the x86-64 architecture.
|
|
|
|
AMD64 Arch = iota
|
2019-07-19 06:30:52 +00:00
|
|
|
// ARM64 is the aarch64 architecture.
|
|
|
|
ARM64
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// String implements fmt.Stringer.
|
|
|
|
func (a Arch) String() string {
|
|
|
|
switch a {
|
|
|
|
case AMD64:
|
|
|
|
return "amd64"
|
2019-07-19 06:30:52 +00:00
|
|
|
case ARM64:
|
|
|
|
return "arm64"
|
2018-04-27 17:37:02 +00:00
|
|
|
default:
|
|
|
|
return fmt.Sprintf("Arch(%d)", a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FloatingPointData is a generic type, and will always be passed as a pointer.
|
|
|
|
// We rely on the individual arch implementations to meet all the necessary
|
|
|
|
// requirements. For example, on x86 the region must be 16-byte aligned and 512
|
|
|
|
// bytes in size.
|
|
|
|
type FloatingPointData byte
|
|
|
|
|
|
|
|
// Context provides architecture-dependent information for a specific thread.
|
|
|
|
//
|
2019-04-29 21:03:04 +00:00
|
|
|
// NOTE(b/34169503): Currently we use uintptr here to refer to a generic native
|
2018-04-27 17:37:02 +00:00
|
|
|
// register value. While this will work for the foreseeable future, it isn't
|
|
|
|
// strictly correct. We may want to create some abstraction that makes this
|
|
|
|
// more clear or enables us to store values of arbitrary widths. This is
|
|
|
|
// particularly true for RegisterMap().
|
|
|
|
type Context interface {
|
|
|
|
// Arch returns the architecture for this Context.
|
|
|
|
Arch() Arch
|
|
|
|
|
|
|
|
// Native converts a generic type to a native value.
|
|
|
|
//
|
|
|
|
// Because the architecture is not specified here, we may be dealing
|
|
|
|
// with return values of varying sizes (for example ARCH_GETFS). This
|
|
|
|
// is a simple utility function to convert to the native size in these
|
|
|
|
// cases, and then we can CopyOut.
|
|
|
|
Native(val uintptr) interface{}
|
|
|
|
|
|
|
|
// Value converts a native type back to a generic value.
|
|
|
|
// Once a value has been converted to native via the above call -- it
|
|
|
|
// can be converted back here.
|
|
|
|
Value(val interface{}) uintptr
|
|
|
|
|
|
|
|
// Width returns the number of bytes for a native value.
|
|
|
|
Width() uint
|
|
|
|
|
|
|
|
// Fork creates a clone of the context.
|
|
|
|
Fork() Context
|
|
|
|
|
|
|
|
// SyscallNo returns the syscall number.
|
|
|
|
SyscallNo() uintptr
|
|
|
|
|
|
|
|
// SyscallArgs returns the syscall arguments in an array.
|
|
|
|
SyscallArgs() SyscallArguments
|
|
|
|
|
|
|
|
// Return returns the return value for a system call.
|
|
|
|
Return() uintptr
|
|
|
|
|
|
|
|
// SetReturn sets the return value for a system call.
|
|
|
|
SetReturn(value uintptr)
|
|
|
|
|
|
|
|
// RestartSyscall reverses over the current syscall instruction, such that
|
|
|
|
// when the application resumes execution the syscall will be re-attempted.
|
|
|
|
RestartSyscall()
|
|
|
|
|
|
|
|
// RestartSyscallWithRestartBlock reverses over the current syscall
|
|
|
|
// instraction and overwrites the current syscall number with that of
|
|
|
|
// restart_syscall(2). This causes the application to restart the current
|
|
|
|
// syscall with a custom function when execution resumes.
|
|
|
|
RestartSyscallWithRestartBlock()
|
|
|
|
|
|
|
|
// IP returns the current instruction pointer.
|
|
|
|
IP() uintptr
|
|
|
|
|
|
|
|
// SetIP sets the current instruction pointer.
|
|
|
|
SetIP(value uintptr)
|
|
|
|
|
|
|
|
// Stack returns the current stack pointer.
|
|
|
|
Stack() uintptr
|
|
|
|
|
|
|
|
// SetStack sets the current stack pointer.
|
|
|
|
SetStack(value uintptr)
|
|
|
|
|
2018-12-10 20:36:27 +00:00
|
|
|
// TLS returns the current TLS pointer.
|
|
|
|
TLS() uintptr
|
|
|
|
|
|
|
|
// SetTLS sets the current TLS pointer. Returns false if value is invalid.
|
|
|
|
SetTLS(value uintptr) bool
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// SetRSEQInterruptedIP sets the register that contains the old IP when a
|
|
|
|
// restartable sequence is interrupted.
|
|
|
|
SetRSEQInterruptedIP(value uintptr)
|
|
|
|
|
|
|
|
// StateData returns a pointer to underlying architecture state.
|
|
|
|
StateData() *State
|
|
|
|
|
|
|
|
// RegisterMap returns a map of all registers.
|
|
|
|
RegisterMap() (map[string]uintptr, error)
|
|
|
|
|
|
|
|
// NewSignalAct returns a new object that is equivalent to struct sigaction
|
|
|
|
// in the guest architecture.
|
|
|
|
NewSignalAct() NativeSignalAct
|
|
|
|
|
|
|
|
// NewSignalStack returns a new object that is equivalent to stack_t in the
|
|
|
|
// guest architecture.
|
|
|
|
NewSignalStack() NativeSignalStack
|
|
|
|
|
|
|
|
// SignalSetup modifies the context in preparation for handling the
|
|
|
|
// given signal.
|
|
|
|
//
|
|
|
|
// st is the stack where the signal handler frame should be
|
|
|
|
// constructed.
|
|
|
|
//
|
|
|
|
// act is the SignalAct that specifies how this signal is being
|
|
|
|
// handled.
|
|
|
|
//
|
|
|
|
// info is the SignalInfo of the signal being delivered.
|
|
|
|
//
|
|
|
|
// alt is the alternate signal stack (even if the alternate signal
|
|
|
|
// stack is not going to be used).
|
|
|
|
//
|
|
|
|
// sigset is the signal mask before entering the signal handler.
|
|
|
|
SignalSetup(st *Stack, act *SignalAct, info *SignalInfo, alt *SignalStack, sigset linux.SignalSet) error
|
|
|
|
|
|
|
|
// SignalRestore restores context after returning from a signal
|
|
|
|
// handler.
|
|
|
|
//
|
|
|
|
// st is the current thread stack.
|
|
|
|
//
|
|
|
|
// rt is true if SignalRestore is being entered from rt_sigreturn and
|
|
|
|
// false if SignalRestore is being entered from sigreturn.
|
|
|
|
// SignalRestore returns the thread's new signal mask.
|
2018-06-08 22:00:29 +00:00
|
|
|
SignalRestore(st *Stack, rt bool) (linux.SignalSet, SignalStack, error)
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
// CPUIDEmulate emulates a CPUID instruction according to current register state.
|
|
|
|
CPUIDEmulate(l log.Logger)
|
|
|
|
|
|
|
|
// SingleStep returns true if single stepping is enabled.
|
|
|
|
SingleStep() bool
|
|
|
|
|
|
|
|
// SetSingleStep enables single stepping.
|
|
|
|
SetSingleStep()
|
|
|
|
|
|
|
|
// ClearSingleStep disables single stepping.
|
|
|
|
ClearSingleStep()
|
|
|
|
|
|
|
|
// FloatingPointData will be passed to underlying save routines.
|
|
|
|
FloatingPointData() *FloatingPointData
|
|
|
|
|
|
|
|
// NewMmapLayout returns a layout for a new MM, where MinAddr for the
|
|
|
|
// returned layout must be no lower than min, and MaxAddr for the returned
|
|
|
|
// layout must be no higher than max. Repeated calls to NewMmapLayout may
|
|
|
|
// return different layouts.
|
|
|
|
NewMmapLayout(min, max usermem.Addr, limits *limits.LimitSet) (MmapLayout, error)
|
|
|
|
|
|
|
|
// PIELoadAddress returns a preferred load address for a
|
|
|
|
// position-independent executable within l.
|
|
|
|
PIELoadAddress(l MmapLayout) usermem.Addr
|
|
|
|
|
|
|
|
// FeatureSet returns the FeatureSet in use in this context.
|
|
|
|
FeatureSet() *cpuid.FeatureSet
|
|
|
|
|
|
|
|
// Hack around our package dependences being too broken to support the
|
|
|
|
// equivalent of arch_ptrace():
|
|
|
|
|
|
|
|
// PtracePeekUser implements ptrace(PTRACE_PEEKUSR).
|
|
|
|
PtracePeekUser(addr uintptr) (interface{}, error)
|
|
|
|
|
|
|
|
// PtracePokeUser implements ptrace(PTRACE_POKEUSR).
|
|
|
|
PtracePokeUser(addr, data uintptr) error
|
|
|
|
|
|
|
|
// PtraceGetRegs implements ptrace(PTRACE_GETREGS) by writing the
|
|
|
|
// general-purpose registers represented by this Context to dst and
|
|
|
|
// returning the number of bytes written.
|
|
|
|
PtraceGetRegs(dst io.Writer) (int, error)
|
|
|
|
|
|
|
|
// PtraceSetRegs implements ptrace(PTRACE_SETREGS) by reading
|
|
|
|
// general-purpose registers from src into this Context and returning the
|
|
|
|
// number of bytes read.
|
|
|
|
PtraceSetRegs(src io.Reader) (int, error)
|
|
|
|
|
|
|
|
// PtraceGetFPRegs implements ptrace(PTRACE_GETFPREGS) by writing the
|
|
|
|
// floating-point registers represented by this Context to addr in dst and
|
|
|
|
// returning the number of bytes written.
|
|
|
|
PtraceGetFPRegs(dst io.Writer) (int, error)
|
|
|
|
|
|
|
|
// PtraceSetFPRegs implements ptrace(PTRACE_SETFPREGS) by reading
|
|
|
|
// floating-point registers from src into this Context and returning the
|
|
|
|
// number of bytes read.
|
|
|
|
PtraceSetFPRegs(src io.Reader) (int, error)
|
|
|
|
|
|
|
|
// PtraceGetRegSet implements ptrace(PTRACE_GETREGSET) by writing the
|
|
|
|
// register set given by architecture-defined value regset from this
|
|
|
|
// Context to dst and returning the number of bytes written, which must be
|
|
|
|
// less than or equal to maxlen.
|
|
|
|
PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int) (int, error)
|
|
|
|
|
|
|
|
// PtraceSetRegSet implements ptrace(PTRACE_SETREGSET) by reading the
|
|
|
|
// register set given by architecture-defined value regset from src and
|
|
|
|
// returning the number of bytes read, which must be less than or equal to
|
|
|
|
// maxlen.
|
|
|
|
PtraceSetRegSet(regset uintptr, src io.Reader, maxlen int) (int, error)
|
|
|
|
|
|
|
|
// FullRestore returns 'true' if all CPU registers must be restored
|
|
|
|
// when switching to the untrusted application. Typically a task enters
|
|
|
|
// and leaves the kernel via a system call. Platform.Switch() may
|
|
|
|
// optimize for this by not saving/restoring all registers if allowed
|
|
|
|
// by the ABI. For e.g. the amd64 ABI specifies that syscall clobbers
|
|
|
|
// %rcx and %r11. If FullRestore returns true then these optimizations
|
|
|
|
// must be disabled and all registers restored.
|
|
|
|
FullRestore() bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// MmapDirection is a search direction for mmaps.
|
|
|
|
type MmapDirection int
|
|
|
|
|
|
|
|
const (
|
|
|
|
// MmapBottomUp instructs mmap to prefer lower addresses.
|
|
|
|
MmapBottomUp MmapDirection = iota
|
|
|
|
|
|
|
|
// MmapTopDown instructs mmap to prefer higher addresses.
|
|
|
|
MmapTopDown
|
|
|
|
)
|
|
|
|
|
|
|
|
// MmapLayout defines the layout of the user address space for a particular
|
|
|
|
// MemoryManager.
|
|
|
|
//
|
|
|
|
// Note that "highest address" below is always exclusive.
|
2018-08-02 17:41:44 +00:00
|
|
|
//
|
|
|
|
// +stateify savable
|
2018-04-27 17:37:02 +00:00
|
|
|
type MmapLayout struct {
|
|
|
|
// MinAddr is the lowest mappable address.
|
|
|
|
MinAddr usermem.Addr
|
|
|
|
|
|
|
|
// MaxAddr is the highest mappable address.
|
|
|
|
MaxAddr usermem.Addr
|
|
|
|
|
|
|
|
// BottomUpBase is the lowest address that may be returned for a
|
|
|
|
// MmapBottomUp mmap.
|
|
|
|
BottomUpBase usermem.Addr
|
|
|
|
|
|
|
|
// TopDownBase is the highest address that may be returned for a
|
|
|
|
// MmapTopDown mmap.
|
|
|
|
TopDownBase usermem.Addr
|
|
|
|
|
|
|
|
// DefaultDirection is the direction for most non-fixed mmaps in this
|
|
|
|
// layout.
|
|
|
|
DefaultDirection MmapDirection
|
|
|
|
|
|
|
|
// MaxStackRand is the maximum randomization to apply to stack
|
|
|
|
// allocations to maintain a proper gap between the stack and
|
|
|
|
// TopDownBase.
|
|
|
|
MaxStackRand uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Valid returns true if this layout is valid.
|
|
|
|
func (m *MmapLayout) Valid() bool {
|
|
|
|
if m.MinAddr > m.MaxAddr {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if m.BottomUpBase < m.MinAddr {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if m.BottomUpBase > m.MaxAddr {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if m.TopDownBase < m.MinAddr {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if m.TopDownBase > m.MaxAddr {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SyscallArgument is an argument supplied to a syscall implementation. The
|
|
|
|
// methods used to access the arguments are named after the ***C type name*** and
|
|
|
|
// they convert to the closest Go type available. For example, Int() refers to a
|
|
|
|
// 32-bit signed integer argument represented in Go as an int32.
|
|
|
|
//
|
|
|
|
// Using the accessor methods guarantees that the conversion between types is
|
|
|
|
// correct, taking into account size and signedness (i.e., zero-extension vs
|
|
|
|
// signed-extension).
|
|
|
|
type SyscallArgument struct {
|
|
|
|
// Prefer to use accessor methods instead of 'Value' directly.
|
|
|
|
Value uintptr
|
|
|
|
}
|
|
|
|
|
|
|
|
// SyscallArguments represents the set of arguments passed to a syscall.
|
|
|
|
type SyscallArguments [6]SyscallArgument
|
|
|
|
|
|
|
|
// Pointer returns the usermem.Addr representation of a pointer argument.
|
|
|
|
func (a SyscallArgument) Pointer() usermem.Addr {
|
|
|
|
return usermem.Addr(a.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Int returns the int32 representation of a 32-bit signed integer argument.
|
|
|
|
func (a SyscallArgument) Int() int32 {
|
|
|
|
return int32(a.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uint returns the uint32 representation of a 32-bit unsigned integer argument.
|
|
|
|
func (a SyscallArgument) Uint() uint32 {
|
|
|
|
return uint32(a.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Int64 returns the int64 representation of a 64-bit signed integer argument.
|
|
|
|
func (a SyscallArgument) Int64() int64 {
|
|
|
|
return int64(a.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uint64 returns the uint64 representation of a 64-bit unsigned integer argument.
|
|
|
|
func (a SyscallArgument) Uint64() uint64 {
|
|
|
|
return uint64(a.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SizeT returns the uint representation of a size_t argument.
|
|
|
|
func (a SyscallArgument) SizeT() uint {
|
|
|
|
return uint(a.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ModeT returns the int representation of a mode_t argument.
|
|
|
|
func (a SyscallArgument) ModeT() uint {
|
|
|
|
return uint(uint16(a.Value))
|
|
|
|
}
|