mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
x86/extable: Adjust extable handling to be shadow stack compatible
When adjusting an IRET frame to recover from a fault, and equivalent adjustment needs making in the shadow IRET frame. The adjustment in exception_with_ints_disabled() could in principle be an alternative block rather than an ifdef, as the only two current users of _PRE_EXTABLE() are IRET-to-guest instructions. However, this is not a fastpath, and this form is more robust to future changes. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
1 parent
4648cba0a6
commit
209fb9919b
2 files changed
+75
-2
No files matched your search
+65
-1
@@ -363,7 +363,7 @@ static void show_guest_stack(struct vcpu *v, const struct cpu_user_regs *regs)
|
||||
}
|
||||
|
||||
/*
|
||||
* Notes for get_stack_trace_bottom() and get_stack_dump_bottom()
|
||||
* Notes for get_{stack,shstk}*_bottom() helpers
|
||||
*
|
||||
* Stack pages 1 - 4:
|
||||
* These are all 1-page IST stacks. Each of these stacks have an exception
|
||||
@@ -400,6 +400,18 @@ unsigned long get_stack_trace_bottom(unsigned long sp)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long get_shstk_bottom(unsigned long sp)
|
||||
{
|
||||
switch ( get_stack_page(sp) )
|
||||
{
|
||||
#ifdef CONFIG_XEN_SHSTK
|
||||
case 0: return ROUNDUP(sp, IST_SHSTK_SIZE) - sizeof(unsigned long);
|
||||
case 5: return ROUNDUP(sp, PAGE_SIZE) - sizeof(unsigned long);
|
||||
#endif
|
||||
default: return sp - sizeof(unsigned long);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long get_stack_dump_bottom(unsigned long sp)
|
||||
{
|
||||
switch ( get_stack_page(sp) )
|
||||
@@ -763,6 +775,55 @@ static void do_reserved_trap(struct cpu_user_regs *regs)
|
||||
trapnr, vec_name(trapnr), regs->error_code);
|
||||
}
|
||||
|
||||
static void extable_shstk_fixup(struct cpu_user_regs *regs, unsigned long fixup)
|
||||
{
|
||||
unsigned long ssp, *ptr, *base;
|
||||
|
||||
asm ( "rdsspq %0" : "=r" (ssp) : "0" (1) );
|
||||
if ( ssp == 1 )
|
||||
return;
|
||||
|
||||
ptr = _p(ssp);
|
||||
base = _p(get_shstk_bottom(ssp));
|
||||
|
||||
for ( ; ptr < base; ++ptr )
|
||||
{
|
||||
/*
|
||||
* Search for %rip. The shstk currently looks like this:
|
||||
*
|
||||
* ... [Likely pointed to by SSP]
|
||||
* %cs [== regs->cs]
|
||||
* %rip [== regs->rip]
|
||||
* SSP [Likely points to 3 slots higher, above %cs]
|
||||
* ... [call tree to this function, likely 2/3 slots]
|
||||
*
|
||||
* and we want to overwrite %rip with fixup. There are two
|
||||
* complications:
|
||||
* 1) We cant depend on SSP values, because they won't differ by 3
|
||||
* slots if the exception is taken on an IST stack.
|
||||
* 2) There are synthetic (unrealistic but not impossible) scenarios
|
||||
* where %rip can end up in the call tree to this function, so we
|
||||
* can't check against regs->rip alone.
|
||||
*
|
||||
* Check for both regs->rip and regs->cs matching.
|
||||
*/
|
||||
if ( ptr[0] == regs->rip && ptr[1] == regs->cs )
|
||||
{
|
||||
asm ( "wrssq %[fix], %[stk]"
|
||||
: [stk] "=m" (ptr[0])
|
||||
: [fix] "r" (fixup) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We failed to locate and fix up the shadow IRET frame. This could be
|
||||
* due to shadow stack corruption, or bad logic above. We cannot continue
|
||||
* executing the interrupted context.
|
||||
*/
|
||||
BUG();
|
||||
}
|
||||
|
||||
static bool extable_fixup(struct cpu_user_regs *regs, bool print)
|
||||
{
|
||||
unsigned long fixup = search_exception_table(regs);
|
||||
@@ -779,6 +840,9 @@ static bool extable_fixup(struct cpu_user_regs *regs, bool print)
|
||||
vec_name(regs->entry_vector), regs->error_code,
|
||||
_p(regs->rip), _p(regs->rip), _p(fixup));
|
||||
|
||||
if ( IS_ENABLED(CONFIG_XEN_SHSTK) )
|
||||
extable_shstk_fixup(regs, fixup);
|
||||
|
||||
regs->rip = fixup;
|
||||
this_cpu(last_extable_addr) = regs->rip;
|
||||
|
||||
|
||||
@@ -708,7 +708,16 @@ exception_with_ints_disabled:
|
||||
call search_pre_exception_table
|
||||
testq %rax,%rax # no fixup code for faulting EIP?
|
||||
jz 1b
|
||||
movq %rax,UREGS_rip(%rsp)
|
||||
movq %rax,UREGS_rip(%rsp) # fixup regular stack
|
||||
|
||||
#ifdef CONFIG_XEN_SHSTK
|
||||
mov $1, %edi
|
||||
rdsspq %rdi
|
||||
cmp $1, %edi
|
||||
je .L_exn_shstk_done
|
||||
wrssq %rax, 1*8(%rdi) # fixup shadow stack
|
||||
.L_exn_shstk_done:
|
||||
#endif
|
||||
subq $8,UREGS_rsp(%rsp) # add ec/ev to previous stack frame
|
||||
testb $15,UREGS_rsp(%rsp) # return %rsp is now aligned?
|
||||
jz 1f # then there is a pad quadword already
|
||||
|
||||