[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v7 2/4] x86/mm: Reject invalid cacheability in PV guests by default
Setting cacheability flags that are not ones specified by Xen is a bug in the guest. By default, return -EINVAL if a guests attempts to do this. The invalid-cacheability= Xen command-line flag allows the administrator to allow such attempts or to produce Suggested-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Signed-off-by: Demi Marie Obenour <demi@xxxxxxxxxxxxxxxxxxxxxx> --- Changes since v6: - Make invalid-cacheability= a subflag of pv=. - Move check for invalid cacheability to get_page_from_l1e(). Changes since v5: - Make parameters static and __ro_after_init. - Replace boolean parameter allow_invalid_cacheability with string parameter invalid-cacheability. - Move parameter definitions to near where they are used. - Add documentation. Changes since v4: - Remove pointless BUILD_BUG_ON(). - Add comment explaining why an exception is being injected. Changes since v3: - Add Andrew Cooper’s Suggested-by --- docs/misc/xen-command-line.pandoc | 11 ++++++ xen/arch/x86/include/asm/pv/domain.h | 7 ++++ xen/arch/x86/mm.c | 53 +++++++++++++++++++++++++++- xen/arch/x86/pv/domain.c | 18 ++++++++-- 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index 424b12cfb27d6ade2ec63eacb8afe5df82465451..0230a7bc17cbd4362a42ea64cea695f31f5e0f86 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -1417,6 +1417,17 @@ detection of systems known to misbehave upon accesses to that port. ### idle_latency_factor (x86) > `= <integer>` +### invalid-cacheability (x86) +> `= allow | deny | trap` + +> Default: `deny` in release builds, otherwise `trap` + +Specify what happens when a PV guest tries to use one of the reserved entries in +the PAT. `deny` causes the attempt to be rejected with -EINVAL, `allow` allows +the attempt, and `trap` causes a general protection fault to be raised. +Currently, the reserved entries are marked as uncacheable in Xen's PAT, but this +will change if new memory types are added, so guests must not rely on it. + ### ioapic_ack (x86) > `= old | new` diff --git a/xen/arch/x86/include/asm/pv/domain.h b/xen/arch/x86/include/asm/pv/domain.h index 924508bbb4f0c199b3cd2306d9d8f0bd0ef399f9..1c9ce259ab4ee23ea5d057f5dfa964effb169032 100644 --- a/xen/arch/x86/include/asm/pv/domain.h +++ b/xen/arch/x86/include/asm/pv/domain.h @@ -71,6 +71,13 @@ void pv_vcpu_destroy(struct vcpu *v); int pv_vcpu_initialise(struct vcpu *v); void pv_domain_destroy(struct domain *d); int pv_domain_initialise(struct domain *d); +extern __ro_after_init uint8_t invalid_cacheability; + +enum { + INVALID_CACHEABILITY_ALLOW, + INVALID_CACHEABILITY_DENY, + INVALID_CACHEABILITY_TRAP, +}; /* * Bits which a PV guest can toggle in its view of cr4. Some are loaded into diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 3558ca215b02a517d55d75329d645ae5905424e4..a8f137925cba1846b97aee9321df6427f4dd1a94 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -879,6 +879,30 @@ get_page_from_l1e( return -EINVAL; } + if ( invalid_cacheability != INVALID_CACHEABILITY_ALLOW ) + { + switch ( l1e.l1 & PAGE_CACHE_ATTRS ) + { + case _PAGE_WB: + case _PAGE_UC: + case _PAGE_UCM: + case _PAGE_WC: + case _PAGE_WT: + case _PAGE_WP: + break; + default: + /* + * If we get here, a PV guest tried to use one of the + * reserved values in Xen's PAT. This indicates a bug + * in the guest. If requested by the user, inject #GP + * to cause the guest to log a stack trace. + */ + if ( invalid_cacheability == INVALID_CACHEABILITY_TRAP ) + pv_inject_hw_exception(TRAP_gp_fault, 0); + return -EINVAL; + } + } + valid = mfn_valid(_mfn(mfn)); if ( !valid || @@ -1324,6 +1348,31 @@ static int put_page_from_l4e(l4_pgentry_t l4e, mfn_t l4mfn, unsigned int flags) return put_pt_page(l4e_get_page(l4e), mfn_to_page(l4mfn), flags); } +#ifdef NDEBUG +#define INVALID_CACHEABILITY_DEFAULT INVALID_CACHEABILITY_DENY +#else +#define INVALID_CACHEABILITY_DEFAULT INVALID_CACHEABILITY_TRAP +#endif + +__ro_after_init uint8_t invalid_cacheability = + INVALID_CACHEABILITY_DEFAULT; + +static int __init cf_check set_invalid_cacheability(const char *str) +{ + if (strcmp("allow", str) == 0) + invalid_cacheability = INVALID_CACHEABILITY_ALLOW; + else if (strcmp("deny", str) == 0) + invalid_cacheability = INVALID_CACHEABILITY_DENY; + else if (strcmp("trap", str) == 0) + invalid_cacheability = INVALID_CACHEABILITY_TRAP; + else + return -EINVAL; + + return 0; +} + +custom_param("invalid-cacheability", set_invalid_cacheability); + static int promote_l1_table(struct page_info *page) { struct domain *d = page_get_owner(page); @@ -1343,7 +1392,9 @@ static int promote_l1_table(struct page_info *page) } else { - switch ( ret = get_page_from_l1e(pl1e[i], d, d) ) + l1_pgentry_t l1e = pl1e[i]; + + switch ( ret = get_page_from_l1e(l1e, d, d) ) { default: goto fail; diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c index f94f28c8e271549acb449ef2e129b928751f765d..40b424351fd99fe1fb0a5faa5b20bf4070bb1d4a 100644 --- a/xen/arch/x86/pv/domain.c +++ b/xen/arch/x86/pv/domain.c @@ -28,9 +28,21 @@ static int __init cf_check parse_pv(const char *s) do { ss = strchr(s, ','); if ( !ss ) - ss = strchr(s, '\0'); - - if ( (val = parse_boolean("32", s, ss)) >= 0 ) + ss += strlen(s); + if ( !strncmp("invalid-cacheability=", s, + sizeof("invalid-cacheability=") - 1) ) + { + const char *p = s + (sizeof("invalid-cacheability=") - 1); + if (ss - p == 5 && !memcmp(p, "allow", 5)) + invalid_cacheability = INVALID_CACHEABILITY_ALLOW; + else if (ss - p == 4 && !memcmp(p, "deny", 4)) + invalid_cacheability = INVALID_CACHEABILITY_DENY; + else if (ss - p == 4 && !memcmp(p, "trap", 4)) + invalid_cacheability = INVALID_CACHEABILITY_TRAP; + else + rc = -EINVAL; + } + else if ( (val = parse_boolean("32", s, ss)) >= 0 ) { #ifdef CONFIG_PV32 opt_pv32 = val; -- Sincerely, Demi Marie Obenour (she/her/hers) Invisible Things Lab
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |