x86/shstk: Create shadow stacks

Introduce HYPERVISOR_SHSTK pagetable constants, which are Read-Only + Dirty.
Use these in place of _PAGE_RW for memguard_guard_stack(), to create real
shadow stacks on capable hardware.

Supervisor shadow stacks need a token written at the top, which is most easily
done before making the frame read only.

Allocate the shadow IST stack block in struct tss_page.  It doesn't strictly
need to live here, but it is a convenient location (and XPTI-safe, for testing
purposes), and placing it ahead of the TSS doesn't risk colliding with a bad
IO Bitmap offset and turning into some IO port permissions.

Have load_system_tables() set up the shadow IST stack table when setting up
the regular IST in the TSS.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Andrew Cooper committed 2020-05-29 23:09:46 +01:00
1 parent 6001660473
commit 91d26ed304
6 files changed
+52 -3

No files matched your search

+23
View File
@@ -769,6 +769,29 @@ void load_system_tables(void)
tss->rsp1 = 0x8600111111111111ul;
tss->rsp2 = 0x8600111111111111ul;
/*
* Set up the shadow stack IST. Used entries must point at the
* supervisor stack token. Unused entries are poisoned.
*
* This IST Table may be live, and the NMI/#MC entries must
* remain valid on every instruction boundary, hence the
* volatile qualifier.
*/
if (cpu_has_xen_shstk) {
volatile uint64_t *ist_ssp = this_cpu(tss_page).ist_ssp;
ist_ssp[0] = 0x8600111111111111ul;
ist_ssp[IST_MCE] = stack_top + (IST_MCE * IST_SHSTK_SIZE) - 8;
ist_ssp[IST_NMI] = stack_top + (IST_NMI * IST_SHSTK_SIZE) - 8;
ist_ssp[IST_DB] = stack_top + (IST_DB * IST_SHSTK_SIZE) - 8;
ist_ssp[IST_DF] = stack_top + (IST_DF * IST_SHSTK_SIZE) - 8;
for ( i = IST_DF + 1;
i < ARRAY_SIZE(this_cpu(tss_page).ist_ssp); ++i )
ist_ssp[i] = 0x8600111111111111ul;
wrmsrl(MSR_INTERRUPT_SSP_TABLE, (unsigned long)ist_ssp);
}
BUILD_BUG_ON(sizeof(*tss) <= 0x67); /* Mandated by the architecture. */
_set_tssldt_desc(gdt + TSS_ENTRY, (unsigned long)tss,
+23 -2
View File
@@ -5995,12 +5995,33 @@ void memguard_unguard_range(void *p, unsigned long l)
#endif
static void write_sss_token(unsigned long *ptr)
{
/*
* A supervisor shadow stack token is its own linear address, with the
* busy bit (0) clear.
*/
*ptr = (unsigned long)ptr;
}
void memguard_guard_stack(void *p)
{
map_pages_to_xen((unsigned long)p, virt_to_mfn(p), 1, _PAGE_NONE);
/* IST Shadow stacks. 4x 1k in stack page 0. */
if ( IS_ENABLED(CONFIG_XEN_SHSTK) )
{
write_sss_token(p + (IST_MCE * IST_SHSTK_SIZE) - 8);
write_sss_token(p + (IST_NMI * IST_SHSTK_SIZE) - 8);
write_sss_token(p + (IST_DB * IST_SHSTK_SIZE) - 8);
write_sss_token(p + (IST_DF * IST_SHSTK_SIZE) - 8);
}
map_pages_to_xen((unsigned long)p, virt_to_mfn(p), 1, PAGE_HYPERVISOR_SHSTK);
/* Primary Shadow Stack. 1x 4k in stack page 5. */
p += PRIMARY_SHSTK_SLOT * PAGE_SIZE;
map_pages_to_xen((unsigned long)p, virt_to_mfn(p), 1, _PAGE_NONE);
if ( IS_ENABLED(CONFIG_XEN_SHSTK) )
write_sss_token(p + PAGE_SIZE - 8);
map_pages_to_xen((unsigned long)p, virt_to_mfn(p), 1, PAGE_HYPERVISOR_SHSTK);
}
void memguard_unguard_stack(void *p)
+2
View File
@@ -66,6 +66,8 @@
#define STACK_ORDER 3
#define STACK_SIZE (PAGE_SIZE << STACK_ORDER)
#define IST_SHSTK_SIZE 1024
#define TRAMPOLINE_STACK_SPACE PAGE_SIZE
#define TRAMPOLINE_SPACE (KB(64) - TRAMPOLINE_STACK_SPACE)
#define WAKEUP_STACK_MIN 3072
+1
View File
@@ -364,6 +364,7 @@ void efi_update_l4_pgtable(unsigned int l4idx, l4_pgentry_t);
_PAGE_DIRTY | _PAGE_RW)
#define __PAGE_HYPERVISOR_UCMINUS (__PAGE_HYPERVISOR | _PAGE_PCD)
#define __PAGE_HYPERVISOR_UC (__PAGE_HYPERVISOR | _PAGE_PCD | _PAGE_PWT)
#define __PAGE_HYPERVISOR_SHSTK (__PAGE_HYPERVISOR_RO | _PAGE_DIRTY)
#define MAP_SMALL_PAGES _PAGE_AVAIL0 /* don't use superpages mappings */
+2 -1
View File
@@ -440,7 +440,8 @@ struct __packed tss64 {
uint16_t :16, bitmap;
};
struct tss_page {
struct tss64 __aligned(PAGE_SIZE) tss;
uint64_t __aligned(PAGE_SIZE) ist_ssp[8];
struct tss64 tss;
};
DECLARE_PER_CPU(struct tss_page, tss_page);
+1
View File
@@ -171,6 +171,7 @@ static inline intpte_t put_pte_flags(unsigned int x)
#define PAGE_HYPERVISOR_RW (__PAGE_HYPERVISOR_RW | _PAGE_GLOBAL)
#define PAGE_HYPERVISOR_RX (__PAGE_HYPERVISOR_RX | _PAGE_GLOBAL)
#define PAGE_HYPERVISOR_RWX (__PAGE_HYPERVISOR | _PAGE_GLOBAL)
#define PAGE_HYPERVISOR_SHSTK (__PAGE_HYPERVISOR_SHSTK | _PAGE_GLOBAL)
#define PAGE_HYPERVISOR PAGE_HYPERVISOR_RW
#define PAGE_HYPERVISOR_UCMINUS (__PAGE_HYPERVISOR_UCMINUS | \
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.