diff options
Diffstat (limited to 'pkg/sentry/arch/arch.go')
-rw-r--r-- | pkg/sentry/arch/arch.go | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/pkg/sentry/arch/arch.go b/pkg/sentry/arch/arch.go new file mode 100644 index 000000000..021789e4b --- /dev/null +++ b/pkg/sentry/arch/arch.go @@ -0,0 +1,351 @@ +// Copyright 2018 Google Inc. +// +// 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" + + "gvisor.googlesource.com/gvisor/pkg/abi/linux" + "gvisor.googlesource.com/gvisor/pkg/cpuid" + "gvisor.googlesource.com/gvisor/pkg/log" + "gvisor.googlesource.com/gvisor/pkg/sentry/limits" + "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" +) + +// Arch describes an architecture. +type Arch int + +const ( + // AMD64 is the x86-64 architecture. + AMD64 Arch = iota +) + +// String implements fmt.Stringer. +func (a Arch) String() string { + switch a { + case AMD64: + return "amd64" + 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. +// +// NOTE: Currently we use uintptr here to refer to a generic native +// 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) + + // 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. + SignalRestore(st *Stack, rt bool) (linux.SignalSet, error) + + // 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. +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)) +} |