usertrap

package
v0.0.0-...-7aa4e8d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 14, 2024 License: Apache-2.0, MIT Imports: 14 Imported by: 1

Documentation

Overview

Package usertrap implements the library to replace syscall instructions with function calls.

The most often used pattern of performing a system call is a sequence of two instruction: mov sysno, %eax; syscall. The size of the mov instruction is 5 bytes and the size of the syscall instruction is 2 bytes. These two instruction can be replaced with a single jmp instruction with an absolute address below 2 gigabytes.

Here is a few tricks:

  • The GS register is used to access a per-thread memory.
  • The syscall instruction is replaced with the "jmp *%ds:offset" instruction. On x86_64, ds is always zero. offset is a 32-bit signed integer. This means that a service mapping for a table with syscall trampolines has to be mapped below 2GB.
  • We can't touch a process stack, so we have to use the jmp instruction instead of callq and generate a new function call for each replaced instruction. Each trampoline contains a syscall number and an return address.
  • The address for the syscall table is set so that the syscall instruction is replaced on an invalid instruction. This allows us to handle races when two threads are executing the same syscall concurrently. And this allows us to restart a syscall if it has been interrupted by a signal.

+checkalignedignore

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrFaultRestart indicates that the current stub thread has to be restarted.
	ErrFaultRestart = fmt.Errorf("need to restart stub thread")
	// ErrFaultSyscall indicates that the current fault has to be handled as a system call.
	ErrFaultSyscall = fmt.Errorf("need to handle as syscall")
)

Functions

This section is empty.

Types

type State

type State struct {
	// contains filtered or unexported fields
}

State represents the current state of the trap table.

+stateify savable

func New

func New() *State

New returns the new state structure.

func (*State) HandleFault

func (s *State) HandleFault(ctx context.Context, ac *arch.Context64, mm memoryManager) error

HandleFault handles a fault on a patched syscall instruction.

When we replace a system call with a function call, we replace two instructions with one instruction. This means that here can be a thread which called the first instruction, then another thread applied a binary patch and the first thread calls the second instruction.

To handle this case, the function call (jmp) instruction is constructed so that the first byte of the syscall instruction is changed with the one-byte invalid instruction (0x6). And in case of the race, the first thread will fault on the invalid instruction and HandleFault will restart the function call.

func (*State) PatchSyscall

func (s *State) PatchSyscall(ctx context.Context, ac *arch.Context64, mm memoryManager) error

PatchSyscall changes the syscall instruction into a function call.

func (*State) PostFork

func (s *State) PostFork()

PostFork unlocks the trap table. +checklocksreleaseread:s.mu

func (*State) PreFork

func (s *State) PreFork()

PreFork locks the trap table for reading. This call guarantees that the trap table will not be changed before the next PostFork call. +checklocksacquireread:s.mu

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL