[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 12/14] x86/spec-ctrl: introduce Address Space Isolation command line option



From: Roger Pau Monné <roger.pau@xxxxxxxxxx>

Introduce the `asi=` command line option, and the opt_vcpu_pt_{pv,hwdom,hvm}
knobs plus the per-domain d->arch.vcpu_pt setting it controls.  The option is
introduced ahead of the functionality it enables, so that the newly added
code can be keyed on it from the start; all knobs currently default to off,
and enabling any of them taints the boot with a "not functional, development
purposes only" warning.

XPTI and per-vCPU page-tables are mutually exclusive (they are different
answers to the same problem, and the entry paths can only be built for one of
them at a time), so an explicit XPTI request takes precedence over vCPU-PT,
per axis: xpti=dom0 clears the hardware domain vCPU-PT knob (when dom0 is
PV), and xpti=domu clears the PV domU one.  When XPTI is left to default, it
is turned off for those domain kinds that use vCPU-PT instead.

The boot log gains "ASI features for ..." lines for Dom0, HVM and PV
domains, so hardware-domain-only configurations remain visible, and the XPTI
line is printed unconditionally: users expecting to assert the state of XPTI
should not need to derive it from the ASI configuration.

Further per-mechanism tokens arrive with their mechanisms in later
patches.

Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
Assisted-by: Claude Code:claude-fable-5, Claude Code:claude-opus-4-8
Signed-off-by: George Dunlap <gwd@xxxxxxxxxxxxxx>
---
Changes in v2:
- Added to the series

Changes since the previously posted version:
- Make the XPTI exclusion per-axis: an explicit xpti=dom0 previously
   cleared only the PV domU vCPU-PT knob, leaving dom0 with both XPTI
   and vCPU-PT enabled.
- Include the hardware domain in the development warning and the boot
   log summary.
- Print the XPTI status line unconditionally.
- Make the opt_vcpu_pt_* knobs plain booleans preinitialised to false,
   dropping the late -1 resolution.
- Documentation: mention possible protection against unmitigated
   attacks, use {pv,hvm} notation in the synopsis, and state that
   pv=/hvm= do not affect the hardware domain.
- Rewrite the commit message.
---
 docs/misc/xen-command-line.pandoc    |  24 ++++++
 xen/arch/x86/include/asm/domain.h    |   3 +
 xen/arch/x86/include/asm/spec_ctrl.h |   2 +
 xen/arch/x86/spec_ctrl.c             | 107 ++++++++++++++++++++++++++-
 4 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/docs/misc/xen-command-line.pandoc 
b/docs/misc/xen-command-line.pandoc
index 1c711fa980..834f6c57f2 100644
--- a/docs/misc/xen-command-line.pandoc
+++ b/docs/misc/xen-command-line.pandoc
@@ -202,6 +202,30 @@ to appropriate auditing by Xen.  Argo is disabled by 
default.
     This option is disabled by default, to protect domains from a DoS by a
     buggy or malicious other domain spamming the ring.
 
+### asi (x86)
+> `= List of [ <bool>, pv=<bool>, hvm=<bool>,
+>              vcpu-pt=<bool> | vcpu-pt={pv,hvm}=<bool> ]`
+
+> Default: `false`
+
+Offers control over whether the hypervisor will engage in Address Space
+Isolation, by not having potentially sensitive information permanently mapped
+in the VMM page-tables.  Using this option might avoid the need to apply
+mitigations for certain speculative related attacks, at the cost of mapping
+sensitive information on-demand.  It might also offer some protection against
+unmitigated speculation-related attacks.
+
+* `pv=` and `hvm=` sub-options allow enabling for specific guest types; they
+  do not affect the hardware domain, which follows the whole-feature forms
+  (the plain boolean, or an un-suffixed `vcpu-pt=<bool>`).
+
+**WARNING: manual de-selection of enabled options will invalidate any
+protection offered by the feature.  The fine grained options provided below
+are meant to be used for debugging purposes only.**
+
+* `vcpu-pt` ensures each vCPU uses a unique top-level page-table and sets up
+  a virtual address space region to map memory on a per-vCPU basis.
+
 ### asid (x86)
 > `= <boolean>`
 
