Add a command line parameter for controlling Xen page table isolation
(XPTI): per default it is on for non-AMD systems in 64 bit pv domains.

Possible settings are:
- true: switched on even on AMD systems
- false: switched off for all
- nodom0: switched off for dom0

As we don't want to set XPTI for 32 bit pv domains we have to delay
XPTI initialization until XEN_DOMCTL_set_address_size has been called
for the domain. Dom0 needs a specific init call.

Signed-off-by: Juergen Gross <jgr...@suse.com>
---
V3:
- move XPTI initialization call to XEN_DOMCTL_set_address_size handling
- move XPTI code into arch/x86/pv/xpti.c
- replace xpti flag in struct domain by pointer
- add is_*_xpti_active() helpers
---
 docs/misc/xen-command-line.markdown |  18 ++++++
 xen/arch/x86/domctl.c               |   4 ++
 xen/arch/x86/pv/Makefile            |   1 +
 xen/arch/x86/pv/dom0_build.c        |   3 +
 xen/arch/x86/pv/domain.c            |   3 +
 xen/arch/x86/pv/xpti.c              | 111 ++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/domain.h        |   4 ++
 xen/include/asm-x86/pv/mm.h         |  20 +++++++
 8 files changed, 164 insertions(+)
 create mode 100644 xen/arch/x86/pv/xpti.c

diff --git a/docs/misc/xen-command-line.markdown 
b/docs/misc/xen-command-line.markdown
index 6df39dae0b..f96bb6342d 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1926,6 +1926,24 @@ In the case that x2apic is in use, this option switches 
between physical and
 clustered mode.  The default, given no hint from the **FADT**, is cluster
 mode.
 
+### xpti
+> `= nodom0 | default | <boolean>`
+
+> Default: `false` on AMD hardware, `true` everywhere else.
+
+> Can be modified at runtime
+
+Override default selection of whether to isolate 64-bit PV guest page
+tables.
+
+`true` activates page table isolation even on AMD hardware.
+
+`false` deactivates page table isolation on all systems.
+
+`nodom0` deactivates page table isolation for dom0.
+
+`default` switch to default settings.
+
 ### xsave
 > `= <boolean>`
 
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 8fbbf3aeb3..0b448e411d 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -31,6 +31,7 @@
 #include <xen/vm_event.h>
 #include <public/vm_event.h>
 #include <asm/mem_sharing.h>
+#include <asm/pv/mm.h>
 #include <asm/xstate.h>
 #include <asm/debugger.h>
 #include <asm/psr.h>
@@ -610,6 +611,9 @@ long arch_do_domctl(
             ret = switch_compat(d);
         else
             ret = -EINVAL;
+
+        if ( ret == 0 )
+            ret = xpti_domain_init(d);
         break;
 
     case XEN_DOMCTL_get_address_size:
diff --git a/xen/arch/x86/pv/Makefile b/xen/arch/x86/pv/Makefile
index 65bca04175..a12e4fbd1a 100644
--- a/xen/arch/x86/pv/Makefile
+++ b/xen/arch/x86/pv/Makefile
@@ -13,6 +13,7 @@ obj-y += mm.o
 obj-y += ro-page-fault.o
 obj-$(CONFIG_PV_SHIM) += shim.o
 obj-y += traps.o
+obj-y += xpti.o
 
 obj-bin-y += dom0_build.init.o
 obj-bin-y += gpr_switch.o
diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c
index 0bd2f1bf90..6e7bc435ab 100644
--- a/xen/arch/x86/pv/dom0_build.c
+++ b/xen/arch/x86/pv/dom0_build.c
@@ -707,6 +707,9 @@ int __init dom0_construct_pv(struct domain *d,
             cpu = p->processor;
     }
 
+    if ( !is_pv_32bit_domain(d) )
+        xpti_domain_init(d);
+
     d->arch.paging.mode = 0;
 
     /* Set up CR3 value for write_ptbase */
diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c
index 2c784fb3cc..a007af94dd 100644
--- a/xen/arch/x86/pv/domain.c
+++ b/xen/arch/x86/pv/domain.c
@@ -10,6 +10,7 @@
 #include <xen/sched.h>
 
 #include <asm/pv/domain.h>
+#include <asm/pv/mm.h>
 
 /* Override macros from asm/page.h to make them work with mfn_t */
 #undef mfn_to_page
@@ -174,6 +175,8 @@ void pv_domain_destroy(struct domain *d)
 
     free_xenheap_page(d->arch.pv_domain.gdt_ldt_l1tab);
     d->arch.pv_domain.gdt_ldt_l1tab = NULL;
+
+    xpti_domain_destroy(d);
 }
 
 
