@@ -434,18 +434,6 @@ unsigned long get_stack_trace_bottom(uns
}
}
-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) )
@@ -837,24 +825,26 @@ static void fixup_exception_return(struc
{
if ( IS_ENABLED(CONFIG_XEN_SHSTK) )
{
- unsigned long ssp, *ptr, *base;
+ unsigned long ssp = rdssp();
- if ( (ssp = rdssp()) == SSP_NO_SHSTK )
- goto shstk_done;
+ if ( ssp != SSP_NO_SHSTK )
+ {
+ unsigned long *ptr = _p(regs->entry_ssp);
+ unsigned long primary_shstk =
+ (ssp & ~(STACK_SIZE - 1)) +
+ (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8;
- ptr = _p(ssp);
- base = _p(get_shstk_bottom(ssp));
+ BUG_ON((regs->entry_ssp ^ primary_shstk) >> PAGE_SHIFT);
- for ( ; ptr < base; ++ptr )
- {
/*
- * Search for %rip. The shstk currently looks like this:
+ * The shstk currently looks like this:
*
* tok [Supervisor token, == &tok | BUSY, only with FRED inactive]
* ... [Pointed to by SSP for most exceptions, empty in IST cases]
* %cs [== regs->cs]
* %rip [== regs->rip]
- * SSP [Likely points to 3 slots higher, above %cs]
+ * SSP [Pointed to by entry_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
@@ -867,13 +857,10 @@ static void fixup_exception_return(struc
*
* Check for both regs->rip and regs->cs matching.
*/
- if ( ptr[0] == regs->rip && ptr[1] == regs->cs )
- {
- unsigned long primary_shstk =
- (ssp & ~(STACK_SIZE - 1)) +
- (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8;
+ BUG_ON(ptr[1] != regs->rip || ptr[2] != regs->cs);
- wrss(fixup, ptr);
+ {
+ wrss(fixup, &ptr[1]);
if ( !stub_ra )
goto shstk_done;
@@ -890,7 +877,7 @@ static void fixup_exception_return(struc
* - if we're on an IST stack, we need to increment the
* original SSP.
*/
- BUG_ON((ptr[-1] ^ primary_shstk) >> PAGE_SHIFT);
+ BUG_ON((ptr[0] ^ primary_shstk) >> PAGE_SHIFT);
if ( (ssp ^ primary_shstk) >> PAGE_SHIFT )
{
@@ -899,37 +886,27 @@ static void fixup_exception_return(struc
* addresses actually match. Then increment the interrupted
* context's SSP.
*/
- BUG_ON(stub_ra != *(unsigned long*)ptr[-1]);
- wrss(ptr[-1] + 8, &ptr[-1]);
+ BUG_ON(stub_ra != *(unsigned long*)ptr[0]);
+ wrss(ptr[0] + 8, &ptr[0]);
goto shstk_done;
}
/* Make sure the two return addresses actually match. */
- BUG_ON(stub_ra != ptr[2]);
+ BUG_ON(stub_ra != ptr[3]);
/* Move exception frame, updating SSP there. */
- wrss(ptr[1], &ptr[2]); /* %cs */
- wrss(ptr[0], &ptr[1]); /* %rip */
- wrss(ptr[-1] + 8, &ptr[0]); /* SSP */
+ wrss(ptr[2], &ptr[3]); /* %cs */
+ wrss(ptr[1], &ptr[2]); /* %rip */
+ wrss(ptr[0] + 8, &ptr[1]); /* SSP */
/* Move all newer entries. */
- while ( --ptr != _p(ssp) )
- wrss(ptr[-1], &ptr[0]);
+ while ( ptr-- != _p(ssp) )
+ wrss(ptr[0], &ptr[1]);
/* Finally account for our own stack having shifted up. */
asm volatile ( "incsspd %0" :: "r" (2) );
-
- goto shstk_done;
}
}
-
- /*
- * 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();
-
}
shstk_done:
With the value recorded on entry there's no need anymore to go hunt for the respective exception frame on the shadow stack. By deriving "ptr" from that field (without any offset), it then ends up pointin one slot lower than before. Therefore all array indexes need incrementing, nicely doing away with all the negative ones. Signed-off-by: Jan Beulich <jbeulich@suse.com> --- Indentation of the prior inner (but not innermost) if()'s body is deliberately left untouched, to aid review. It'll be adjusted in a separate follow-on patch.