diff --git a/xen/arch/x86/include/asm/domain.h 
b/xen/arch/x86/include/asm/domain.h
index 38df5c376e..fdf7b205ea 100644
--- a/xen/arch/x86/include/asm/domain.h
+++ b/xen/arch/x86/include/asm/domain.h
@@ -472,6 +472,9 @@ struct arch_domain
     /* Don't unconditionally inject #GP for unhandled MSRs. */
     bool msr_relaxed;
 
+    /* Use a per-vCPU root pt, and switch per-domain slot to per-vCPU. */
+    bool vcpu_pt;
+
     /* Emulated devices enabled bitmap. */
     uint32_t emulation_flags;
 } __cacheline_aligned;
diff --git a/xen/arch/x86/include/asm/spec_ctrl.h 
b/xen/arch/x86/include/asm/spec_ctrl.h
index 8f82533c41..770c24f6a0 100644
--- a/xen/arch/x86/include/asm/spec_ctrl.h
+++ b/xen/arch/x86/include/asm/spec_ctrl.h
@@ -87,6 +87,8 @@ extern uint8_t default_scf;
 
 extern int8_t opt_xpti_hwdom, opt_xpti_domu;
 
+extern bool opt_vcpu_pt_pv, opt_vcpu_pt_hwdom, opt_vcpu_pt_hvm;
+
 extern bool cpu_has_bug_l1tf;
 extern int8_t opt_pv_l1tf_hwdom, opt_pv_l1tf_domu;
 extern bool opt_bp_spec_reduce;
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index bc8538a56f..55a02212a9 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -86,6 +86,14 @@ bool __ro_after_init opt_bp_spec_reduce = true;
 
 static bool __initdata opt_ibpb_alt;
 
