Skip to content

Commit

Permalink
x86/shskt: Disable CET-SS on parts susceptible to fractured updates
Browse files Browse the repository at this point in the history
Refer to Intel SDM Rev 70 (Dec 2022), Vol3 17.2.3 "Supervisor Shadow Stack
Token".

Architecturally, an event delivery which starts in CPL<3 and switches shadow
stack will first validate the Supervisor Shadow Stack Token (setting the busy
bit), then pushes CS/LIP/SSP.  One example of this is an NMI interrupting Xen.

Some CPUs suffer from an issue called fracturing, whereby a fault/vmexit/etc
between setting the busy bit and completing the event injection renders the
action non-restartable, because when it comes time to restart, the busy bit is
found to be already set.

This is far more easily encountered under virt, yet it is not the fault of the
hypervisor, nor the fault of the guest kernel.  The fault lies somewhere
between the architectural specification, and the uarch behaviour.

Intel have allocated CPUID.7[1].ecx[18] CET_SSS to enumerate that supervisor
shadow stacks are safe to use.  Because of how Xen lays out its shadow stacks,
fracturing is not expected to be a problem on native.

Detect this case on boot and default to not using shstk if virtualised.
Specifying `cet=shstk` on the command line will override this heuristic and
enable shadow stacks irrespective.

Signed-off-by: Andrew Cooper <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
  • Loading branch information
andyhhp committed Feb 9, 2023
1 parent b4a23bf commit 01e7477
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 11 deletions.
7 changes: 6 additions & 1 deletion docs/misc/xen-command-line.pandoc
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,15 @@ can be maintained with the pv-shim mechanism.
protection.

The option is available when `CONFIG_XEN_SHSTK` is compiled in, and
defaults to `true` on hardware supporting CET-SS. Specifying
generally defaults to `true` on hardware supporting CET-SS. Specifying
`cet=no-shstk` will cause Xen not to use Shadow Stacks even when support
is available in hardware.

Some hardware suffers from an issue known as Supervisor Shadow Stack
Fracturing. On such hardware, Xen will default to not using Shadow Stacks
when virtualised. Specifying `cet=shstk` will override this heuristic and
enable Shadow Stacks unilaterally.

* The `ibt=` boolean controls whether Xen uses Indirect Branch Tracking for
its own protection.

Expand Down
2 changes: 2 additions & 0 deletions tools/libs/light/libxl_cpuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
{"fsrcs", 0x00000007, 1, CPUID_REG_EAX, 12, 1},
{"wrmsrns", 0x00000007, 1, CPUID_REG_EAX, 19, 1},

{"cet-sss", 0x00000007, 1, CPUID_REG_EDX, 18, 1},

{"intel-psfd", 0x00000007, 2, CPUID_REG_EDX, 0, 1},
{"mcdt-no", 0x00000007, 2, CPUID_REG_EDX, 5, 1},

Expand Down
1 change: 1 addition & 0 deletions tools/misc/xen-cpuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ static const char *const str_7c1[32] =

static const char *const str_7d1[32] =
{
[18] = "cet-sss",
};

static const char *const str_7d2[32] =
Expand Down
11 changes: 9 additions & 2 deletions xen/arch/x86/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,18 @@ void __init early_cpu_init(void)
x86_cpuid_vendor_to_str(c->x86_vendor), c->x86, c->x86,
c->x86_model, c->x86_model, c->x86_mask, eax);

if (c->cpuid_level >= 7)
cpuid_count(7, 0, &eax, &ebx,
if (c->cpuid_level >= 7) {
uint32_t max_subleaf;

cpuid_count(7, 0, &max_subleaf, &ebx,
&c->x86_capability[FEATURESET_7c0],
&c->x86_capability[FEATURESET_7d0]);

if (max_subleaf >= 1)
cpuid_count(7, 1, &eax, &ebx, &ecx,
&c->x86_capability[FEATURESET_7d1]);
}

eax = cpuid_eax(0x80000000);
if ((eax >> 16) == 0x8000 && eax >= 0x80000008) {
ebx = eax >= 0x8000001f ? cpuid_ebx(0x8000001f) : 0;
Expand Down
46 changes: 38 additions & 8 deletions xen/arch/x86/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,7 @@ unsigned long __initdata highmem_start;
size_param("highmem-start", highmem_start);
#endif

#ifdef CONFIG_XEN_SHSTK
static bool __initdata opt_xen_shstk = true;
#else
#define opt_xen_shstk false
#endif
static int8_t __initdata opt_xen_shstk = -IS_ENABLED(CONFIG_XEN_SHSTK);

#ifdef CONFIG_XEN_IBT
static bool __initdata opt_xen_ibt = true;
Expand Down Expand Up @@ -1100,11 +1096,45 @@ void __init noreturn __start_xen(unsigned long mbi_p)
early_cpu_init();

/* Choose shadow stack early, to set infrastructure up appropriately. */
if ( opt_xen_shstk && boot_cpu_has(X86_FEATURE_CET_SS) )
if ( !boot_cpu_has(X86_FEATURE_CET_SS) )
opt_xen_shstk = 0;

if ( opt_xen_shstk )
{
printk("Enabling Supervisor Shadow Stacks\n");
/*
* Some CPUs suffer from Shadow Stack Fracturing, an issue whereby a
* fault/VMExit/etc between setting a Supervisor Busy bit and the
* event delivery completing renders the operation non-restartable.
* On restart, event delivery will find the Busy bit already set.
*
* This is a problem on bare metal, but outside of synthetic cases or
* a very badly timed #MC, it's not believed to be a problem. It is a
* much bigger problem under virt, because we can VMExit for a number
* of legitimate reasons and tickle this bug.
*
* CPUs with this addressed enumerate CET-SSS to indicate that
* supervisor shadow stacks are now safe to use.
*/
bool cpu_has_bug_shstk_fracture =
boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
!boot_cpu_has(X86_FEATURE_CET_SSS);

setup_force_cpu_cap(X86_FEATURE_XEN_SHSTK);
/*
* On bare metal, assume that Xen won't be impacted by shstk
* fracturing problems. Under virt, be more conservative and disable
* shstk by default.
*/
if ( opt_xen_shstk == -1 )
opt_xen_shstk =
cpu_has_hypervisor ? !cpu_has_bug_shstk_fracture
: true;

if ( opt_xen_shstk )
{
printk("Enabling Supervisor Shadow Stacks\n");

setup_force_cpu_cap(X86_FEATURE_XEN_SHSTK);
}
}

if ( opt_xen_ibt && boot_cpu_has(X86_FEATURE_CET_IBT) )
Expand Down
1 change: 1 addition & 0 deletions xen/include/public/arch-x86/cpufeatureset.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ XEN_CPUFEATURE(MCDT_NO, 13*32+ 5) /*A MCDT_NO */
/* Intel-defined CPU features, CPUID level 0x00000007:1.ecx, word 14 */

/* Intel-defined CPU features, CPUID level 0x00000007:1.edx, word 15 */
XEN_CPUFEATURE(CET_SSS, 15*32+18) /* CET Supervisor Shadow Stacks safe to use */

#endif /* XEN_CPUFEATURE */

Expand Down

0 comments on commit 01e7477

Please sign in to comment.