Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP1:Update
xen.8389
xsa273-3.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File xsa273-3.patch of Package xen.8389
x86/shadow: Infrastructure to force a PV guest into shadow mode To mitigate L1TF, we cannot alter an architecturally-legitimate PTE a PV guest chooses to write, but we can force the PV domain into shadow mode so Xen controls the PTEs which are reachable by the CPU pagewalk. Introduce new shadow mode, PG_SH_forced, and a tasklet to perform the transition. Later patches will introduce the logic to enable this mode at the appropriate time. To simplify vcpu cleanup, make tasklet_kill() idempotent with respect to tasklet_init(), which involves adding a helper to check for an uninitialised list head. This is part of XSA-273 / CVE-2018-3620. Signed-off-by: Juergen Gross <jgross@suse.com> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Tim Deegan <tim@xen.org> Reviewed-by: Jan Beulich <jbeulich@suse.com> --- a/xen/arch/x86/mm/paging.c +++ b/xen/arch/x86/mm/paging.c @@ -879,6 +879,8 @@ void paging_dump_domain_info(struct doma printk(" paging assistance: "); if ( paging_mode_shadow(d) ) printk("shadow "); + if ( paging_mode_sh_forced(d) ) + printk("forced "); if ( paging_mode_hap(d) ) printk("hap "); if ( paging_mode_refcounts(d) ) --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -3057,6 +3057,15 @@ static void sh_new_mode(struct domain *d ASSERT(paging_locked_by_me(d)); ASSERT(d != current->domain); + /* + * If PG_SH_forced has previously been activated because of writing an + * L1TF-vulnerable PTE, it must remain active for the remaining lifetime + * of the domain, even if the logdirty mode needs to be controlled for + * migration purposes. + */ + if ( paging_mode_sh_forced(d) ) + new_mode |= PG_SH_forced | PG_SH_enable; + d->arch.paging.mode = new_mode; for_each_vcpu(d, v) sh_update_paging_modes(v); @@ -3935,6 +3944,33 @@ void shadow_audit_tables(struct vcpu *v) #endif /* Shadow audit */ +#ifdef CONFIG_PV + +void pv_l1tf_tasklet(unsigned long data) +{ + struct domain *d = (void *)data; + + domain_pause(d); + paging_lock(d); + + if ( !paging_mode_sh_forced(d) && !d->is_dying ) + { + int ret = shadow_one_bit_enable(d, PG_SH_forced); + + if ( ret ) + { + printk(XENLOG_G_ERR "d%d Failed to enable PG_SH_forced: %d\n", + d->domain_id, ret); + domain_crash(d); + } + } + + paging_unlock(d); + domain_unpause(d); +} + +#endif /* CONFIG_PV */ + /* * Local variables: * mode: C --- a/xen/arch/x86/pv/domain.c +++ b/xen/arch/x86/pv/domain.c @@ -13,6 +13,7 @@ #include <asm/invpcid.h> #include <asm/spec_ctrl.h> #include <asm/pv/domain.h> +#include <asm/shadow.h> static __read_mostly enum { PCID_OFF, @@ -215,6 +216,8 @@ int pv_vcpu_initialise(struct vcpu *v) void pv_domain_destroy(struct domain *d) { + pv_l1tf_domain_destroy(d); + destroy_perdomain_mapping(d, GDT_LDT_VIRT_START, GDT_LDT_MBYTES << (20 - PAGE_SHIFT)); @@ -236,6 +239,8 @@ int pv_domain_initialise(struct domain * }; int rc = -ENOMEM; + pv_l1tf_domain_init(d); + d->arch.pv_domain.gdt_ldt_l1tab = alloc_xenheap_pages(0, MEMF_node(domain_to_node(d))); if ( !d->arch.pv_domain.gdt_ldt_l1tab ) --- a/xen/common/tasklet.c +++ b/xen/common/tasklet.c @@ -156,6 +156,10 @@ void tasklet_kill(struct tasklet *t) spin_lock_irqsave(&tasklet_lock, flags); + /* Cope with uninitialised tasklets. */ + if ( list_head_is_null(&t->list) ) + goto unlock; + if ( !list_empty(&t->list) ) { BUG_ON(t->is_dead || t->is_running || (t->scheduled_on < 0)); @@ -172,6 +176,7 @@ void tasklet_kill(struct tasklet *t) spin_lock_irqsave(&tasklet_lock, flags); } + unlock: spin_unlock_irqrestore(&tasklet_lock, flags); } --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -121,6 +121,11 @@ struct shadow_domain { /* Has this domain ever used HVMOP_pagetable_dying? */ bool_t pagetable_dying_op; + +#ifdef CONFIG_PV + /* PV L1 Terminal Fault mitigation. */ + struct tasklet pv_l1tf_tasklet; +#endif /* CONFIG_PV */ #endif }; @@ -257,6 +262,8 @@ struct pv_domain bool xpti; /* Use PCID feature? */ bool pcid; + /* Mitigate L1TF with shadow/crashing? */ + bool check_l1tf; /* map_domain_page() mapping cache. */ struct mapcache_domain mapcache; --- a/xen/include/asm-x86/paging.h +++ b/xen/include/asm-x86/paging.h @@ -37,11 +37,14 @@ #define PG_SH_shift 20 #define PG_HAP_shift 21 +#define PG_SHF_shift 22 /* We're in one of the shadow modes */ #ifdef CONFIG_SHADOW_PAGING #define PG_SH_enable (1U << PG_SH_shift) +#define PG_SH_forced (1U << PG_SHF_shift) #else #define PG_SH_enable 0 +#define PG_SH_forced 0 #endif #define PG_HAP_enable (1U << PG_HAP_shift) @@ -62,6 +65,7 @@ #define paging_mode_enabled(_d) (!!(_d)->arch.paging.mode) #define paging_mode_shadow(_d) (!!((_d)->arch.paging.mode & PG_SH_enable)) +#define paging_mode_sh_forced(_d) (!!((_d)->arch.paging.mode & PG_SH_forced)) #define paging_mode_hap(_d) (!!((_d)->arch.paging.mode & PG_HAP_enable)) #define paging_mode_refcounts(_d) (!!((_d)->arch.paging.mode & PG_refcounts)) --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -29,6 +29,7 @@ #include <asm/flushtlb.h> #include <asm/paging.h> #include <asm/p2m.h> +#include <asm/spec_ctrl.h> /***************************************************************************** * Macros to tell which shadow paging mode a domain is in*/ @@ -115,6 +116,37 @@ static inline int shadow_domctl(struct d #endif /* CONFIG_SHADOW_PAGING */ +/* + * Mitigations for L1TF / CVE-2018-3620 for PV guests. + * + * We cannot alter an architecturally-legitimate PTE which a PV guest has + * chosen to write, as traditional paged-out metadata is L1TF-vulnerable. + * What we can do is force a PV guest which writes a vulnerable PTE into + * shadow mode, so Xen controls the pagetables which are reachable by the CPU + * pagewalk. + */ + +void pv_l1tf_tasklet(unsigned long data); + +static inline void pv_l1tf_domain_init(struct domain *d) +{ + d->arch.pv_domain.check_l1tf = + opt_pv_l1tf & (is_hardware_domain(d) + ? OPT_PV_L1TF_DOM0 : OPT_PV_L1TF_DOMU); + +#if defined(CONFIG_SHADOW_PAGING) && defined(CONFIG_PV) + tasklet_init(&d->arch.paging.shadow.pv_l1tf_tasklet, + pv_l1tf_tasklet, (unsigned long)d); +#endif +} + +static inline void pv_l1tf_domain_destroy(struct domain *d) +{ +#if defined(CONFIG_SHADOW_PAGING) && defined(CONFIG_PV) + tasklet_kill(&d->arch.paging.shadow.pv_l1tf_tasklet); +#endif +} + /* Remove all shadows of the guest mfn. */ static inline void shadow_remove_all_shadows(struct domain *d, mfn_t gmfn) { --- a/xen/include/xen/list.h +++ b/xen/include/xen/list.h @@ -51,6 +51,11 @@ static inline void INIT_LIST_HEAD(struct list->prev = list; } +static inline bool list_head_is_null(const struct list_head *list) +{ + return !list->next && !list->prev; +} + /* * Insert a new entry between two known consecutive entries. *
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor