From 39f2721c9bf77865189889dc4900da7adf5f379f Mon Sep 17 00:00:00 2001 From: Konstantin Bogomolov Date: Tue, 7 Mar 2023 09:14:01 -0800 Subject: [PATCH] Implement saving decoupled context from syshandler. Rewrite the syshandler assembly routine to save the full state of user threads, like the sighandler would. With fpstate, it does so by writing straight to the thread context struct, so there is no need to do an intermediate copy. PiperOrigin-RevId: 514751894 --- pkg/sentry/platform/systrap/subprocess.go | 11 +- .../platform/systrap/subprocess_amd64.go | 68 ------ .../platform/systrap/subprocess_arm64.go | 13 - .../systrap/sysmsg/sighandler_amd64.c | 68 ++---- .../systrap/sysmsg/syshandler_amd64.S | 228 ++++++++++++++---- pkg/sentry/platform/systrap/sysmsg/sysmsg.go | 12 - pkg/sentry/platform/systrap/sysmsg/sysmsg.h | 2 - .../platform/systrap/sysmsg/sysmsg_amd64.go | 7 +- .../platform/systrap/sysmsg/sysmsg_lib.c | 5 +- .../platform/systrap/sysmsg/sysmsg_offsets.h | 6 +- 10 files changed, 221 insertions(+), 199 deletions(-) diff --git a/pkg/sentry/platform/systrap/subprocess.go b/pkg/sentry/platform/systrap/subprocess.go index c97816e36..9d2e6fcb3 100644 --- a/pkg/sentry/platform/systrap/subprocess.go +++ b/pkg/sentry/platform/systrap/subprocess.go @@ -675,10 +675,7 @@ func (s *subprocess) switchToApp(c *context, ac *arch.Context64) (isSyscall bool if ctx.State == sysmsg.ContextStateSyscallCanBePatched { ctx.State = sysmsg.ContextStateSyscall - // Syshandler not implemented with context decoupling yet. - if !contextDecouplingExp { - shouldPatchSyscall = true - } + shouldPatchSyscall = true } if ctx.State == sysmsg.ContextStateSyscall || ctx.State == sysmsg.ContextStateSyscallTrap { @@ -750,10 +747,6 @@ func (s *subprocess) Unmap(addr hostarch.Addr, length uint64) { } func (s *subprocess) PullFullState(c *context, ac *arch.Context64) error { - if !contextDecouplingExp { - return s.PullFullArchState(c, ac) - } - if s != c.subprocess { panic("Attempted to PullFullState for context that is not used in subprocess") } @@ -857,10 +850,10 @@ func (s *subprocess) getSysmsgThread(tregs *arch.Registers, c *context, ac *arch sysThread.setMsg(sysmsg.StackAddrToMsg(sentryStackAddr)) sysThread.msg.Init() sysThread.msg.Self = uint64(sysmsgStackAddr + sysmsg.MsgOffsetFromSharedStack) - sysThread.msg.Syshandler = uint64(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_syshandler)) sysThread.msg.SyshandlerStack = uint64(sysmsg.StackAddrToSyshandlerStack(sysThread.sysmsgPerThreadMemAddr())) sysThread.msg.ContextRegion = uint64(stubContextRegion) sysThread.msg.ContextID = c.cid + sysThread.msg.Syshandler = uint64(stubSysmsgStart + uintptr(sysmsg.Sighandler_blob_offset____export_syshandler)) sysThread.msg.State.Set(sysmsg.ThreadStateDone) diff --git a/pkg/sentry/platform/systrap/subprocess_amd64.go b/pkg/sentry/platform/systrap/subprocess_amd64.go index 7071d11aa..14b8fb076 100644 --- a/pkg/sentry/platform/systrap/subprocess_amd64.go +++ b/pkg/sentry/platform/systrap/subprocess_amd64.go @@ -211,74 +211,6 @@ func appendArchSeccompRules(rules []seccomp.RuleSet) []seccomp.RuleSet { }...) } -func (s *subprocess) PullFullArchState(c *context, ac *arch.Context64) error { - // Reset necessary registers. - regs := &ac.StateData().Regs - - sysThread, err := s.getSysmsgThread(regs, c, ac) - if err != nil { - return err - } - msg := sysThread.msg - ctx := s.getThreadContextFromID(c.cid) - - // In case of EventTypeSyscallTrap, we have only syscall argument - // registers and we need to trigger a signal in the stub process to get - // a full set of registers and an FPU state. - // - // In other cases, we have the full set of registers and need only copy - // the FPU state from a signal frame. - if ctx.State != sysmsg.ContextStateSyscallTrap { - s.saveFPState(msg, ctx, sysThread.fpuStateToMsgOffset, c, ac) - return nil - } - - // In case of EventTypeSyscallTrap, the Sentry knows only the syscall - // number and syscall arguments and the target thread is stopped in the - // syshandler stub function. We need to ask syshandler to trigger a - // real syscall to get the full state. - ctx.Regs = regs.PtraceRegs - - sysThread.waitEvent(sysmsg.ThreadStateSigact) - - if msg.Err != 0 { - panic(fmt.Sprintf("stub thread failed: err %d line %d: %s", msg.Err, msg.Line, msg)) - } - - if ctx.State != sysmsg.ContextStateSyscall { - panic(fmt.Sprintf("unknown context state: state %v: %s", ctx.State, msg)) - } - - sysThread.fpuStateToMsgOffset, err = msg.FPUStateOffset() - if err != nil { - return err - } - - // When we are triggering the real syscall instruction, we don't - // restore all syscall arguments and even the syscall number. - ctx.Regs.Rax = regs.Rax - ctx.Regs.Orig_rax = regs.Orig_rax - ctx.Regs.Rdi = regs.Rdi - ctx.Regs.Rsi = regs.Rsi - ctx.Regs.Rdx = regs.Rdx - ctx.Regs.R10 = regs.R10 - ctx.Regs.R8 = regs.R8 - ctx.Regs.R9 = regs.R9 - regs.PtraceRegs = ctx.Regs - - // The thread has restored all registers that could be changed in - // the syshandler stub function, but it is still in this function. We - // know the return address and let's set it so to be not affected if - // the stub code will be changed after save/restore. - regs.Rip = msg.RetAddr - - s.saveFPState(msg, ctx, sysThread.fpuStateToMsgOffset, c, ac) - - c.signalInfo = ctx.SignalInfo - - return nil -} - func restoreArchSpecificState(regs *arch.Registers, t *thread, sysThread *sysmsgThread, msg *sysmsg.Msg, _ *arch.Context64) { regs.Gs_base = msg.Self diff --git a/pkg/sentry/platform/systrap/subprocess_arm64.go b/pkg/sentry/platform/systrap/subprocess_arm64.go index 8568732d5..ae6f0bf9f 100644 --- a/pkg/sentry/platform/systrap/subprocess_arm64.go +++ b/pkg/sentry/platform/systrap/subprocess_arm64.go @@ -187,19 +187,6 @@ func (s *subprocess) arm64SyscallWorkaround(t *thread, regs *arch.Registers) { } } -func (s *subprocess) PullFullArchState(c *context, ac *arch.Context64) error { - // We do not support syscall trap in ARM64 so just get the fp state from the - // signal frame and we are done. - regs := &ac.StateData().Regs - sysThread, err := s.getSysmsgThread(regs, c, ac) - if err != nil { - return err - } - ctx := s.getThreadContextFromID(c.cid) - s.saveFPState(sysThread.msg, ctx, sysThread.fpuStateToMsgOffset, c, ac) - return nil -} - func restoreArchSpecificState(regs *arch.Registers, t *thread, _ *sysmsgThread, msg *sysmsg.Msg, ac *arch.Context64) { msg.TLS = uint64(ac.TLS()) } diff --git a/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c b/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c index 87b673049..2b7c0a2ac 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c +++ b/pkg/sentry/platform/systrap/sysmsg/sighandler_amd64.c @@ -177,8 +177,7 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { // because sysmsg can't be changed. int32_t thread_state; thread_state = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); - if ((thread_state != THREAD_STATE_NONE) || - (ucontext->uc_mcontext.gregs[REG_RSP] > (unsigned long)sp)) { + if (thread_state != THREAD_STATE_NONE) { __atomic_store_n(&sysmsg->interrupt, 1, __ATOMIC_RELEASE); return; } @@ -189,6 +188,13 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { __atomic_store_n(&sysmsg->interrupt, 0, __ATOMIC_RELAXED); // Skip the fault instruction. ucontext->uc_mcontext.gregs[REG_RIP] = sysmsg->ret_addr; + // If we're skipping the fault instruction and going straight to the user + // RIP we must also restore RSP and RFLAGS which are the last registers + // restored. We can take these values from ctx->ptregs because the + // syshandler saved them there and hasn't overwritten them before + // retriggering the interrupt. + ucontext->uc_mcontext.gregs[REG_RSP] = ctx->ptregs.rsp; + ucontext->uc_mcontext.gregs[REG_EFL] = ctx->ptregs.eflags; } // Handle faults in syshandler. @@ -220,12 +226,7 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { // If a syscall instruction set is "mov sysno, %eax, syscall", it can be // replaced on a function call which works much faster. // Look at pkg/sentry/usertrap for more details. - // - // Exclude all syscalls which requires a full thread state to be handled. - if (siginfo->si_arch == AUDIT_ARCH_X86_64 && si_sysno != __NR_execveat && - si_sysno != __NR_execve && si_sysno != __NR_fork && - si_sysno != __NR_clone && si_sysno != __NR_vfork && - si_sysno != __NR_rt_sigreturn && si_sysno != __NR_arch_prctl) { + if (siginfo->si_arch == AUDIT_ARCH_X86_64) { uint8_t *rip = (uint8_t *)ctx->ptregs.rip; // FIXME(b/144063246): Even if all five bytes before the syscall // instruction match the "mov sysno, %eax" instruction, they can be a @@ -314,49 +315,32 @@ void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { __atomic_store_n(&sysmsg->state, THREAD_STATE_NONE, __ATOMIC_RELEASE); } -// Function arguments: %rdi,%rsi, %rdx, %rcx, %r8 and %r9. -// http://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf -long __syshandler(long a1, long a2, long a3, long __unused, long a5, long a6) { - long sysno, a4, rip; +void __syshandler() { struct sysmsg *sysmsg; - asm volatile( - "movq %%rax, %0\n" - "movq %%r10, %1\n" - : "=m"(sysno), "=m"(a4) - : - :); asm volatile("movq %%gs:0, %0\n" : "=r"(sysmsg) : :); - struct thread_context *ctx = thread_context_addr(sysmsg); - // SYSMSG_STATE_PREP is set to postpone interrupts. Look at // __export_sighandler for more details. - int thread_state = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); - if (thread_state != THREAD_STATE_PREP) panic(thread_state); - ctx->signo = SIGSYS; - ctx->ptregs.rax = sysno; - ctx->ptregs.rdi = a1; - ctx->ptregs.rsi = a2; - ctx->ptregs.rdx = a3; - ctx->ptregs.r10 = a4; - ctx->ptregs.r8 = a5; - ctx->ptregs.r9 = a6; - ctx->ptregs.rsp = sysmsg->app_stack; - ctx->ptregs.rip = sysmsg->ret_addr; + int state = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); + if (state != THREAD_STATE_PREP) panic(state); + + struct thread_context *ctx = thread_context_addr(sysmsg); + ctx->state = CONTEXT_STATE_SYSCALL_TRAP; - ctx->ptregs.orig_rax = ctx->ptregs.rax; - ctx->ptregs.rax = (unsigned long)-ENOSYS; + ctx->signo = SIGSYS; ctx->siginfo.si_addr = 0; - ctx->siginfo.si_syscall = sysno; + ctx->siginfo.si_syscall = ctx->ptregs.rax; + ctx->ptregs.rax = (unsigned long)-ENOSYS; __atomic_store_n(&sysmsg->interrupt, 0, __ATOMIC_RELAXED); - thread_state = wait_state(sysmsg, THREAD_STATE_EVENT); - long sysret = ctx->ptregs.rax; - if (thread_state == THREAD_STATE_SIGACT) { - return -1; - } + get_fsbase(&ctx->ptregs); + long fs_base = ctx->ptregs.fs_base; - __atomic_store_n(&sysmsg->state, THREAD_STATE_NONE, __ATOMIC_RELEASE); - return sysret; + state = wait_state(sysmsg, THREAD_STATE_EVENT); + + // Restore state + if (fs_base != ctx->ptregs.fs_base) { + set_fsbase(&ctx->ptregs); + } } void verify_offsets_amd64() { diff --git a/pkg/sentry/platform/systrap/sysmsg/syshandler_amd64.S b/pkg/sentry/platform/systrap/sysmsg/syshandler_amd64.S index 0ac39a112..e66b5f908 100644 --- a/pkg/sentry/platform/systrap/sysmsg/syshandler_amd64.S +++ b/pkg/sentry/platform/systrap/sysmsg/syshandler_amd64.S @@ -13,66 +13,208 @@ // limitations under the License. #include "sysmsg_offsets.h" +#include "sysmsg_offsets_amd64.h" +// Helper macros: +//////////////////////////////////////// + +// load_thread_context loads the address of the thread context slot for the current +// context. +// Clobbers %rflags; loads address into %rcx. +.macro load_thread_context_addr + movl %gs:offsetof_sysmsg_context_id, %ecx + shl $THREAD_CONTEXT_STRUCT_BITSHIFT, %rcx + add %gs:offsetof_sysmsg_context_region, %rcx +.endm + +// prepare_enter_syshandler does the following: +// - saves all registers that are restorable onto the thread_context struct. +// - loads the address of the thread_context struct into %rcx. +.macro prepare_enter_syshandler + // Syshandler clobbers rflags (load_thread_context_addr does so for example). + // Therefore save it as the first thing we do. + pushfq + // load_thread_context_addr overwrites %rcx. + push %rcx + + load_thread_context_addr + + // Registers listed in order as written in ptregs: + movq %r15, offsetof_thread_context_ptregs_r15(%rcx) + movq %r14, offsetof_thread_context_ptregs_r14(%rcx) + movq %r13, offsetof_thread_context_ptregs_r13(%rcx) + movq %r12, offsetof_thread_context_ptregs_r12(%rcx) + movq %rbp, offsetof_thread_context_ptregs_rbp(%rcx) + movq %rbx, offsetof_thread_context_ptregs_rbx(%rcx) + movq %r11, offsetof_thread_context_ptregs_r11(%rcx) + movq %r10, offsetof_thread_context_ptregs_r10(%rcx) + movq %r9, offsetof_thread_context_ptregs_r9(%rcx) + movq %r8, offsetof_thread_context_ptregs_r8(%rcx) + movq %rax, offsetof_thread_context_ptregs_rax(%rcx) + pop %r15 + movq %r15, offsetof_thread_context_ptregs_rcx(%rcx) + movq %rdx, offsetof_thread_context_ptregs_rdx(%rcx) + movq %rsi, offsetof_thread_context_ptregs_rsi(%rcx) + movq %rdi, offsetof_thread_context_ptregs_rdi(%rcx) + movq %rax, offsetof_thread_context_ptregs_orig_rax(%rcx) + + movw %cs, offsetof_thread_context_ptregs_cs(%rcx) + movw %ss, offsetof_thread_context_ptregs_ss(%rcx) + // Don't bother save/restoring ds/es on amd64 + // movw %ds, offsetof_thread_context_ptregs_ds(%rcx) + // movw %es, offsetof_thread_context_ptregs_es(%rcx) + movw %fs, offsetof_thread_context_ptregs_fs(%rcx) + movw %gs, offsetof_thread_context_ptregs_gs(%rcx) + + pop %rax + movq %rax, offsetof_thread_context_ptregs_eflags(%rcx) + + movq %gs:offsetof_sysmsg_app_stack, %r8 + movq %r8, offsetof_thread_context_ptregs_rsp(%rcx) + movq %gs:offsetof_sysmsg_ret_addr, %r9 + movq %r9, offsetof_thread_context_ptregs_rip(%rcx) +.endm + +// prepare_exit_syshandler assumes that: +// - the memory address of the thread_context is loaded in %rcx. +// prepare_exit_syshandler does the following: +// - sets sysmsg->ret_addr +// - restores all registers that were saved inside the thread_context struct except for +// %rsp and rflags. +// - %rcx will be restored as well, and will no longer contain the memory address to the +// thread context. +// - puts user %rsp and rflags onto the syshandler stack (in that order). rflags cannot +// be restored at this point because syshandler will clobber it before it exits. +.macro prepare_exit_syshandler + movq offsetof_thread_context_ptregs_rsp(%rcx), %rax + push %rax + movq offsetof_thread_context_ptregs_eflags(%rcx), %rbx + push %rbx + + // set sysmsg->ret_addr + movq offsetof_thread_context_ptregs_rip(%rcx), %r9 + movq %r9, %gs:offsetof_sysmsg_ret_addr + + // Restore segments. Because restoring segments is slow, restore them only if necessary. + movw %fs, %dx + cmpw %dx, offsetof_thread_context_ptregs_fs(%rcx) + je restored_fs + movw offsetof_thread_context_ptregs_fs(%rcx), %fs +restored_fs: + movw %gs, %si + cmpw %si, offsetof_thread_context_ptregs_gs(%rcx) + je restored_gs + movw offsetof_thread_context_ptregs_gs(%rcx), %gs +restored_gs: + // Restore other GP registers + movq offsetof_thread_context_ptregs_r15(%rcx), %r15 + movq offsetof_thread_context_ptregs_r14(%rcx), %r14 + movq offsetof_thread_context_ptregs_r13(%rcx), %r13 + movq offsetof_thread_context_ptregs_r12(%rcx), %r12 + movq offsetof_thread_context_ptregs_rbp(%rcx), %rbp + movq offsetof_thread_context_ptregs_rbx(%rcx), %rbx + movq offsetof_thread_context_ptregs_r11(%rcx), %r11 + movq offsetof_thread_context_ptregs_r10(%rcx), %r10 + movq offsetof_thread_context_ptregs_r9(%rcx), %r9 + movq offsetof_thread_context_ptregs_r8(%rcx), %r8 + movq offsetof_thread_context_ptregs_rax(%rcx), %rax + // %rcx restored last + movq offsetof_thread_context_ptregs_rdx(%rcx), %rdx + movq offsetof_thread_context_ptregs_rsi(%rcx), %rsi + movq offsetof_thread_context_ptregs_rdi(%rcx), %rdi + + movq offsetof_thread_context_ptregs_rcx(%rcx), %rcx +.endm + +// save_fpstate saves the current fpstate onto thread_context.fpstate. +// It assumes that: +// - the memory address of the thread_context is loaded in %rcx. +.macro save_fpstate + lea offsetof_thread_context_fpstate(%rcx), %rdi + movl $0xffffffff, %eax + movl $0xffffffff, %edx + movl __export_arch_state+offsetof_arch_state_xsave_mode(%rip), %esi + // TODO(b/268366549): Fix use of xsavec/xsaveopt. + // cmpl $XSAVE_MODE_XSAVEC, %esi + // jl use_xsaveopt + // xsavec (%rdi) + // jmp fpu_saved + // use_xsaveopt: + // cmpl $XSAVE_MODE_XSAVEOPT, %esi + // jl use_xsave + // xsaveopt (%rdi) + // jmp fpu_saved + // use_xsave: + cmpl $XSAVE_MODE_XSAVE, %esi + jl use_fxsave + xsave (%rdi) + jmp fpu_saved +use_fxsave: + fxsave (%rdi) +fpu_saved: +.endm + +// restore_fpstate restores the fpstate previously saved onto thread_context.fpstate. +// It assumes that: +// - the memory address of the thread_context is loaded in %rcx. +.macro restore_fpstate + // We only need to restore fpstate if we were signalled that it changed (syshandler + // does not modify fpstate). + cmpl $0, offsetof_thread_context_fpstate_changed(%rcx) + je fpu_restored + + lea offsetof_thread_context_fpstate(%rcx), %rdi + mov __export_arch_state+offsetof_arch_state_xsave_mode(%rip), %eax + cmpl $XSAVE_MODE_FXSAVE, %eax + jz use_fxrstor +use_xrstor: + movl $0xffffffff, %eax + movl $0xffffffff, %edx + xrstor (%rdi) + jmp fpu_restored +use_fxrstor: + fxrstor (%rdi) +fpu_restored: +.endm + +// Syshandler: +//////////////////////////////////////// .globl __export_syshandler; .type __export_syshandler, @function; .align 4, 0x00; __export_syshandler: // The start of this function is in a usertrap trampoline: - // mov %rsp,%gs:0x20 - // mov %gs:0x18,%rs + // mov sysmsg.ThreadStatePrep, %gs:offset(msg.State) + // mov %rsp,%gs:0x20 // msg.AppStack + // mov %gs:0x18,%rsp // msg.SyshandlerStack // movabs $ret_addr, %rax - // mov %rax, %fs:0x8 - // mov sysno, %eax - // jmpq *%gs,0x10 + // mov %rax,%gs:0x8 // msg.RetAddr + // mov sysno,%eax + // jmpq *%gs:0x10 // msg.Syshandler + prepare_enter_syshandler + save_fpstate - // Save registers which are not preserved across function calls. - // http://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf - push %rbp - push %r11 - push %r10 - push %r9 - push %r8 - push %rdi - push %rsi - push %rdx - push %rcx - - // We have to avoid races with sighandler, so if sysmsg isn't equal to - // SYSMSG_STATE_NONE, we can't fault on a user stack. - // - // We can fault on a user stack, what a page isn't mapped yet or when a - // process is dieing and a process address spaces has been cleaned up (see - // subprocess.Release). callq __syshandler - // Restore registers and return back to a guest code. - pop %rcx - pop %rdx - pop %rsi - pop %rdi - pop %r8 - pop %r9 - pop %r10 - pop %r11 - pop %rbp + // thread_context may have changed, therefore we reload it into %rcx anew. + load_thread_context_addr + restore_fpstate - movq %gs:offsetof_sysmsg_app_stack,%rsp + prepare_exit_syshandler - cmpl $kTHREAD_STATE_SIGACT, %gs:offsetof_sysmsg_state // msg->state - jne skipsyscall - mov $0xffff, %eax // any syscall which isn't allowed by seccomp. - // nop is here to avoid matching the `mov sysno, %eax; syscall` pattern that - // we are substituting with function calls. - nop - syscall - jmp skipint -skipsyscall: + // Indicate syshandler is done. + movl $kTHREAD_STATE_NONE, %gs:offsetof_sysmsg_state + + // Check if syshandler received an interrupt while executing. + // If it did, retrigger the interrupt. See __export_sighandler for details. cmpl $0, %gs:offsetof_sysmsg_interrupt // msg->interrupt je skipint movl $kTHREAD_STATE_INTERRUPT, %gs:offsetof_sysmsg_state .byte FAULT_OPCODE // Re-trigger the interrupt. skipint: + // Now syshandler is exiting for good; restore user rflags and %rsp. + popfq + movq 0(%rsp), %rsp jmp *%gs:offsetof_sysmsg_ret_addr // msg->ret_addr .size __export_syshandler, . - __export_syshandler diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg.go b/pkg/sentry/platform/systrap/sysmsg/sysmsg.go index 2a81974d4..0bab82026 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg.go +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg.go @@ -108,10 +108,6 @@ const ( ThreadStateEvent // ThreadStatePrep means that syshandler started filling the sysmsg struct. ThreadStatePrep - // ThreadStateSigact means that the sentry requests the full state of the stub - // thread. - // TODO(b/268366549): Remove this when syshandler saves full state to context. - ThreadStateSigact // ThreadStateInterrupt is a Sysmsg state that indicates to the sighandler // that there is a postponed interrupt from the syshandler. // The sentry should never see this event. @@ -264,14 +260,6 @@ type ThreadContext struct { State ContextState // Interrupt is set to indicate that this context has been interrupted. Interrupt uint32 - // Decoupled is set to indicate that this context is not tied to the sysmsg - // thread used to to execute this context. This value is only changed from - // the sentry if contextDecouplingExp is on. - // It changes the behaviour of the sysmsg threads in the following ways: - // - sighandler will save fpstate to ThreadContext.FPState instead of on the - // sighandler stack. - // - syshandler will not save fpstate at all. - Decoupled uint32 // Debug is a variable to use to get visibility into the stub from the sentry. Debug uint64 } diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg.h b/pkg/sentry/platform/systrap/sysmsg/sysmsg.h index 3b2a8a3b4..465f43ac1 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg.h +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg.h @@ -42,7 +42,6 @@ enum { THREAD_STATE_DONE, THREAD_STATE_EVENT, THREAD_STATE_PREP, - THREAD_STATE_SIGACT, THREAD_STATE_INTERRUPT, }; @@ -95,7 +94,6 @@ struct thread_context { int64_t signo; uint32_t state; uint32_t interrupt; - uint32_t decoupled; uint64_t debug; }; diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_amd64.go b/pkg/sentry/platform/systrap/sysmsg/sysmsg_amd64.go index f4165b5e3..03a604953 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg_amd64.go +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_amd64.go @@ -51,11 +51,8 @@ func (s *ArchState) Init() { fpLenUint, _ := fs.ExtendedStateSize() s.fpLen = uint32(fpLenUint) - if fs.UseXsavec() { - s.xsaveMode = xsavec - } else if fs.UseXsaveopt() { - s.xsaveMode = xsaveopt - } else if fs.UseXsave() { + // TODO(b/268366549): Fix use of xsavec/xsaveopt. + if fs.UseXsave() { s.xsaveMode = xsave } else { s.xsaveMode = fxsave diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c b/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c index 3622d69d4..358f3856f 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_lib.c @@ -90,13 +90,13 @@ int wait_state(struct sysmsg *sysmsg, uint32_t state) { } v = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); - if (v == THREAD_STATE_DONE || v == THREAD_STATE_SIGACT) goto out; + if (v == THREAD_STATE_DONE) goto out; handshake_timeout = __export_handshake_timeout; start = rdtsc(); while (1) { v = __atomic_load_n(&sysmsg->state, __ATOMIC_ACQUIRE); - if (v == THREAD_STATE_DONE || v == THREAD_STATE_SIGACT) goto out; + if (v == THREAD_STATE_DONE) goto out; // The Sentry can change stub_fast_path to zero if it finds out that the // user task has to sleep. @@ -154,7 +154,6 @@ void verify_offsets() { offsetof(struct thread_context, ptregs)); BUILD_BUG_ON(kTHREAD_STATE_NONE != THREAD_STATE_NONE); - BUILD_BUG_ON(kTHREAD_STATE_SIGACT != THREAD_STATE_SIGACT); BUILD_BUG_ON(kTHREAD_STATE_INTERRUPT != THREAD_STATE_INTERRUPT); BUILD_BUG_ON(sizeof(struct thread_context) > diff --git a/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h index b93cfd0b1..0c0ec5514 100644 --- a/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h +++ b/pkg/sentry/platform/systrap/sysmsg/sysmsg_offsets.h @@ -22,7 +22,10 @@ // LINT.IfChange #define MAX_FPSTATE_LEN 3648 +// Note: To be explicit, 2^12 = 4096; if ALLOCATED_SIZEOF_THREAD_CONTEXT_STRUCT +// is changed, make sure to change the code that relies on the bitshift. #define ALLOCATED_SIZEOF_THREAD_CONTEXT_STRUCT 4096 +#define THREAD_CONTEXT_STRUCT_BITSHIFT 12 // LINT.ThenChange(sysmsg.go) // LINT.IfChange @@ -44,8 +47,7 @@ #define offsetof_thread_context_ptregs 0x8 + MAX_FPSTATE_LEN #define kTHREAD_STATE_NONE 0 -#define kTHREAD_STATE_SIGACT 4 -#define kTHREAD_STATE_INTERRUPT 5 +#define kTHREAD_STATE_INTERRUPT 4 // LINT.ThenChange(sysmsg.h, sysmsg_lib.c)