package usertrap

import "gvisor.dev/gvisor/pkg/sentry/platform/systrap/usertrap"

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:

+checkalignedignore

Index

Variables

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")
)

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

Source Files

usertrap.go usertrap_amd64.go usertrap_amd64_unsafe.go

Version
v0.0.0-20250605235530-a6711d1e1dc6 (latest)
Published
Jun 5, 2025
Platform
linux/amd64
Imports
14 packages
Last checked
4 hours ago

Tools for package owners.