From 9ec69054f84c44f9d90e810524fab8f8987917f4 Mon Sep 17 00:00:00 2001 From: Konstantin Bogomolov Date: Fri, 3 Mar 2023 13:48:57 -0800 Subject: [PATCH] Map shared region for systrap thread contexts. Introduces what a ThreadContext struct is in the context of systrap. It makes the mappings of the region where the contexts will be stored into both the sentry and the address space of stub processes. PiperOrigin-RevId: 513913793 --- pkg/sentry/platform/systrap/stub_unsafe.go | 17 ++-- pkg/sentry/platform/systrap/subprocess.go | 83 ++++++++++++++--- pkg/sentry/platform/systrap/sysmsg/BUILD | 25 +++--- .../systrap/sysmsg/sighandler_amd64.c | 74 ++++++++++++--- pkg/sentry/platform/systrap/sysmsg/sysmsg.go | 90 +++++++++++++++++-- pkg/sentry/platform/systrap/sysmsg/sysmsg.h | 22 +++++ .../platform/systrap/sysmsg/sysmsg_lib.c | 31 +++++++ .../platform/systrap/sysmsg/sysmsg_offsets.h | 15 +++- .../systrap/sysmsg/sysmsg_offsets_amd64.h | 89 ++++++++++++++++++ pkg/sentry/platform/systrap/systrap.go | 8 +- 10 files changed, 402 insertions(+), 52 deletions(-) create mode 100644 pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets_amd64.h 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() } }