github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/arch/arch.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package arch provides abstractions around architecture-dependent details,
    16  // such as syscall calling conventions, native types, etc.
    17  package arch
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/abi/linux"
    24  	"github.com/ttpreport/gvisor-ligolo/pkg/cpuid"
    25  	"github.com/ttpreport/gvisor-ligolo/pkg/hostarch"
    26  	"github.com/ttpreport/gvisor-ligolo/pkg/marshal"
    27  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/arch/fpu"
    28  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/limits"
    29  )
    30  
    31  // Arch describes an architecture.
    32  type Arch int
    33  
    34  const (
    35  	// AMD64 is the x86-64 architecture.
    36  	AMD64 Arch = iota
    37  	// ARM64 is the aarch64 architecture.
    38  	ARM64
    39  )
    40  
    41  // String implements fmt.Stringer.
    42  func (a Arch) String() string {
    43  	switch a {
    44  	case AMD64:
    45  		return "amd64"
    46  	case ARM64:
    47  		return "arm64"
    48  	default:
    49  		return fmt.Sprintf("Arch(%d)", a)
    50  	}
    51  }
    52  
    53  // contextInterface provides architecture-dependent information for a thread.
    54  // This is currently not referenced, because there exists only one concrete
    55  // implementation of this interface (*Context64), which we reference directly
    56  // wherever this interface could otherwise be used in order to avoid the
    57  // overhead involved in calling functions on interfaces in Go.
    58  // This interface is still useful in order to see the entire
    59  // architecture-dependent call surface it must support, as this is difficult
    60  // to follow across the rest of this module due to the conditional compilation
    61  // of the files that make it up.
    62  //
    63  // NOTE(b/34169503): Currently we use uintptr here to refer to a generic native
    64  // register value. While this will work for the foreseeable future, it isn't
    65  // strictly correct. We may want to create some abstraction that makes this
    66  // more clear or enables us to store values of arbitrary widths. This is
    67  // particularly true for RegisterMap().
    68  type contextInterface interface {
    69  	// Arch returns the architecture for this Context.
    70  	Arch() Arch
    71  
    72  	// Native converts a generic type to a native value.
    73  	//
    74  	// Because the architecture is not specified here, we may be dealing
    75  	// with return values of varying sizes (for example ARCH_GETFS). This
    76  	// is a simple utility function to convert to the native size in these
    77  	// cases, and then we can CopyOut.
    78  	Native(val uintptr) marshal.Marshallable
    79  
    80  	// Value converts a native type back to a generic value.
    81  	// Once a value has been converted to native via the above call -- it
    82  	// can be converted back here.
    83  	Value(val marshal.Marshallable) uintptr
    84  
    85  	// Width returns the number of bytes for a native value.
    86  	Width() uint
    87  
    88  	// Fork creates a clone of the context.
    89  	Fork() *Context64
    90  
    91  	// SyscallNo returns the syscall number.
    92  	SyscallNo() uintptr
    93  
    94  	// SyscallSaveOrig save orignal register value.
    95  	SyscallSaveOrig()
    96  
    97  	// SyscallArgs returns the syscall arguments in an array.
    98  	SyscallArgs() SyscallArguments
    99  
   100  	// Return returns the return value for a system call.
   101  	Return() uintptr
   102  
   103  	// SetReturn sets the return value for a system call.
   104  	SetReturn(value uintptr)
   105  
   106  	// RestartSyscall reverses over the current syscall instruction, such that
   107  	// when the application resumes execution the syscall will be re-attempted.
   108  	RestartSyscall()
   109  
   110  	// RestartSyscallWithRestartBlock reverses over the current syscall
   111  	// instraction and overwrites the current syscall number with that of
   112  	// restart_syscall(2). This causes the application to restart the current
   113  	// syscall with a custom function when execution resumes.
   114  	RestartSyscallWithRestartBlock()
   115  
   116  	// IP returns the current instruction pointer.
   117  	IP() uintptr
   118  
   119  	// SetIP sets the current instruction pointer.
   120  	SetIP(value uintptr)
   121  
   122  	// Stack returns the current stack pointer.
   123  	Stack() uintptr
   124  
   125  	// SetStack sets the current stack pointer.
   126  	SetStack(value uintptr)
   127  
   128  	// TLS returns the current TLS pointer.
   129  	TLS() uintptr
   130  
   131  	// SetTLS sets the current TLS pointer. Returns false if value is invalid.
   132  	SetTLS(value uintptr) bool
   133  
   134  	// SetOldRSeqInterruptedIP sets the register that contains the old IP
   135  	// when an "old rseq" restartable sequence is interrupted.
   136  	SetOldRSeqInterruptedIP(value uintptr)
   137  
   138  	// StateData returns a pointer to underlying architecture state.
   139  	StateData() *State
   140  
   141  	// RegisterMap returns a map of all registers.
   142  	RegisterMap() (map[string]uintptr, error)
   143  
   144  	// SignalSetup modifies the context in preparation for handling the
   145  	// given signal.
   146  	//
   147  	// st is the stack where the signal handler frame should be
   148  	// constructed.
   149  	//
   150  	// act is the SigAction that specifies how this signal is being
   151  	// handled.
   152  	//
   153  	// info is the SignalInfo of the signal being delivered.
   154  	//
   155  	// alt is the alternate signal stack (even if the alternate signal
   156  	// stack is not going to be used).
   157  	//
   158  	// sigset is the signal mask before entering the signal handler.
   159  	//
   160  	// featureSet is the application CPU feature set.
   161  	SignalSetup(st *Stack, act *linux.SigAction, info *linux.SignalInfo, alt *linux.SignalStack, sigset linux.SignalSet, featureSet cpuid.FeatureSet) error
   162  
   163  	// SignalRestore restores context after returning from a signal
   164  	// handler.
   165  	//
   166  	// st is the current thread stack.
   167  	//
   168  	// rt is true if SignalRestore is being entered from rt_sigreturn and
   169  	// false if SignalRestore is being entered from sigreturn.
   170  	//
   171  	// featureSet is the application CPU feature set.
   172  	//
   173  	// SignalRestore returns the thread's new signal mask.
   174  	SignalRestore(st *Stack, rt bool, featureSet cpuid.FeatureSet) (linux.SignalSet, linux.SignalStack, error)
   175  
   176  	// SingleStep returns true if single stepping is enabled.
   177  	SingleStep() bool
   178  
   179  	// SetSingleStep enables single stepping.
   180  	SetSingleStep()
   181  
   182  	// ClearSingleStep disables single stepping.
   183  	ClearSingleStep()
   184  
   185  	// FloatingPointData will be passed to underlying save routines.
   186  	FloatingPointData() *fpu.State
   187  
   188  	// NewMmapLayout returns a layout for a new MM, where MinAddr for the
   189  	// returned layout must be no lower than min, and MaxAddr for the returned
   190  	// layout must be no higher than max. Repeated calls to NewMmapLayout may
   191  	// return different layouts.
   192  	NewMmapLayout(min, max hostarch.Addr, limits *limits.LimitSet) (MmapLayout, error)
   193  
   194  	// PIELoadAddress returns a preferred load address for a
   195  	// position-independent executable within l.
   196  	PIELoadAddress(l MmapLayout) hostarch.Addr
   197  
   198  	// Hack around our package dependences being too broken to support the
   199  	// equivalent of arch_ptrace():
   200  
   201  	// PtracePeekUser implements ptrace(PTRACE_PEEKUSR).
   202  	PtracePeekUser(addr uintptr) (marshal.Marshallable, error)
   203  
   204  	// PtracePokeUser implements ptrace(PTRACE_POKEUSR).
   205  	PtracePokeUser(addr, data uintptr) error
   206  
   207  	// PtraceGetRegs implements ptrace(PTRACE_GETREGS) by writing the
   208  	// general-purpose registers represented by this Context to dst and
   209  	// returning the number of bytes written.
   210  	PtraceGetRegs(dst io.Writer) (int, error)
   211  
   212  	// PtraceSetRegs implements ptrace(PTRACE_SETREGS) by reading
   213  	// general-purpose registers from src into this Context and returning the
   214  	// number of bytes read.
   215  	PtraceSetRegs(src io.Reader) (int, error)
   216  
   217  	// PtraceGetRegSet implements ptrace(PTRACE_GETREGSET) by writing the
   218  	// register set given by architecture-defined value regset from this
   219  	// Context to dst and returning the number of bytes written, which must be
   220  	// less than or equal to maxlen.
   221  	PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int, fs cpuid.FeatureSet) (int, error)
   222  
   223  	// PtraceSetRegSet implements ptrace(PTRACE_SETREGSET) by reading the
   224  	// register set given by architecture-defined value regset from src and
   225  	// returning the number of bytes read, which must be less than or equal to
   226  	// maxlen.
   227  	PtraceSetRegSet(regset uintptr, src io.Reader, maxlen int, fs cpuid.FeatureSet) (int, error)
   228  
   229  	// FullRestore returns 'true' if all CPU registers must be restored
   230  	// when switching to the untrusted application. Typically a task enters
   231  	// and leaves the kernel via a system call. Platform.Switch() may
   232  	// optimize for this by not saving/restoring all registers if allowed
   233  	// by the ABI. For e.g. the amd64 ABI specifies that syscall clobbers
   234  	// %rcx and %r11. If FullRestore returns true then these optimizations
   235  	// must be disabled and all registers restored.
   236  	FullRestore() bool
   237  }
   238  
   239  // Compile-time assertion that Context64 implements contextInterface.
   240  var _ = (contextInterface)((*Context64)(nil))
   241  
   242  // MmapDirection is a search direction for mmaps.
   243  type MmapDirection int
   244  
   245  const (
   246  	// MmapBottomUp instructs mmap to prefer lower addresses.
   247  	MmapBottomUp MmapDirection = iota
   248  
   249  	// MmapTopDown instructs mmap to prefer higher addresses.
   250  	MmapTopDown
   251  )
   252  
   253  // MmapLayout defines the layout of the user address space for a particular
   254  // MemoryManager.
   255  //
   256  // Note that "highest address" below is always exclusive.
   257  //
   258  // +stateify savable
   259  type MmapLayout struct {
   260  	// MinAddr is the lowest mappable address.
   261  	MinAddr hostarch.Addr
   262  
   263  	// MaxAddr is the highest mappable address.
   264  	MaxAddr hostarch.Addr
   265  
   266  	// BottomUpBase is the lowest address that may be returned for a
   267  	// MmapBottomUp mmap.
   268  	BottomUpBase hostarch.Addr
   269  
   270  	// TopDownBase is the highest address that may be returned for a
   271  	// MmapTopDown mmap.
   272  	TopDownBase hostarch.Addr
   273  
   274  	// DefaultDirection is the direction for most non-fixed mmaps in this
   275  	// layout.
   276  	DefaultDirection MmapDirection
   277  
   278  	// MaxStackRand is the maximum randomization to apply to stack
   279  	// allocations to maintain a proper gap between the stack and
   280  	// TopDownBase.
   281  	MaxStackRand uint64
   282  }
   283  
   284  // Valid returns true if this layout is valid.
   285  func (m *MmapLayout) Valid() bool {
   286  	if m.MinAddr > m.MaxAddr {
   287  		return false
   288  	}
   289  	if m.BottomUpBase < m.MinAddr {
   290  		return false
   291  	}
   292  	if m.BottomUpBase > m.MaxAddr {
   293  		return false
   294  	}
   295  	if m.TopDownBase < m.MinAddr {
   296  		return false
   297  	}
   298  	if m.TopDownBase > m.MaxAddr {
   299  		return false
   300  	}
   301  	return true
   302  }
   303  
   304  // SyscallArgument is an argument supplied to a syscall implementation. The
   305  // methods used to access the arguments are named after the ***C type name*** and
   306  // they convert to the closest Go type available. For example, Int() refers to a
   307  // 32-bit signed integer argument represented in Go as an int32.
   308  //
   309  // Using the accessor methods guarantees that the conversion between types is
   310  // correct, taking into account size and signedness (i.e., zero-extension vs
   311  // signed-extension).
   312  type SyscallArgument struct {
   313  	// Prefer to use accessor methods instead of 'Value' directly.
   314  	Value uintptr
   315  }
   316  
   317  // SyscallArguments represents the set of arguments passed to a syscall.
   318  type SyscallArguments [6]SyscallArgument
   319  
   320  // Pointer returns the hostarch.Addr representation of a pointer argument.
   321  func (a SyscallArgument) Pointer() hostarch.Addr {
   322  	return hostarch.Addr(a.Value)
   323  }
   324  
   325  // Int returns the int32 representation of a 32-bit signed integer argument.
   326  func (a SyscallArgument) Int() int32 {
   327  	return int32(a.Value)
   328  }
   329  
   330  // Uint returns the uint32 representation of a 32-bit unsigned integer argument.
   331  func (a SyscallArgument) Uint() uint32 {
   332  	return uint32(a.Value)
   333  }
   334  
   335  // Int64 returns the int64 representation of a 64-bit signed integer argument.
   336  func (a SyscallArgument) Int64() int64 {
   337  	return int64(a.Value)
   338  }
   339  
   340  // Uint64 returns the uint64 representation of a 64-bit unsigned integer argument.
   341  func (a SyscallArgument) Uint64() uint64 {
   342  	return uint64(a.Value)
   343  }
   344  
   345  // SizeT returns the uint representation of a size_t argument.
   346  func (a SyscallArgument) SizeT() uint {
   347  	return uint(a.Value)
   348  }
   349  
   350  // ModeT returns the int representation of a mode_t argument.
   351  func (a SyscallArgument) ModeT() uint {
   352  	return uint(uint16(a.Value))
   353  }