# Commit 2713715305ca516f698d58cec5e0b322c3b2c4eb
# Date 2018-01-26 14:10:21 +0000
# Author Andrew Cooper <andrew.cooper3@citrix.com>
# Committer Andrew Cooper <andrew.cooper3@citrix.com>
x86/boot: Calculate the most appropriate BTI mitigation to use

See the logic and comments in init_speculation_mitigations() for further
details.

There are two controls for RSB overwriting, because in principle there are
cases where it might be safe to forego rsb_native (Off the top of my head,
SMEP active, no 32bit PV guests at all, no use of vmevent/paging subsystems
for HVM guests, but I make no guarantees that this list of restrictions is
exhaustive).

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>

# Commit 30cbd0c83ef3d0edac2d5bcc41a9a2b7a843ae58
# Date 2018-02-06 18:32:58 +0000
# Author Andrew Cooper <andrew.cooper3@citrix.com>
# Committer Andrew Cooper <andrew.cooper3@citrix.com>
x86/spec_ctrl: Fix determination of when to use IBRS

The original version of this logic was:

    /*
     * On Intel hardware, we'd like to use retpoline in preference to
     * IBRS, but only if it is safe on this hardware.
     */
    else if ( boot_cpu_has(X86_FEATURE_IBRSB) )
    {
        if ( retpoline_safe() )
            thunk = THUNK_RETPOLINE;
        else
            ibrs = true;
    }

but it was changed by a request during review.  Sadly, the result is buggy as
it breaks the later fallback logic by allowing IBRS to appear as available
when in fact it isn't.

This in practice means that on repoline-unsafe hardware without IBRS, we
select THUNK_JUMP despite intending to select THUNK_RETPOLINE.

Reported-by: Zhenzhong Duan <zhenzhong.duan@oracle.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>

--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -191,6 +191,17 @@ Scrub free RAM during boot.  This is a s
 accidentally leaking sensitive VM data into other VMs if Xen crashes
 and reboots.
 
+### bti (x86)
+> `= List of [ ibrs=<bool>, rsb_{vmexit,native}=<bool> ]`
+
+On hardware supporting IBRS, the `ibrs=` option can be used to force or
+prevent Xen using the feature itself.  If Xen is not using IBRS itself,
+functionality is still set up so IBRS can be virtualised for guests.
+
+The `rsb_vmexit=` and `rsb_native=` options can be used to fine tune when the
+RSB gets overwritten.  There are individual controls for an entry from HVM
+context, and an entry from a native (PV or Xen) context.
+
 ### cachesize
 > `= <size>`
 
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -17,6 +17,7 @@
  * Copyright (c) 2017-2018 Citrix Systems Ltd.
  */
 #include <xen/init.h>
+#include <xen/errno.h>
 #include <xen/lib.h>
 
 #include <asm/processor.h>
@@ -28,6 +29,37 @@ enum ind_thunk {
 
     THUNK_RETPOLINE,
 };
+static int8_t __initdata opt_ibrs = -1;
+static bool_t __initdata opt_rsb_native = 1;
+static bool_t __initdata opt_rsb_vmexit = 1;
+int8_t __read_mostly default_xen_ibrs = -1;
+uint8_t __read_mostly default_xen_rsb = 0;
+
+static int __init parse_bti(const char *s)
+{
+    const char *ss;
+    int val, rc = 0;
+
+    do {
+        ss = strchr(s, ',');
+        if ( !ss )
+            ss = strchr(s, '\0');
+
+        if ( (val = parse_boolean("ibrs", s, ss)) >= 0 )
+            opt_ibrs = val;
+        else if ( (val = parse_boolean("rsb_native", s, ss)) >= 0 )
+            opt_rsb_native = val;
+        else if ( (val = parse_boolean("rsb_vmexit", s, ss)) >= 0 )
+            opt_rsb_vmexit = val;
+        else
+            rc = -EINVAL;
+
+        s = ss + 1;
+    } while ( *ss );
+
+    return rc;
+}
+custom_param("bti", parse_bti);
 
 static void __init print_details(enum ind_thunk thunk)
 {
@@ -56,14 +88,24 @@ static void __init print_details(enum in
 #endif
 
     printk(XENLOG_INFO
-           "BTI mitigations: Thunk %s\n",
+           "BTI mitigations: Thunk %s, Others:%s%s%s\n",
            thunk == THUNK_NONE      ? "N/A" :
-           thunk == THUNK_RETPOLINE ? "RETPOLINE" : "?");
+           thunk == THUNK_RETPOLINE ? "RETPOLINE" : "?",
+           default_xen_ibrs > 0     ? " IBRS+" :
+           default_xen_ibrs == 0    ? " IBRS-" : "",
+           default_xen_rsb & XEN_RSB_NATIVE ? " RSB_NATIVE" : "",
+           default_xen_rsb & XEN_RSB_VMEXIT ? " RSB_VMEXIT" : "");
 }
 
 void __init init_speculation_mitigations(void)
 {
     enum ind_thunk thunk = THUNK_DEFAULT;
+    bool_t ibrs;
+
+    if ( opt_ibrs != -1 )
+        ibrs = !!opt_ibrs;
+    else
+        ibrs = !!boot_cpu_has(X86_FEATURE_IBRSB);
 
     /*
      * Supplimentary minor adjustments.  Without compiler support, there are
@@ -80,6 +122,42 @@ void __init init_speculation_mitigations
     if ( thunk == THUNK_DEFAULT )
         thunk = THUNK_RETPOLINE;
 
+    if ( boot_cpu_has(X86_FEATURE_IBRSB) )
+    {
+        /*
+         * Even if we've chosen to not have IBRS set in Xen context, we still
+         * need the IBRS entry/exit logic to virtualise IBRS support for
+         * guests.
+         */
+        default_xen_ibrs = ibrs;
+    }
+
+    /*
+     * PV guests can poison the RSB to any virtual address from which
+     * they can execute a call instruction.  This is necessarily outside
+     * of the Xen supervisor mappings.
+     *
+     * With SMEP enabled, the processor won't speculate into user mappings.
+     * Therefore, in this case, we don't need to worry about poisoned entries
+     * from 64bit PV guests.
+     *
+     * 32bit PV guest kernels run in ring 1, so use supervisor mappings.
+     * If a processors speculates to 32bit PV guest kernel mappings, it is
+     * speculating in 64bit supervisor mode, and can leak data.
+     */
+    if ( opt_rsb_native )
+        default_xen_rsb |= XEN_RSB_NATIVE;
+
+    /*
+     * HVM guests can always poison the RSB to point at Xen supervisor
+     * mappings.
+     */
+    if ( opt_rsb_vmexit )
+        default_xen_rsb |= XEN_RSB_VMEXIT;
+
+    /* (Re)init BSP state now that default_xen_* have been calculated. */
+    init_shadow_spec_ctrl_state();
+
     print_details(thunk);
 }
 
--- a/xen/include/asm-x86/spec_ctrl.h
+++ b/xen/include/asm-x86/spec_ctrl.h
@@ -24,13 +24,16 @@
 
 void init_speculation_mitigations(void);
 
+extern int8_t default_xen_ibrs;
+extern uint8_t default_xen_rsb;
+
 static inline void init_shadow_spec_ctrl_state(void)
 {
     struct cpu_info *info = get_cpu_info();
 
     info->shadow_spec_ctrl = info->use_shadow_spec_ctrl = 0;
-    info->xen_ibrs = -1;
-    info->xen_rsb = 0;
+    info->xen_ibrs = default_xen_ibrs;
+    info->xen_rsb = default_xen_rsb;
 }
 
 #endif /* !__X86_SPEC_CTRL_H__ */
