diff --git a/pkg/sentry/platform/systrap/stub_unsafe.go b/pkg/sentry/platform/systrap/stub_unsafe.go index 0780baaa8..d87494ade 100644 --- a/pkg/sentry/platform/systrap/stub_unsafe.go +++ b/pkg/sentry/platform/systrap/stub_unsafe.go @@ -109,18 +109,19 @@ func stubInit() { // |--------stubSysmsgStack-------------| // | Reserved space for per-thread | // | sysmsg stacks. | + // |--------stubThreadContextRegion-----| + // | Reserved space for thread contexts | // *------------------------------------* - pageMask := uintptr(hostarch.PageSize - 1) // Grab the existing stub. procStubBegin := addrOfInitStubProcess() procStubLen := int(safecopy.FindEndAddress(procStubBegin) - procStubBegin) procStubSlice := unsafeSlice(procStubBegin, procStubLen) - mapLen := (uintptr(procStubLen) + pageMask) & ^pageMask + mapLen, _ := hostarch.PageRoundUp(uintptr(procStubLen)) stubSysmsgStart = mapLen stubSysmsgLen := len(sysmsg.SighandlerBlob) - mapLen += (uintptr(stubSysmsgLen) + pageMask) & ^pageMask + mapLen, _ = hostarch.PageRoundUp(mapLen + uintptr(stubSysmsgLen)) stubSysmsgRules = mapLen stubSysmsgRulesLen = hostarch.PageSize * 4 @@ -133,7 +134,11 @@ func stubInit() { // Allocate maxGuestThreads plus ONE because each per-thread stack // has to be aligned to sysmsg.PerThreadMemSize. // Look at sysmsg/sighandler.c:sysmsg_addr() for more details. - mapLen += sysmsg.PerThreadMemSize * (maxGuestThreads + 1) + mapLen, _ = hostarch.PageRoundUp(mapLen + sysmsg.PerThreadMemSize*(maxSystemThreads+1)) + // Allocate thread context region + stubContextRegion = mapLen + stubContextRegionLen = sysmsg.AllocatedSizeofThreadContextStruct * (maxGuestContexts + 1) + mapLen, _ = hostarch.PageRoundUp(mapLen + stubContextRegionLen) // Randomize stubStart address. randomOffset := uintptr(rand.Uint64() * hostarch.PageSize) @@ -172,6 +177,7 @@ func stubInit() { // Randomize stubSysmsgStack address. gap := uintptr(rand.Uint64()) * hostarch.PageSize % (maximumUserAddress - stubStart - mapLen) stubSysmsgStack += uintptr(gap) + stubContextRegion += uintptr(gap) // Copy the stub to the address. targetSlice := unsafeSlice(stubStart, procStubLen) @@ -181,6 +187,7 @@ func stubInit() { stubSysmsgStart += stubStart stubSysmsgStack += stubStart stubROMapEnd += stubStart + stubContextRegion += stubStart // Align stubSysmsgStack to the per-thread stack size. // Look at sysmsg/sighandler.c:sysmsg_addr() for more details. @@ -217,7 +224,7 @@ func stubInit() { // Set the end. stubEnd = stubStart + mapLen + uintptr(gap) - log.Debugf("stubStart %x stubSysmsgStart %x stubSysmsgStack %x, mapLen %x", stubStart, stubSysmsgStart, stubSysmsgStack, mapLen) + log.Debugf("stubStart %x stubSysmsgStart %x stubSysmsgStack %x, stubThreadContextRegion %x, mapLen %x", stubStart, stubSysmsgStart, stubSysmsgStack, stubContextRegion, mapLen) log.Debugf(archState.String()) log.Debugf("contextDecouplingExp=%t", contextDecouplingExp) } diff --git a/pkg/sentry/platform/systrap/subprocess.go b/pkg/sentry/platform/systrap/subprocess.go index 82022c61a..b38a3e459 100644 --- a/pkg/sentry/platform/systrap/subprocess.go +++ b/pkg/sentry/platform/systrap/subprocess.go @@ -99,7 +99,12 @@ type requestStub struct { } const ( - maxGuestThreads = 4096 + // maxSystemThreads specifies the maximum number of system threads that a + // subprocess may create in order to process the contexts. + maxSystemThreads = 4096 + // maxGuestContexts specifies the maximum number of task contexts that a + // subprocess can handle. + maxGuestContexts = 4096 ) // subprocess is a collection of threads being traced. @@ -123,13 +128,20 @@ type subprocess struct { // reused until all tied contexts have been unregistered. released bool - // contexts is the set of contexts for which it's possible that + // faultedContexts is the set of contexts for which it's possible that // context.lastFaultSP == this subprocess. - contexts map[*context]struct{} + faultedContexts map[*context]struct{} // sysmsgStackPool is a pool of available sysmsg stacks. sysmsgStackPool pool.Pool + // threadContextPool is a pool of available sysmsg.ThreadContext IDs. + threadContextPool pool.Pool + + // threadContextRegion defines the ThreadContext memory region start + // within the sentry address space. + threadContextRegion uintptr + // memoryFile is used to allocate a sysmsg stack which is shared // between a stub process and the Sentry. memoryFile *pgalloc.MemoryFile @@ -244,10 +256,11 @@ func newSubprocess(create func() (*thread, error), memoryFile *pgalloc.MemoryFil // Ready. sp := &subprocess{ - requests: requests, - contexts: make(map[*context]struct{}), - sysmsgStackPool: pool.Pool{Start: 0, Limit: maxGuestThreads}, - memoryFile: memoryFile, + requests: requests, + faultedContexts: make(map[*context]struct{}), + sysmsgStackPool: pool.Pool{Start: 0, Limit: maxSystemThreads}, + threadContextPool: pool.Pool{Start: 0, Limit: maxGuestContexts}, + memoryFile: memoryFile, } runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -275,11 +288,61 @@ func newSubprocess(create func() (*thread, error), memoryFile *pgalloc.MemoryFil sp.unmap() sp.usertrap = usertrap.New() + sp.mapSharedRegions() globalPool.add(sp) return sp, nil } +// mapSharedRegions maps the shared regions that are used between the subprocess +// and ALL of the subsequently created sysmsg threads into both the sentry and +// the syscall thread. +// +// Should be called before any sysmsg threads are created. +// Initializes s.contextQueue and s.threadContextRegion. +func (s *subprocess) mapSharedRegions() { + if s.threadContextRegion != 0 { + panic("contextQueue or threadContextRegion was already initialized") + } + + opts := pgalloc.AllocOpts{ + Kind: usage.System, + Dir: pgalloc.TopDown, + } + + // Map thread context region into the sentry. + threadContextFR, err := s.memoryFile.Allocate(uint64(stubContextRegionLen), opts) + if err != nil { + panic(fmt.Sprintf("failed to allocate a new subprocess context memory region")) + } + sentryThreadContextRegionAddr, _, errno := unix.RawSyscall6( + unix.SYS_MMAP, + 0, + uintptr(threadContextFR.Length()), + unix.PROT_WRITE|unix.PROT_READ, + unix.MAP_SHARED|unix.MAP_FILE, + uintptr(s.memoryFile.FD()), uintptr(threadContextFR.Start)) + if errno != 0 { + panic(fmt.Sprintf("mmap failed for subprocess context memory region: %v", errno)) + } + + // Map thread context region into the syscall thread. + // Map shared regions that will be the same and used for all sysmsg threads + // in this subprocess. + if _, err := s.syscallThread.syscall( + unix.SYS_MMAP, + arch.SyscallArgument{Value: uintptr(stubContextRegion)}, + arch.SyscallArgument{Value: uintptr(threadContextFR.Length())}, + arch.SyscallArgument{Value: uintptr(unix.PROT_READ | unix.PROT_WRITE)}, + arch.SyscallArgument{Value: uintptr(unix.MAP_SHARED | unix.MAP_FILE | unix.MAP_FIXED)}, + arch.SyscallArgument{Value: uintptr(s.memoryFile.FD())}, + arch.SyscallArgument{Value: uintptr(threadContextFR.Start)}); err != nil { + panic(fmt.Sprintf("failed to mmap context queue region into syscall thread: %v", err)) + } + + s.threadContextRegion = sentryThreadContextRegionAddr +} + // unmap unmaps non-stub regions of the process. // // This will panic on failure (which should never happen). @@ -659,7 +722,7 @@ func (s *subprocess) Unmap(addr hostarch.Addr, length uint64) { panic(fmt.Sprintf("addr %#x + length %#x overflows", addr, length)) } s.mu.Lock() - for c := range s.contexts { + for c := range s.faultedContexts { c.mu.Lock() if c.lastFaultSP == s && ar.Contains(c.lastFaultAddr) { // Forget the last fault so that if c faults again, the fault isn't @@ -667,7 +730,7 @@ func (s *subprocess) Unmap(addr hostarch.Addr, length uint64) { // due to munmap() of the corresponding vma, handling of the second // fault will fail anyway. c.lastFaultSP = nil - delete(s.contexts, c) + delete(s.faultedContexts, c) } c.mu.Unlock() } @@ -850,7 +913,7 @@ func (s *subprocess) unregisterContext(c *context) { return } s.mu.Lock() - delete(s.contexts, c) + delete(s.faultedContexts, c) s.numContexts.Add(-1) released := s.released s.mu.Unlock() diff --git a/pkg/sentry/platform/systrap/sysmsg/BUILD b/pkg/sentry/platform/systrap/sysmsg/BUILD index 633f8da6b..44ac4fc54 100644 --- a/pkg/sentry/platform/systrap/sysmsg/BUILD +++ b/pkg/sentry/platform/systrap/sysmsg/BUILD @@ -17,15 +17,13 @@ cc_pie_obj( srcs = select_arch( amd64 = [ "sighandler_amd64.c", - "sysmsg.h", - "sysmsg_offsets.h", + "sysmsg_offsets_amd64.h", ], - arm64 = [ - "sighandler_arm64.c", - "sysmsg.h", - "sysmsg_offsets.h", - ], - ), + arm64 = ["sighandler_arm64.c"], + ) + [ + "sysmsg.h", + "sysmsg_offsets.h", + ], outs = ["sighandler.o"], ) @@ -53,13 +51,12 @@ cc_pie_obj( srcs = select_arch( amd64 = [ "syshandler_amd64.S", - "sysmsg_offsets.h", + "sysmsg_offsets_amd64.h", ], - arm64 = [ - "syshandler_arm64.S", - "sysmsg_offsets.h", - ], - ), + arm64 = ["syshandler_arm64.S"], + ) + [ + "sysmsg_offsets.h", + ], outs = ["syshandler.o"], ) diff --git a/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c b/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c index 23c8a9c54..15d9e207a 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c +++ b/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c @@ -28,6 +28,7 @@ #include "sysmsg.h" #include "sysmsg_offsets.h" +#include "sysmsg_offsets_amd64.h" long __syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { unsigned long ret; @@ -298,19 +299,6 @@ long __syshandler(long a1, long a2, long a3, long __unused, long a5, long a6) { :); asm volatile("movq %%gs:0, %0\n" : "=r"(sysmsg) : :); - BUILD_BUG_ON(offsetof_sysmsg_self != offsetof(struct sysmsg, self)); - BUILD_BUG_ON(offsetof_sysmsg_ret_addr != offsetof(struct sysmsg, ret_addr)); - BUILD_BUG_ON(offsetof_sysmsg_syshandler != - offsetof(struct sysmsg, syshandler)); - BUILD_BUG_ON(offsetof_sysmsg_syshandler_stack != - offsetof(struct sysmsg, syshandler_stack)); - BUILD_BUG_ON(offsetof_sysmsg_app_stack != offsetof(struct sysmsg, app_stack)); - BUILD_BUG_ON(offsetof_sysmsg_interrupt != offsetof(struct sysmsg, interrupt)); - BUILD_BUG_ON(offsetof_sysmsg_type != offsetof(struct sysmsg, type)); - BUILD_BUG_ON(offsetof_sysmsg_state != offsetof(struct sysmsg, state)); - BUILD_BUG_ON(kSYSMSG_SYSCALL != SYSMSG_SYSCALL); - BUILD_BUG_ON(kSYSMSG_INTERRUPT != SYSMSG_INTERRUPT); - // SYSMSG_STATE_PREP is set to postpone interrupts. Look at // __export_sighandler for more details. int state = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); @@ -342,3 +330,63 @@ long __syshandler(long a1, long a2, long a3, long __unused, long a5, long a6) { __atomic_store_n(&sysmsg->state, SYSMSG_STATE_NONE, __ATOMIC_RELEASE); return sysret; } + +void verify_offsets_amd64() { +#define PTREGS_OFFSET offsetof(struct thread_context, ptregs) + BUILD_BUG_ON(offsetof_thread_context_ptregs != PTREGS_OFFSET); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r15 != + (offsetof(struct user_regs_struct, r15) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r14 != + (offsetof(struct user_regs_struct, r14) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r13 != + (offsetof(struct user_regs_struct, r13) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r12 != + (offsetof(struct user_regs_struct, r12) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rbp != + (offsetof(struct user_regs_struct, rbp) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rbx != + (offsetof(struct user_regs_struct, rbx) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r11 != + (offsetof(struct user_regs_struct, r11) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r10 != + (offsetof(struct user_regs_struct, r10) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r9 != + (offsetof(struct user_regs_struct, r9) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_r8 != + (offsetof(struct user_regs_struct, r8) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rax != + (offsetof(struct user_regs_struct, rax) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rcx != + (offsetof(struct user_regs_struct, rcx) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rdx != + (offsetof(struct user_regs_struct, rdx) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rsi != + (offsetof(struct user_regs_struct, rsi) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rdi != + (offsetof(struct user_regs_struct, rdi) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_orig_rax != + (offsetof(struct user_regs_struct, orig_rax) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rip != + (offsetof(struct user_regs_struct, rip) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_cs != + (offsetof(struct user_regs_struct, cs) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_eflags != + (offsetof(struct user_regs_struct, eflags) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_rsp != + (offsetof(struct user_regs_struct, rsp) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_ss != + (offsetof(struct user_regs_struct, ss) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_fs_base != + (offsetof(struct user_regs_struct, fs_base) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_gs_base != + (offsetof(struct user_regs_struct, gs_base) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_ds != + (offsetof(struct user_regs_struct, ds) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_es != + (offsetof(struct user_regs_struct, es) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_fs != + (offsetof(struct user_regs_struct, fs) + PTREGS_OFFSET)); + BUILD_BUG_ON(offsetof_thread_context_ptregs_gs != + (offsetof(struct user_regs_struct, gs) + PTREGS_OFFSET)); +#undef PTREGS_OFFSET +} diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg.go b/pkg/sentry/platform/systrap/sysmsg/sysmsg.go index c69f1d70a..a77291da5 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg.go +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg.go @@ -152,7 +152,8 @@ type Msg struct { 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 is a value of the stack register before calling the syshandler + // function. AppStack uint64 // interrupt is non-zero if there is a postponed interrupt. interrupt uint32 @@ -160,11 +161,24 @@ type Msg struct { FaultJump int32 Type EventType State State + // ContextID is the ID of the ThreadContext struct that the current + // sysmsg thread is is processing. This ID is used in the {sig|sys}handler + // to find the offset to the correct ThreadContext struct location. + ContextID uint64 + // ContextRegion defines the ThreadContext memory region start within + // the sysmsg thread address space. + ContextRegion uint64 - Signo int32 - Err int32 - Line int32 - debug uint64 + // Signo is the signal that the stub is requesting the sentry to handle. + Signo int32 + // Err is the error value with which the {sig|sys}handler crashes the stub + // thread (see sysmsg.h:__panic). + Err 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 Regs linux.PtraceRegs fpState uint64 SignalInfo linux.SignalInfo @@ -190,6 +204,48 @@ type Msg struct { stubFastPath uint32 sentryFastPath uint32 AckedEvents uint32 + // InterruptedContextID is the target of the interrupt sent to sysmsg thread. + InterruptedContextID uint64 +} + +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 = 3648 + + // 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 +) + +// 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. +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 + // Interrupt is set to indicate that this context has been interrupted. + Interrupt uint64 + // Debug is a variable to use to get visibility into the stub from the sentry. + Debug uint64 } // LINT.ThenChange(sysmsg.h) @@ -202,6 +258,14 @@ func (m *Msg) Init() { m.sentryFastPath = 1 } +// Init initializes the ThreadContext instance. +func (c *ThreadContext) Init() { + c.FPStateChanged = 1 + c.Regs = linux.PtraceRegs{} + c.Signo = 0 + c.SignalInfo = linux.SignalInfo{} +} + // StubFastPath returns true if the stub thread in the polling mode. func (m *Msg) StubFastPath() bool { return atomic.LoadUint32(&m.stubFastPath) != 0 @@ -236,9 +300,21 @@ func (m *Msg) String() string { var b strings.Builder fmt.Fprintf(&b, "sysmsg.Msg{msg: %x type %d", m.Self, m.Type) fmt.Fprintf(&b, " fault addr %x syscall %d", m.SignalInfo.Addr(), m.SignalInfo.Syscall()) - fmt.Fprintf(&b, " err %x line %d debug %x", m.Err, m.Line, m.debug) + fmt.Fprintf(&b, " err %x line %d debug %x", m.Err, m.Line, m.Debug) fmt.Fprintf(&b, " ip %x sp %x ret addr %x app stack %x", m.Regs.InstructionPointer(), m.Regs.StackPointer(), m.RetAddr, m.AppStack) - fmt.Fprintf(&b, " signo: %d, siginfo: %+v", m.Signo, m.SignalInfo) + fmt.Fprintf(&b, " signo %d siginfo %+v", m.Signo, m.SignalInfo) + fmt.Fprintf(&b, " contextID %d", m.ContextID) + b.WriteString("}") + + return b.String() +} + +func (c *ThreadContext) String() string { + var b strings.Builder + fmt.Fprintf(&b, "sysmsg.ThreadContext{fault addr %x syscall %d", c.SignalInfo.Addr(), c.SignalInfo.Syscall()) + fmt.Fprintf(&b, " ip %x sp %x", c.Regs.InstructionPointer(), c.Regs.StackPointer()) + fmt.Fprintf(&b, " FPStateChanged %d Regs %+v", c.FPStateChanged, c.Regs) + fmt.Fprintf(&b, " signo: %d, siginfo: %+v", c.Signo, c.SignalInfo) b.WriteString("}") return b.String() diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg.h b/pkg/sentry/platform/systrap/sysmsg/sysmsg.h index 6a0c91206..6c598dbce 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg.h +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg.h @@ -18,6 +18,8 @@ #include #include +#include "sysmsg_offsets.h" // NOLINT + #if defined(__x86_64__) // LINT.IfChange struct arch_state { @@ -50,6 +52,7 @@ enum sysmsg_type { SYSMSG_INTERRUPT, }; +// sysmsg contains the current state of the sysmsg thread. See: sysmsg.go:Msg struct sysmsg { struct sysmsg *self; uint64_t ret_addr; @@ -60,6 +63,10 @@ struct sysmsg { int32_t fault_jump; uint32_t type; uint32_t state; + uint64_t context_id; + uint64_t context_region; + + // The fields above have offsets defined in sysmsg_offsets*.h int32_t signo; int32_t err; @@ -73,6 +80,21 @@ struct sysmsg { uint32_t stub_fast_path; uint32_t sentry_fast_path; uint32_t acked_events; + uint64_t interrupted_context_id; +}; + +// thread_context contains the current context of the sysmsg thread. +// See sysmsg.go:SysThreadContext +struct thread_context { + uint8_t fpstate[MAX_FPSTATE_LEN]; + uint64_t fpstate_changed; + struct user_regs_struct ptregs; + + // The fields above have offsets defined in sysmsg_offsets*.h + + siginfo_t siginfo; + int64_t signo; + uint64_t interrupt; }; #ifndef PAGE_SIZE diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c b/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c index 80ff12de3..5357ebda0 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c @@ -126,3 +126,34 @@ out: __atomic_fetch_add(&sysmsg->acked_events, 1, __ATOMIC_SEQ_CST); return v; } + +void verify_offsets() { + BUILD_BUG_ON(offsetof_sysmsg_self != offsetof(struct sysmsg, self)); + BUILD_BUG_ON(offsetof_sysmsg_ret_addr != offsetof(struct sysmsg, ret_addr)); + BUILD_BUG_ON(offsetof_sysmsg_syshandler != + offsetof(struct sysmsg, syshandler)); + BUILD_BUG_ON(offsetof_sysmsg_syshandler_stack != + offsetof(struct sysmsg, syshandler_stack)); + BUILD_BUG_ON(offsetof_sysmsg_app_stack != offsetof(struct sysmsg, app_stack)); + BUILD_BUG_ON(offsetof_sysmsg_interrupt != offsetof(struct sysmsg, interrupt)); + BUILD_BUG_ON(offsetof_sysmsg_type != offsetof(struct sysmsg, type)); + BUILD_BUG_ON(offsetof_sysmsg_state != offsetof(struct sysmsg, state)); + BUILD_BUG_ON(offsetof_sysmsg_context_id != + offsetof(struct sysmsg, context_id)); + BUILD_BUG_ON(offsetof_sysmsg_context_region != + offsetof(struct sysmsg, context_region)); + + BUILD_BUG_ON(offsetof_thread_context_fpstate != + offsetof(struct thread_context, fpstate)); + BUILD_BUG_ON(offsetof_thread_context_fpstate_changed != + offsetof(struct thread_context, fpstate_changed)); + BUILD_BUG_ON(offsetof_thread_context_ptregs != + offsetof(struct thread_context, ptregs)); + + BUILD_BUG_ON(kSYSMSG_SYSCALL != SYSMSG_SYSCALL); + BUILD_BUG_ON(kSYSMSG_INTERRUPT != SYSMSG_INTERRUPT); + BUILD_BUG_ON(kSYSMSG_STATE_NONE != SYSMSG_STATE_NONE); + + BUILD_BUG_ON(sizeof(struct thread_context) > + ALLOCATED_SIZEOF_THREAD_CONTEXT_STRUCT); +} diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h index 84cfaf342..15ed97d49 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h @@ -20,6 +20,11 @@ // for the pkg/sentry/platform/systrap/usertrap package. #define FAULT_OPCODE 0x06 +// LINT.IfChange +#define MAX_FPSTATE_LEN 3648 +#define ALLOCATED_SIZEOF_THREAD_CONTEXT_STRUCT 4096 +// LINT.ThenChange(sysmsg.go) + // LINT.IfChange // Define offsets in the struct sysmsg to use them in assembly files. @@ -32,10 +37,18 @@ #define offsetof_sysmsg_interrupt 0x28 #define offsetof_sysmsg_type 0x30 #define offsetof_sysmsg_state 0x34 +#define offsetof_sysmsg_context_id 0x38 +#define offsetof_sysmsg_context_region 0x40 + +#define offsetof_thread_context_fpstate 0x0 +#define offsetof_thread_context_fpstate_changed MAX_FPSTATE_LEN +#define offsetof_thread_context_ptregs 0x8 + MAX_FPSTATE_LEN #define kSYSMSG_SYSCALL 1 #define kSYSMSG_INTERRUPT 5 -// LINT.ThenChange(sysmsg.h, sighandler.c) +#define kSYSMSG_STATE_NONE 0 + +// LINT.ThenChange(sysmsg.h, sysmsg_lib.c) #endif // THIRD_PARTY_GVISOR_PKG_SENTRY_PLATFORM_SYSTRAP_SYSMSG_SYSMSG_OFFSETS_H_ diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets_amd64.h b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets_amd64.h new file mode 100644 index 000000000..e01e633aa --- /dev/null +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets_amd64.h @@ -0,0 +1,89 @@ +// Copyright 2022 The gVisor Authors. +// +// 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. + +#ifndef THIRD_PARTY_GVISOR_PKG_SENTRY_PLATFORM_SYSTRAP_SYSMSG_SYSMSG_OFFSETS_AMD64_H_ +#define THIRD_PARTY_GVISOR_PKG_SENTRY_PLATFORM_SYSTRAP_SYSMSG_SYSMSG_OFFSETS_AMD64_H_ + +// LINT.IfChange + +#define offsetof_arch_state_xsave_mode (0x0) +#define offsetof_arch_state_fpLen (0x4) +#define offsetof_arch_state_fsgsbase (0x8) + +#define XSAVE_MODE_FXSAVE (0x0) +#define XSAVE_MODE_XSAVE (0x1) +#define XSAVE_MODE_XSAVEOPT (0x2) +#define XSAVE_MODE_XSAVEC (0x3) + +// LINT.ThenChange(sysmsg.h, sysmsg_amd64.go) +// LINT.IfChange + +#define offsetof_thread_context_ptregs_r15 \ + (0x0 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_r14 \ + (0x8 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_r13 \ + (0x10 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_r12 \ + (0x18 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rbp \ + (0x20 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rbx \ + (0x28 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_r11 \ + (0x30 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_r10 \ + (0x38 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_r9 \ + (0x40 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_r8 \ + (0x48 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rax \ + (0x50 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rcx \ + (0x58 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rdx \ + (0x60 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rsi \ + (0x68 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rdi \ + (0x70 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_orig_rax \ + (0x78 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rip \ + (0x80 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_cs \ + (0x88 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_eflags \ + (0x90 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_rsp \ + (0x98 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_ss \ + (0xa0 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_fs_base \ + (0xa8 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_gs_base \ + (0xb0 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_ds \ + (0xb8 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_es \ + (0xc0 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_fs \ + (0xc8 + offsetof_thread_context_ptregs) +#define offsetof_thread_context_ptregs_gs \ + (0xd0 + offsetof_thread_context_ptregs) + +// LINT.ThenChange(sysmsg.h, sighandler_amd64.c) + +#endif // THIRD_PARTY_GVISOR_PKG_SENTRY_PLATFORM_SYSTRAP_SYSMSG_SYSMSG_OFFSETS_AMD64_H_ diff --git a/pkg/sentry/platform/systrap/systrap.go b/pkg/sentry/platform/systrap/systrap.go index 055c07264..c30c363dc 100644 --- a/pkg/sentry/platform/systrap/systrap.go +++ b/pkg/sentry/platform/systrap/systrap.go @@ -74,9 +74,13 @@ var ( stubInitProcess uintptr + // Memory region to store thread specific stacks. stubSysmsgStack uintptr stubSysmsgStart uintptr stubSysmsgEnd uintptr + // Memory region to store instances of sysmsg.ThreadContext. + stubContextRegion uintptr + stubContextRegionLen uintptr // The memory blob with precompiled seccomp rules. stubSysmsgRules uintptr stubSysmsgRulesLen uintptr @@ -218,12 +222,12 @@ restart: if lastFaultSP != faultSP { if lastFaultSP != nil { lastFaultSP.mu.Lock() - delete(lastFaultSP.contexts, c) + delete(lastFaultSP.faultedContexts, c) lastFaultSP.mu.Unlock() } if faultSP != nil { faultSP.mu.Lock() - faultSP.contexts[c] = struct{}{} + faultSP.faultedContexts[c] = struct{}{} faultSP.mu.Unlock() } }