diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 451d213c8c..5e427a1cf8 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -918,7 +918,7 @@ Controls for interacting with the system Extended Firmware Interface. uncacheable. ### ept -> `= List of [ ad=, pml= ]` +> `= List of [ ad=, pml=, exec-sp= ]` > Applicability: Intel @@ -949,6 +949,31 @@ introduced with the Nehalem architecture. disable PML. `pml=0` can be used to prevent the use of PML on otherwise capable hardware. +* The `exec-sp` boolean controls whether EPT superpages with execute + permissions are permitted. In general this is good for performance. + + However, on processors vulnerable CVE-2018-12207, HVM guest kernels can + use executable superpages to crash the host. By default, executable + superpages are disabled on affected hardware. + + If HVM guest kernels are trusted not to mount a DoS against the system, + this option can enabled to regain performance. + + This boolean may be modified at runtime using `xl set-parameters + ept=[no-]exec-sp` to switch between fast and secure. + + * When switching from secure to fast, preexisting HVM domains will run + at their current performance until they are rebooted; new domains will + run without any overhead. + + * When switching from fast to secure, all HVM domains will immediately + suffer a performance penalty. + + **Warning: No guarantee is made that this runtime option will be retained + indefinitely, or that it will retain this exact behaviour. It is + intended as an emergency option for people who first chose fast, then + change their minds to secure, and wish not to reboot.** + ### extra_guest_irqs > `= [][,]` diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 06a7b40107..818e705fd1 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1833,6 +1833,24 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, break; } + /* + * Workaround for XSA-304 / CVE-2018-12207. If we take an execution + * fault against a non-executable superpage, shatter it to regain + * execute permissions. + */ + if ( page_order > 0 && npfec.insn_fetch && npfec.present && !violation ) + { + int res = p2m_set_entry(p2m, _gfn(gfn), mfn, PAGE_ORDER_4K, + p2mt, p2ma); + + if ( res ) + printk(XENLOG_ERR "Failed to shatter gfn %"PRI_gfn": %d\n", + gfn, res); + + rc = !res; + goto out_put_gfn; + } + if ( violation ) { /* Should #VE be emulated for this fault? */ diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index ed27e8def7..668986eeaa 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -67,6 +67,7 @@ integer_param("ple_window", ple_window); static bool __read_mostly opt_ept_pml = true; static s8 __read_mostly opt_ept_ad = -1; +int8_t opt_ept_exec_sp = -1; static int __init parse_ept_param(const char *s) { @@ -92,6 +93,40 @@ static int __init parse_ept_param(const char *s) } custom_param("ept", parse_ept_param); +int parse_ept_param_runtime(const char *s) +{ + int val; + + if ( !cpu_has_vmx_ept || !hvm_funcs.hap_supported || + !(hvm_funcs.hap_capabilities & + (HVM_HAP_SUPERPAGE_2MB | HVM_HAP_SUPERPAGE_1GB)) ) + { + printk("VMX: EPT not available, or not in use - ignoring\n"); + return 0; + } + + if ( (val = parse_boolean("exec-sp", s, NULL)) < 0 ) + return -EINVAL; + + if ( val != opt_ept_exec_sp ) + { + struct domain *d; + + opt_ept_exec_sp = val; + + rcu_read_lock(&domlist_read_lock); + for_each_domain ( d ) + if ( paging_mode_hap(d) ) + p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_rw); + rcu_read_unlock(&domlist_read_lock); + } + + printk("VMX: EPT executable superpages %sabled\n", + val ? "en" : "dis"); + + return 0; +} + /* Dynamic (run-time adjusted) execution control flags. */ u32 vmx_pin_based_exec_control __read_mostly; u32 vmx_cpu_based_exec_control __read_mostly; diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index 220990f017..f06e51904a 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -174,6 +174,12 @@ static void ept_p2m_type_to_flags(struct p2m_domain *p2m, ept_entry_t *entry, break; } + /* + * Don't create executable superpages if we need to shatter them to + * protect against CVE-2018-12207. + */ + if ( !opt_ept_exec_sp && is_epte_superpage(entry) ) + entry->x = 0; } #define GUEST_TABLE_MAP_FAILED 0 diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index e5e4349dea..ba126f790a 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -289,15 +289,20 @@ static void change_entry_type_global(struct p2m_domain *p2m, p2m_type_t ot, p2m_type_t nt) { p2m->change_entry_type_global(p2m, ot, nt); - p2m->global_logdirty = (nt == p2m_ram_logdirty); + /* Don't allow 'recalculate' operations to change the logdirty state. */ + if ( ot != nt ) + p2m->global_logdirty = (nt == p2m_ram_logdirty); } +/* + * May be called with ot = nt = p2m_ram_rw for its side effect of + * recalculating all PTEs in the p2m. + */ void p2m_change_entry_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt) { struct p2m_domain *hostp2m = p2m_get_hostp2m(d); - ASSERT(ot != nt); ASSERT(p2m_is_changeable(ot) && p2m_is_changeable(nt)); p2m_lock(hostp2m); diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index ebaa74449b..371b912887 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -28,6 +28,8 @@ #include #include +extern int8_t opt_ept_exec_sp; + typedef union { struct { u64 r : 1, /* bit 0 - Read permission */ diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h index 637259bd1f..32746aa8ae 100644 --- a/xen/include/asm-x86/msr-index.h +++ b/xen/include/asm-x86/msr-index.h @@ -52,6 +52,7 @@ #define ARCH_CAPS_SKIP_L1DFL (_AC(1, ULL) << 3) #define ARCH_CAPS_SSB_NO (_AC(1, ULL) << 4) #define ARCH_CAPS_MDS_NO (_AC(1, ULL) << 5) +#define ARCH_CAPS_IF_PSCHANGE_MC_NO (_AC(1, ULL) << 6) #define MSR_FLUSH_CMD 0x0000010b #define FLUSH_CMD_L1D (_AC(1, ULL) << 0)