diff --git a/xen/arch/x86/pv/xpti.c b/xen/arch/x86/pv/xpti.c
new file mode 100644
index 0000000000..0b17d77d74
--- /dev/null
+++ b/xen/arch/x86/pv/xpti.c
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * arch/x86/mm/xpti.c
+ *
+ * Xen Page Table Isolation support.
+ *
+ * Copyright (c) 2018 SUSE Linux GmbH (Juergen Gross)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+
+struct xpti_domain {
+    int pad;
+};
+
+static __read_mostly enum {
+    XPTI_DEFAULT,
+    XPTI_ON,
+    XPTI_OFF,
+    XPTI_NODOM0
+} opt_xpti = XPTI_DEFAULT;
+
+static int parse_xpti(const char *s)
+{
+    int rc = 0;
+
+    switch ( parse_bool(s, NULL) )
+    {
+    case 0:
+        opt_xpti = XPTI_OFF;
+        break;
+    case 1:
+        opt_xpti = XPTI_ON;
+        break;
+    default:
+        if ( !strcmp(s, "default") )
+            opt_xpti = XPTI_DEFAULT;
+        else if ( !strcmp(s, "nodom0") )
+            opt_xpti = XPTI_NODOM0;
+        else
+            rc = -EINVAL;
+        break;
+    }
+
+    return rc;
+}
+
+custom_runtime_param("xpti", parse_xpti);
+
+void xpti_domain_destroy(struct domain *d)
+{
+    xfree(d->arch.pv_domain.xpti);
+    d->arch.pv_domain.xpti = NULL;
+}
+
+int xpti_domain_init(struct domain *d)
+{
+    bool xpti = false;
+    int ret = 0;
+
+    if ( !is_pv_domain(d) || is_pv_32bit_domain(d) )
+        return 0;
+
+    switch ( opt_xpti )
+    {
+    case XPTI_OFF:
+        xpti = false;
+        break;
+    case XPTI_ON:
+        xpti = true;
+        break;
+    case XPTI_NODOM0:
+        xpti = boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+               d->domain_id != 0 && d->domain_id != hardware_domid;
+        break;
+    case XPTI_DEFAULT:
+        xpti = boot_cpu_data.x86_vendor != X86_VENDOR_AMD;
+        break;
+    }
+
+    if ( !xpti )
+        return 0;
+
+    d->arch.pv_domain.xpti = xmalloc(struct xpti_domain);
+    if ( !d->arch.pv_domain.xpti )
+    {
+        ret = -ENOMEM;
+        goto done;
+    }
+
+    printk("Enabling Xen Pagetable protection (XPTI) for Domain %d\n",
+           d->domain_id);
+
+ done:
+    return ret;
+}
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 4679d5477d..b33c286807 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -247,6 +247,8 @@ struct time_scale {
     u32 mul_frac;
 };
 
+struct xpti_domain;
+
 struct pv_domain
 {
     l1_pgentry_t **gdt_ldt_l1tab;
@@ -257,6 +259,8 @@ struct pv_domain
     struct mapcache_domain mapcache;
 
     struct cpuidmasks *cpuidmasks;
+
+    struct xpti_domain *xpti;
 };
 
 struct monitor_write_data {
diff --git a/xen/include/asm-x86/pv/mm.h b/xen/include/asm-x86/pv/mm.h
index 246b99014c..dfac89df0b 100644
--- a/xen/include/asm-x86/pv/mm.h
+++ b/xen/include/asm-x86/pv/mm.h
@@ -31,6 +31,19 @@ void pv_destroy_gdt(struct vcpu *v);
 bool pv_map_ldt_shadow_page(unsigned int off);
 bool pv_destroy_ldt(struct vcpu *v);
 
+int xpti_domain_init(struct domain *d);
+void xpti_domain_destroy(struct domain *d);
+
+static inline bool is_domain_xpti_active(const struct domain *d)
+{
+    return is_pv_domain(d) && d->arch.pv_domain.xpti;
+}
+
+static inline bool is_vcpu_xpti_active(const struct vcpu *v)
+{
+    return is_domain_xpti_active(v->domain);
+}
+
 #else
 
 #include <xen/errno.h>
@@ -52,6 +65,13 @@ static inline bool pv_map_ldt_shadow_page(unsigned int off) 
{ return false; }
 static inline bool pv_destroy_ldt(struct vcpu *v)
 { ASSERT_UNREACHABLE(); return false; }
 
+static inline int xpti_domain_init(struct domain *d) { return 0; }
+static inline void xpti_domain_destroy(struct domain *d) { }
+
+static inline bool is_domain_xpti_active(const struct domain *d)
+{ return false; }
+static inline bool is_vcpu_xpti_active(const struct vcpu *v) { return false; }
+
 #endif
 
 #endif /* __X86_PV_MM_H__ */
-- 
2.13.6


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

Reply via email to