Documentation
¶
Overview ¶
Package sysmsg provides a stub signal handler and a communication protocol between stub threads and the Sentry.
Note that this package is allowlisted for use of sync/atomic.
+checkalignedignore
Index ¶
Constants ¶
const ( // the thread stack. MsgOffsetFromSharedStack = PerThreadMemSize - hostarch.PageSize - PerThreadSharedStackOffset // SpinningQueueMemSize is the size of a spinning queue memory region. SpinningQueueMemSize = hostarch.PageSize )
LINT.IfChange Per-thread stack layout:
*------------* | guard page | |------------| | | | sysstack | | | *------------* | guard page | |------------| | | | ^ | | / \ | | | | | altstack | |------------| | sysmsg | *------------*
const ( // MaxFPStateLen is the largest possible FPState that we will save. // Note: This value was chosen to be able to fit ThreadContext into one page. MaxFPStateLen uint32 = 3584 // AllocatedSizeofThreadContextStruct defines how much memory to allocate for // one instance of ThreadContext. // We over allocate the memory for it because: // - The next instances needs to align to 64 bytes for purposes of xsave. // - It's nice to align it to the page boundary. AllocatedSizeofThreadContextStruct uintptr = 4096 )
const ( // PerThreadMemSize is the size of a per-thread memory region (32KB). PerThreadMemSize = 8 * hostarch.PageSize // GuardSize is the size of an unmapped region before the signal stack (4KB). GuardSize = hostarch.PageSize PerThreadPrivateStackOffset = GuardSize PerThreadPrivateStackSize = 2 * hostarch.PageSize // PerThreadSharedStackSize is the size of a per-thread stack region (16KB, includes stack + sysmsg). )
Variables ¶
var SighandlerBlob []byte
SighandlerBlob contains the compiled code of the sysmsg signal handler.
Functions ¶
func MsgToStackAddr ¶
MsgToStackAddr returns a start address of a stack.
func StackAddrToMsg ¶
StackAddrToMsg returns an address of a sysmsg structure.
func StackAddrToSyshandlerStack ¶
StackAddrToSyshandlerStack returns an address of a syshandler stack.
Types ¶
type ArchState ¶
type ArchState struct {
// contains filtered or unexported fields
}
ArchState defines variables specific to the architecture being used.
type ContextState ¶
type ContextState uint32
ContextState defines the reason the context has exited back to the sentry, or ContextStateNone if running/ready-to-run.
const ( // ContextStateNone means that is either running in the user task or is ready // to run in the user task. ContextStateNone ContextState = iota // ContextStateSyscall means that a syscall event is triggered from the // sighandler. ContextStateSyscall // ContextStateFault means that there is a fault event that needs to be // handled. ContextStateFault // ContextStateSyscallTrap means that a syscall event is triggered from // a function call (syshandler). ContextStateSyscallTrap // ContextStateSyscallCanBePatched means that the syscall can be replaced // with a function call. ContextStateSyscallCanBePatched // ContextStateUnexpectedDeath means a stub thread died unexpectedly. ContextStateUnexpectedDeath // ContextStateInvalid is an invalid state that the sentry should never see. ContextStateInvalid )
Context State types.
func (*ContextState) CompareAndSwap ¶
func (s *ContextState) CompareAndSwap(old, new ContextState) bool
CompareAndSwap performs a compare-and-swap operation on the state value.
func (*ContextState) Get ¶
func (s *ContextState) Get() ContextState
Get returns the current state value.
func (*ContextState) Set ¶
func (s *ContextState) Set(state ContextState)
Set atomically sets the state value.
type Msg ¶
type Msg struct {
// The next batch of fields is used to call the syshandler stub
// function. A system call can be replaced with a function call. When
// a function call is executed, it can't change the current process
// stack, so it needs to save stack and instruction registers, switch
// on its syshandler stack and call the jmp instruction to the syshandler
// address.
//
// Self is a pointer to itself in a process address space.
Self uint64
// RetAddr is a return address from the syshandler function.
RetAddr uint64
// Syshandler is an address of the syshandler function.
Syshandler uint64
// SyshandlerStack is an address of the thread syshandler stack.
SyshandlerStack uint64
// AppStack is a value of the stack register before calling the syshandler
// function.
AppStack uint64
// State indicates to the sentry what the sysmsg thread is doing at a given
// moment.
State ThreadState
// Context is a pointer to the ThreadContext struct that the current sysmsg
// thread is processing.
Context uint64
// FaultJump is the size of a faulted instruction.
FaultJump int32
// Err is the error value with which the {sig|sys}handler crashes the stub
// thread (see sysmsg.h:__panic).
Err int32
// ErrAdditional is an error value that gives additional information
// about the panic.
ErrAdditional int32
// Line is the code line on which the {sig|sys}handler crashed the stub thread
// (see sysmsg.h:panic).
Line int32
// Debug is a variable to use to get visibility into the stub from the sentry.
Debug uint64
// ThreadID is the ID of the sysmsg thread.
ThreadID uint32
// contains filtered or unexported fields
}
Msg contains the current state of the sysmsg thread.
func (*Msg) ConvertSysmsgErr ¶
func (m *Msg) ConvertSysmsgErr() *platform.ContextError
ConvertSysmsgErr converts m.Err to platform.ContextError.
type StubError ¶
type StubError int32
StubError are values that represent known stub-thread failure modes. Since these errors originate from the stub threads, look at sysmsg.h:stub_error.
const ( // StubErrorBadSysmsg indicates sysmsg->self did not match sysmsg. StubErrorBadSysmsg StubError = 0x0bad0000 + iota // StubErrorBadThreadState indicates sysmsg->state was invalid. StubErrorBadThreadState // StubErrorBadSpinningQueueDecref indicates stubs removed more threads // from spinning queue than were put in. StubErrorBadSpinningQueueDecref // StubErrorArchPrctl indicates an error when calling arch_prctl. StubErrorArchPrctl // StubErrorFutex indicates an error when calling futex. StubErrorFutex // StubErrorBadContextID indicates a context received from the context // queue was of unexpected value. StubErrorBadContextID // StubErrorFpStateBadHeader indicates that the floating point state // header did not match the expected value. StubErrorFpStateBadHeader )
type ThreadContext ¶
type ThreadContext struct {
// FPState is a region of memory where:
// - syshandler saves FPU state to using xsave/fxsave
// - sighandler copies FPU state to from ucontext->uc_mcontext.fpregs
// Note that xsave requires this region of memory to be 64 byte aligned;
// therefore allocations of ThreadContext must be too.
FPState [MaxFPStateLen]byte
// FPStateChanged is set to true when the stub thread needs to restore FPState
// because the sentry changed it.
FPStateChanged uint64
// Regs is the context's GP register set. The {sig|sys}handler will save and
// restore the user app's registers here.
Regs linux.PtraceRegs
// SignalInfo is the siginfo struct.
SignalInfo linux.SignalInfo
// Signo is the signal that the stub is requesting the sentry to handle.
Signo int64
// State indicates the reason why the context has exited back to the sentry.
State ContextState
// Interrupt is set to indicate that this context has been interrupted.
Interrupt uint32
// ThreadID is the ID of the sysmsg thread that's currently working on the
// context.
ThreadID uint32
// LastThreadID is the ID of the previous sysmsg thread that ran the context
// (not the one currently working on it). This field is used by sysmsg threads
// to detect whether fpstate may have changed since the last time they ran a
// context.
LastThreadID uint32
// SentryFastPath is used to indicate to the stub thread that the sentry
// goroutine used for this thread context is busy-polling for a response
// instead of using FUTEX_WAIT.
SentryFastPath uint32
// AckedTime is used by sysmsg threads to signal to the sentry that this context
// has been picked up from the context queue and is actively being worked on.
// The stub thread puts down the timestamp at which it has started processing
// this context.
AckedTime uint64
// StateChangedTime is the time when the ThreadContext.State changed, as
// recorded by the stub thread when it gave it back to the sentry
// (the sentry does not populate this field except to reset it).
StateChangedTime uint64
// TLS is a pointer to a thread local storage.
// It is is only populated on ARM64.
TLS uint64
// Debug is a variable to use to get visibility into the stub from the sentry.
Debug uint64
// SigError is an error code that clarifies the nature of the signal.
SigError uint64
}
ThreadContext contains the current context of the sysmsg thread. The struct facilitates switching contexts by allowing the sentry to switch pointers to this struct as it needs to.
N.B ThreadContexts are shared between all sysmsg threads within a subprocess, and are necessarily writeable by any thread within the subprocess. If a subprocess really wants to (i.e. sandbox break-out attempts) it can find where the TC region is mapped and use other threads to manipulate this data for a thread doing a context switch into the sentry. This is OK because as a rule we do not trust this data; if any funny business is going on the sentry simply kills the subprocess.
func (*ThreadContext) Init ¶
func (c *ThreadContext) Init(initialThreadID uint32)
Init initializes the ThreadContext instance.
func (*ThreadContext) SleepOnState ¶
func (c *ThreadContext) SleepOnState(curState ContextState, timeout *unix.Timespec) syscall.Errno
SleepOnState makes the caller sleep on the ThreadContext.State futex.
func (*ThreadContext) String ¶
func (c *ThreadContext) String() string
type ThreadState ¶
type ThreadState uint32
ThreadState is used to store a state of the sysmsg thread.
const ( // ThreadStateNone means that the thread is executing the user workload. ThreadStateNone ThreadState = iota // ThreadStateDone means that last event has been handled and the stub thread // can be resumed. ThreadStateDone // ThreadStatePrep means that syshandler started filling the sysmsg struct. ThreadStatePrep // ThreadStateAsleep means that this thread fell asleep because there was not // enough contexts to process in the context queue. ThreadStateAsleep // ThreadStateInitializing is only set once at sysmsg thread creation time. It // is used to tell the signal handler that the thread does not yet have a // context. ThreadStateInitializing )
func (*ThreadState) CompareAndSwap ¶
func (s *ThreadState) CompareAndSwap(old, state ThreadState) bool
CompareAndSwap atomicaly compares and swaps the state value.
func (*ThreadState) Get ¶
func (s *ThreadState) Get() ThreadState
Get returns the current state value.
func (*ThreadState) Set ¶
func (s *ThreadState) Set(state ThreadState)
Set atomicaly sets the state value.