+/*
+ * Use a per-vCPU root page-table and switch the per-domain slot to per-vCPU.
+ * Off by default until the feature is complete.
+ */
+bool __ro_after_init opt_vcpu_pt_hvm;
+bool __ro_after_init opt_vcpu_pt_hwdom;
+bool __ro_after_init opt_vcpu_pt_pv;
+
 static int __init cf_check parse_spec_ctrl(const char *s)
 {
     const char *ss;
@@ -383,6 +391,18 @@ int8_t __ro_after_init opt_xpti_domu = -1;
 
 static __init void xpti_init_default(void)
 {
+    if ( !opt_dom0_pvh && opt_xpti_hwdom == 1 && opt_vcpu_pt_hwdom )
+    {
+        printk(XENLOG_ERR
+               "XPTI incompatible with per-vCPU page-tables, disabling Dom0 
vCPU-PT\n");
+        opt_vcpu_pt_hwdom = false;
+    }
+    if ( opt_xpti_domu == 1 && opt_vcpu_pt_pv )
+    {
+        printk(XENLOG_ERR
+               "XPTI incompatible with per-vCPU page-tables, disabling PV DomU 
vCPU-PT\n");
+        opt_vcpu_pt_pv = false;
+    }
     if ( (boot_cpu_data.vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON)) ||
          cpu_has_rdcl_no )
     {
@@ -394,9 +414,9 @@ static __init void xpti_init_default(void)
     else
     {
         if ( opt_xpti_hwdom < 0 )
-            opt_xpti_hwdom = 1;
+            opt_xpti_hwdom = !opt_vcpu_pt_hwdom;
         if ( opt_xpti_domu < 0 )
-            opt_xpti_domu = 1;
+            opt_xpti_domu = !opt_vcpu_pt_pv;
     }
 }
 
@@ -487,6 +507,66 @@ static int __init cf_check parse_pv_l1tf(const char *s)
 }
 custom_param("pv-l1tf", parse_pv_l1tf);
 
+static int __init cf_check parse_asi(const char *s)
+{
+    const char *ss;
+    int val, rc = 0;
+
+    /* Interpret 'asi' alone in its positive boolean form. */
+    if ( *s == '\0' )
+        opt_vcpu_pt_pv = opt_vcpu_pt_hwdom = opt_vcpu_pt_hvm = true;
+
+    do {
+        ss = strchr(s, ',');
+        if ( !ss )
+            ss = strchr(s, '\0');
+
+        val = parse_bool(s, ss);
+        switch ( val )
+        {
+        case 0:
+        case 1:
+            opt_vcpu_pt_pv = opt_vcpu_pt_hwdom = opt_vcpu_pt_hvm = val;
+            break;
+
+        default:
+            if ( (val = parse_boolean("pv", s, ss)) >= 0 )
+                opt_vcpu_pt_pv = val;
+            else if ( (val = parse_boolean("hvm", s, ss)) >= 0 )
+                opt_vcpu_pt_hvm = val;
+            else if ( (val = parse_boolean("vcpu-pt", s, ss)) != -1 )
+            {
+                switch ( val )
+                {
+                case 1:
+                case 0:
+                    opt_vcpu_pt_pv = opt_vcpu_pt_hvm = opt_vcpu_pt_hwdom = val;
+                    break;
+
+                case -2:
+                    s += strlen("vcpu-pt=");
+                    if ( (val = parse_boolean("pv", s, ss)) >= 0 )
+                        opt_vcpu_pt_pv = val;
+                    else if ( (val = parse_boolean("hvm", s, ss)) >= 0 )
+                        opt_vcpu_pt_hvm = val;
+                    else
+                default:
+                        rc = -EINVAL;
+                    break;
+                }
+            }
+            else if ( *s )
+                rc = -EINVAL;
+            break;
+        }
+
+        s = ss + 1;
+    } while ( *ss );
+
+    return rc;
+}
+custom_param("asi", parse_asi);
+
 static void __init print_details(enum ind_thunk thunk)
 {
     unsigned int _7d0 = 0, _7d2 = 0, e8b = 0, e21a = 0, e21c = 0, max = 0, tmp;
@@ -680,6 +760,20 @@ static void __init print_details(enum ind_thunk thunk)
            opt_pv_l1tf_hwdom ? "enabled"  : "disabled",
            opt_pv_l1tf_domu  ? "enabled"  : "disabled");
 #endif
+
+    printk("  ASI features for Dom0:%s%s\n",
+           opt_vcpu_pt_hwdom                         ? ""               : " 
None",
+           opt_vcpu_pt_hwdom                         ? " vCPU-PT"       : "");
+#ifdef CONFIG_HVM
+    printk("  ASI features for HVM VMs:%s%s\n",
+           opt_vcpu_pt_hvm                           ? ""               : " 
None",
+           opt_vcpu_pt_hvm                           ? " vCPU-PT"       : "");
+#endif
+#ifdef CONFIG_PV
+    printk("  ASI features for PV VMs:%s%s\n",
+           opt_vcpu_pt_pv                            ? ""               : " 
None",
+           opt_vcpu_pt_pv                            ? " vCPU-PT"       : "");
+#endif
 }
 
 static bool __init check_smt_enabled(void)
@@ -1866,6 +1960,10 @@ void spec_ctrl_init_domain(struct domain *d)
     if ( pv )
         d->arch.pv.xpti = is_hardware_domain(d) ? opt_xpti_hwdom
                                                 : opt_xpti_domu;
+
+    d->arch.vcpu_pt = is_hardware_domain(d) ? opt_vcpu_pt_hwdom
+                                            : pv ? opt_vcpu_pt_pv
+                                                 : opt_vcpu_pt_hvm;
 }
 
 void __init init_speculation_mitigations(void)
@@ -2158,6 +2256,11 @@ void __init init_speculation_mitigations(void)
          hw_smt_enabled && default_xen_spec_ctrl )
         setup_force_cpu_cap(X86_FEATURE_SC_MSR_IDLE);
 
+    if ( opt_vcpu_pt_pv || opt_vcpu_pt_hwdom || opt_vcpu_pt_hvm )
+        warning_add(
+            "Address Space Isolation is not functional, this option is\n"
+            "intended to be used only for development purposes.\n");
+
     xpti_init_default();
 
     l1tf_calculations();
-- 
2.55.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.