[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 2/4] x86: record SSP at non-guest entry points
We will want to use that value for call trace generation, and likely also to eliminate the somewhat fragile shadow stack searching done in fixup_exception_return(). For those purposes, guest-only entry points do not need to record that value. To keep the saving code simple, record our own SSP that corresponds to an exception frame, pointing to the top of the shadow stack counterpart of what the CPU has saved on the regular stack. Consuming code can then work its way from there. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> --- To record the full 64-bit value, some of the unused bits in the %cs slot could be used. Sadly that slot has saved_upcall_mask in an unhelpful location, otherwise simply storing low and high 32 bits in those two separate half-slots would be a pretty obvious choice. As long as "entry_ssp" is used in non-guest-entry frames only, we could of course put half of it into a union with saved_upcall_mask ... Else may want to put a BUILD_BUG_ON(VADDR_BITS > 48) somewhere, but I'm afraid I can't really identify a good place for such to live. Leveraging that the CPU stores zero in the upper bits of the selector register slots, the save sequence could also be shl $16, %rcx or %rcx, UREGS_entry_ssp-2(%rsp) That's shorter and avoids a 16-bit operation, but may be less desirable, for being a read-modify-write access. --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -1354,6 +1354,7 @@ void arch_get_info_guest(struct vcpu *v, if ( !compat ) { memcpy(&c.nat->user_regs, &v->arch.user_regs, sizeof(c.nat->user_regs)); + c.nat->user_regs.entry_ssp = 0; if ( is_pv_domain(d) ) memcpy(c.nat->trap_ctxt, v->arch.pv.trap_ctxt, sizeof(c.nat->trap_ctxt)); --- a/xen/arch/x86/hvm/svm/entry.S +++ b/xen/arch/x86/hvm/svm/entry.S @@ -94,7 +94,7 @@ __UNLIKELY_END(nsvm_hap) sti vmrun - SAVE_ALL + SAVE_ALL ssp=0 GET_CURRENT(bx) --- a/xen/arch/x86/hvm/vmx/entry.S +++ b/xen/arch/x86/hvm/vmx/entry.S @@ -25,7 +25,7 @@ #define VMLAUNCH .byte 0x0f,0x01,0xc2 ENTRY(vmx_asm_vmexit_handler) - SAVE_ALL + SAVE_ALL ssp=0 mov %cr2,%rax GET_CURRENT(bx) @@ -119,7 +119,7 @@ UNLIKELY_END(realmode) .Lvmx_vmentry_fail: sti - SAVE_ALL + SAVE_ALL ssp=0 /* * SPEC_CTRL_ENTRY notes --- a/xen/arch/x86/include/asm/asm_defns.h +++ b/xen/arch/x86/include/asm/asm_defns.h @@ -221,7 +221,7 @@ static always_inline void stac(void) #endif #ifdef __ASSEMBLY__ -.macro SAVE_ALL compat=0 +.macro SAVE_ALL compat=0 ssp=IS_ENABLED(CONFIG_XEN_SHSTK) addq $-(UREGS_error_code-UREGS_r15), %rsp cld movq %rdi,UREGS_rdi(%rsp) @@ -235,6 +235,9 @@ static always_inline void stac(void) movq %rax,UREGS_rax(%rsp) xor %eax, %eax .if !\compat +.if \ssp + rdsspq %rcx +.endif movq %r8,UREGS_r8(%rsp) movq %r9,UREGS_r9(%rsp) movq %r10,UREGS_r10(%rsp) @@ -264,6 +267,11 @@ static always_inline void stac(void) xor %r13d, %r13d xor %r14d, %r14d xor %r15d, %r15d +.if \ssp && !\compat + mov %cx, UREGS_entry_ssp(%rsp) + shr $16, %rcx + mov %ecx, UREGS_entry_ssp+2(%rsp) +.endif .endm #define LOAD_ONE_REG(reg, compat) \ --- a/xen/arch/x86/x86_64/asm-offsets.c +++ b/xen/arch/x86/x86_64/asm-offsets.c @@ -48,6 +48,7 @@ void __dummy__(void) OFFSET(UREGS_eflags, struct cpu_user_regs, rflags); OFFSET(UREGS_rsp, struct cpu_user_regs, rsp); OFFSET(UREGS_ss, struct cpu_user_regs, ss); + OFFSET(UREGS_entry_ssp, struct cpu_user_regs, entry_ssp); OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, es); BLANK(); --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -257,7 +257,7 @@ FUNC(lstar_enter) pushq $0 BUILD_BUG_ON(TRAP_syscall & 0xff) movb $TRAP_syscall >> 8, EFRAME_entry_vector + 1(%rsp) - SAVE_ALL + SAVE_ALL ssp=0 SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ @@ -296,7 +296,7 @@ FUNC(cstar_enter) pushq $0 BUILD_BUG_ON(TRAP_syscall & 0xff) movb $TRAP_syscall >> 8, EFRAME_entry_vector + 1(%rsp) - SAVE_ALL + SAVE_ALL ssp=0 SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ @@ -339,7 +339,7 @@ LABEL(sysenter_eflags_saved, 0) pushq $0 BUILD_BUG_ON(TRAP_syscall & 0xff) movb $TRAP_syscall >> 8, EFRAME_entry_vector + 1(%rsp) - SAVE_ALL + SAVE_ALL ssp=0 SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ @@ -394,7 +394,7 @@ FUNC(entry_int80) ALTERNATIVE "", clac, X86_FEATURE_XEN_SMAP pushq $0 movb $0x80, EFRAME_entry_vector(%rsp) - SAVE_ALL + SAVE_ALL ssp=0 SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */ /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ --- a/xen/include/public/arch-x86/xen-x86_64.h +++ b/xen/include/public/arch-x86/xen-x86_64.h @@ -183,7 +183,19 @@ struct cpu_user_regs { uint8_t _pad1[3]; __DECL_REG_LO16(flags); /* rflags.IF == !saved_upcall_mask */ __DECL_REG_LO8(sp); - uint16_t ss, _pad2[3]; + uint16_t ss; +#if !defined(__XEN__) + uint16_t _pad2[3]; +#elif defined(COMPILE_OFFSETS) + uint16_t entry_ssp[3]; +#else + /* + * This points _at_ the corresponding shadow stack frame; it is _not_ the + * outer context's SSP. That, if the outer context has CET-SS enabled, + * is stored in the top slot of the pointed to shadow stack frame. + */ + signed long entry_ssp:48; +#endif uint16_t es, _pad3[3]; uint16_t ds, _pad4[3]; uint16_t fs, _pad5[3];
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |