Add new protection modes for Spectre v2 mitigations against
Spectre v2 attacks on user processes.  There are three modes:

        strict mode:
        In this mode, IBPB and STIBP are deployed full
        time to protect all processes.

        lite mode:
        In this mode, IBPB and STIBP are only deployed on
        processes marked with TIF_STIBP flag.

        none mode:
        In this mode, no mitigations are deployed.

The protection mode can be specified by the spectre_v2_app2app
boot parameter with the following semantics:

spectre_v2_app2app=
        off    - Turn off mitigation
        lite   - Protect processes which are marked non-dumpable
        strict - Protect all processes
        auto   - Kernel selects the mode

        Not specifying this option is equivalent to
        spectre_v2_app2app=auto.

        Setting spectre_v2=off will also turn off this mitigation.

        Setting spectre_v2=on implies unconditionally enabling
        this mitigation.

Signed-off-by: Tim Chen <tim.c.c...@linux.intel.com>
---
 Documentation/admin-guide/kernel-parameters.txt |  20 ++++
 arch/x86/include/asm/nospec-branch.h            |   9 ++
 arch/x86/kernel/cpu/bugs.c                      | 153 +++++++++++++++++++++---
 arch/x86/mm/tlb.c                               |  23 +++-
 4 files changed, 185 insertions(+), 20 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index 81d1d5a..9c306e3 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4215,6 +4215,26 @@
                        Not specifying this option is equivalent to
                        spectre_v2=auto.
 
+       spectre_v2_app2app=
+                       [X86] Control mitigation of Spectre variant 2
+                       application to application (indirect branch speculation)
+                       vulnerability.
+
+                       off    - Unconditionally disable mitigations
+                       lite   - Protect tasks which have requested restricted
+                                indirect branch speculation via the
+                                PR_SET_SPECULATION_CTRL prctl(). 
+                       strict - Protect all processes
+                       auto   - Kernel selects the mode
+
+                       Not specifying this option is equivalent to
+                       spectre_v2_app2app=auto.
+
+                       Setting spectre_v2=off will also turn off this 
mitigation.
+
+                       Setting spectre_v2=on implies unconditionally enabling
+                       this mitigation.
+
        spec_store_bypass_disable=
                        [HW] Control Speculative Store Bypass (SSB) Disable 
mitigation
                        (Speculative Store Bypass vulnerability)
diff --git a/arch/x86/include/asm/nospec-branch.h 
b/arch/x86/include/asm/nospec-branch.h
index 80dc144..587629d 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -3,6 +3,7 @@
 #ifndef _ASM_X86_NOSPEC_BRANCH_H_
 #define _ASM_X86_NOSPEC_BRANCH_H_
 
+#include <linux/static_key.h>
 #include <asm/alternative.h>
 #include <asm/alternative-asm.h>
 #include <asm/cpufeatures.h>
@@ -226,6 +227,12 @@ enum spectre_v2_mitigation {
        SPECTRE_V2_IBRS_ENHANCED,
 };
 
+enum spectre_v2_app2app_mitigation {
+       SPECTRE_V2_APP2APP_NONE,
+       SPECTRE_V2_APP2APP_LITE,
+       SPECTRE_V2_APP2APP_STRICT,
+};
+
 /* The Speculative Store Bypass disable variants */
 enum ssb_mitigation {
        SPEC_STORE_BYPASS_NONE,
@@ -237,6 +244,8 @@ enum ssb_mitigation {
 extern char __indirect_thunk_start[];
 extern char __indirect_thunk_end[];
 
+DECLARE_STATIC_KEY_FALSE(spectre_v2_app_lite);
+
 /*
  * On VMEXIT we must ensure that no RSB predictions learned in the guest
  * can be followed in the host, by overwriting the RSB completely. Both
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 6e1b910..21caade 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -133,6 +133,14 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_RETPOLINE_AMD,
 };
 
+enum spectre_v2_app2app_mitigation_cmd {
+       SPECTRE_V2_APP2APP_CMD_NONE,
+       SPECTRE_V2_APP2APP_CMD_AUTO,
+       SPECTRE_V2_APP2APP_CMD_FORCE,
+       SPECTRE_V2_APP2APP_CMD_LITE,
+       SPECTRE_V2_APP2APP_CMD_STRICT,
+};
+
 static const char *spectre_v2_strings[] = {
        [SPECTRE_V2_NONE]                       = "Vulnerable",
        [SPECTRE_V2_RETPOLINE_MINIMAL]          = "Vulnerable: Minimal generic 
ASM retpoline",
@@ -142,12 +150,24 @@ static const char *spectre_v2_strings[] = {
        [SPECTRE_V2_IBRS_ENHANCED]              = "Mitigation: Enhanced IBRS",
 };
 
+static const char *spectre_v2_app2app_strings[] = {
+       [SPECTRE_V2_APP2APP_NONE]   = "App-App Vulnerable",
+       [SPECTRE_V2_APP2APP_LITE]   = "App-App Mitigation: Protect branch 
speculation restricted tasks",
+       [SPECTRE_V2_APP2APP_STRICT] = "App-App Mitigation: Full app to app 
attack protection",
+};
+
+DEFINE_STATIC_KEY_FALSE(spectre_v2_app_lite);
+EXPORT_SYMBOL_GPL(spectre_v2_app_lite);
+
 #undef pr_fmt
 #define pr_fmt(fmt)     "Spectre V2 : " fmt
 
 static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
        SPECTRE_V2_NONE;
 
+static enum spectre_v2_app2app_mitigation
+       spectre_v2_app2app_enabled __ro_after_init = SPECTRE_V2_APP2APP_NONE;
+
 void
 x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool 
setguest)
 {
@@ -169,6 +189,9 @@ x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 
guest_virt_spec_ctrl, bool setguest)
                    static_cpu_has(X86_FEATURE_AMD_SSBD))
                        hostval |= ssbd_tif_to_spec_ctrl(ti->flags);
 
+               if (static_branch_unlikely(&spectre_v2_app_lite))
+                       hostval |= stibp_tif_to_spec_ctrl(ti->flags);
+
                if (hostval != guestval) {
                        msrval = setguest ? guestval : hostval;
                        wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
@@ -275,6 +298,66 @@ static const struct {
        { "auto",              SPECTRE_V2_CMD_AUTO,              false },
 };
 
+static const struct {
+       const char *option;
+       enum spectre_v2_app2app_mitigation_cmd cmd;
+       bool secure;
+} app2app_options[] = {
+       { "off",        SPECTRE_V2_APP2APP_CMD_NONE,   false },
+       { "lite",       SPECTRE_V2_APP2APP_CMD_LITE,   false },
+       { "strict",     SPECTRE_V2_APP2APP_CMD_STRICT, false },
+       { "auto",       SPECTRE_V2_APP2APP_CMD_AUTO,   false },
+       /*
+        * The "on" option is kept as last entry. It is implied by
+        * spectre_v2=on boot parameter and it is not checked
+        * in spectre_v2_app2app boot parameter.
+        */
+       { "on",         SPECTRE_V2_APP2APP_CMD_FORCE,  true  },
+};
+
+static enum spectre_v2_app2app_mitigation_cmd __init
+           spectre_v2_parse_app2app_cmdline(enum spectre_v2_mitigation_cmd 
v2_cmd)
+{
+       enum spectre_v2_app2app_mitigation_cmd cmd;
+       char arg[20];
+       int ret, i;
+
+       if (v2_cmd == SPECTRE_V2_CMD_FORCE) {
+               cmd = SPECTRE_V2_APP2APP_CMD_FORCE;
+               goto show_cmd;
+       }
+
+       cmd = SPECTRE_V2_APP2APP_CMD_AUTO;
+       ret = cmdline_find_option(boot_command_line, "spectre_v2_app2app",
+                                 arg, sizeof(arg));
+       if (ret < 0)
+               return SPECTRE_V2_APP2APP_CMD_AUTO;
+
+       /*
+        * Don't check the last entry for forced mitigation. It is infered from
+        * v2_cmd == SPECTRE_V2_CMD_FORCE
+        */
+       for (i = 0; i < ARRAY_SIZE(app2app_options)-1; i++) {
+               if (!match_option(arg, ret, app2app_options[i].option))
+                       continue;
+               cmd = app2app_options[i].cmd;
+               break;
+       }
+
+       if (i >= ARRAY_SIZE(app2app_options)) {
+               pr_err("unknown app to app protection option (%s). Switching to 
AUTO select\n", arg);
+               return SPECTRE_V2_APP2APP_CMD_AUTO;
+       }
+
+show_cmd:
+       if (app2app_options[i].secure)
+               spec2_print_if_secure(app2app_options[i].option);
+       else
+               spec2_print_if_insecure(app2app_options[i].option);
+
+       return cmd;
+}
+
 static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
 {
        char arg[20];
@@ -328,14 +411,19 @@ static bool stibp_needed(void)
        /*
         * Determine if STIBP should be always on.
         * Using enhanced IBRS makes using STIBP unnecessary.
+        * For lite option, STIBP is used only for task with
+        * TIF_STIBP flag. STIBP is not always on for that case.
         */
 
-       if (spectre_v2_enabled == SPECTRE_V2_NONE)
+       if (spectre_v2_app2app_enabled == SPECTRE_V2_APP2APP_NONE)
                return false;
 
        if (static_cpu_has(X86_FEATURE_USE_IBRS_ENHANCED))
                return false;
 
+       if (static_branch_unlikely(&spectre_v2_app_lite))
+               return false;
+
        if (!boot_cpu_has(X86_FEATURE_STIBP))
                return false;
 
@@ -376,6 +464,8 @@ static void __init spectre_v2_select_mitigation(void)
 {
        enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
        enum spectre_v2_mitigation mode = SPECTRE_V2_NONE;
+       enum spectre_v2_app2app_mitigation_cmd app2app_cmd;
+       enum spectre_v2_app2app_mitigation app2app_mode;
 
        /*
         * If the CPU is not affected and the command line mode is NONE or AUTO
@@ -452,12 +542,6 @@ static void __init spectre_v2_select_mitigation(void)
        setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
        pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context 
switch\n");
 
-       /* Initialize Indirect Branch Prediction Barrier if supported */
-       if (boot_cpu_has(X86_FEATURE_IBPB)) {
-               setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
-               pr_info("Spectre v2 mitigation: Enabling Indirect Branch 
Prediction Barrier\n");
-       }
-
        /*
         * Retpoline means the kernel is safe because it has no indirect
         * branches. Enhanced IBRS protects firmware too, so, enable restricted
@@ -474,6 +558,43 @@ static void __init spectre_v2_select_mitigation(void)
                pr_info("Enabling Restricted Speculation for firmware calls\n");
        }
 
+       app2app_mode = SPECTRE_V2_APP2APP_NONE;
+       if (!boot_cpu_has(X86_FEATURE_IBPB) ||
+           !boot_cpu_has(X86_FEATURE_STIBP))
+               goto set_app2app_mode;
+
+       app2app_cmd = spectre_v2_parse_app2app_cmdline(cmd);
+
+       switch (app2app_cmd) {
+       case SPECTRE_V2_APP2APP_CMD_NONE:
+               break;
+
+       case SPECTRE_V2_APP2APP_CMD_LITE:
+       case SPECTRE_V2_APP2APP_CMD_AUTO:
+               app2app_mode = SPECTRE_V2_APP2APP_LITE;
+               break;
+
+       case SPECTRE_V2_APP2APP_CMD_STRICT:
+       case SPECTRE_V2_APP2APP_CMD_FORCE:
+               app2app_mode = SPECTRE_V2_APP2APP_STRICT;
+               break;
+       }
+
+       /*
+        * Initialize Indirect Branch Prediction Barrier if supported
+        * and not disabled explicitly
+        */
+       if (app2app_mode != SPECTRE_V2_APP2APP_NONE) {
+               setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
+               pr_info("Spectre v2 mitigation: Enabling Indirect Branch 
Prediction Barrier\n");
+       }
+
+set_app2app_mode:
+       spectre_v2_app2app_enabled = app2app_mode;
+       pr_info("%s\n", spectre_v2_app2app_strings[app2app_mode]);
+       if (app2app_mode == SPECTRE_V2_APP2APP_LITE)
+               static_branch_enable(&spectre_v2_app_lite);
+
        /* Enable STIBP if appropriate */
        arch_smt_update();
 }
@@ -873,21 +994,23 @@ static ssize_t l1tf_show_state(char *buf)
 
 static char *stibp_state(void)
 {
-       if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
+       if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED ||
+           spectre_v2_app2app_enabled == SPECTRE_V2_APP2APP_NONE)
                return "";
-
-       if (x86_spec_ctrl_base & SPEC_CTRL_STIBP)
-               return ", STIBP";
+       else if (spectre_v2_app2app_enabled == SPECTRE_V2_APP2APP_LITE)
+               return ", STIBP-lite";
        else
-               return "";
+               return ", STIBP-strict";
 }
 
 static char *ibpb_state(void)
 {
-       if (boot_cpu_has(X86_FEATURE_USE_IBPB))
-               return ", IBPB";
-       else
+       if (spectre_v2_app2app_enabled == SPECTRE_V2_APP2APP_NONE)
                return "";
+       else if (spectre_v2_app2app_enabled == SPECTRE_V2_APP2APP_LITE)
+               return ", IBPB-lite";
+       else
+               return ", IBPB-strict";
 }
 
 static ssize_t cpu_show_common(struct device *dev, struct device_attribute 
*attr,
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index bddd6b3..9201470 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -184,14 +184,27 @@ static void sync_current_stack_to_mm(struct mm_struct *mm)
 static bool ibpb_needed(struct task_struct *tsk, u64 last_ctx_id)
 {
        /*
-        * Check if the current (previous) task has access to the memory
-        * of the @tsk (next) task. If access is denied, make sure to
-        * issue a IBPB to stop user->user Spectre-v2 attacks.
+        * Don't issue IBPB when switching to kernel threads or staying in the
+        * same mm context.
+        */
+       if (!tsk || !tsk->mm || tsk->mm->context.ctx_id == last_ctx_id)
+               return false;
+
+       /*
+        * If lite protection mode is enabled, check the STIBP thread flag.
+        *
+        * Otherwise check if the current (previous) task has access to the
+        * the memory of the @tsk (next) task for strict app to app protection.
+        * If access is denied, make sure to issue a IBPB to stop user->user
+        * Spectre-v2 attacks.
         *
         * Note: __ptrace_may_access() returns 0 or -ERRNO.
         */
-       return (tsk && tsk->mm && tsk->mm->context.ctx_id != last_ctx_id &&
-               ptrace_may_access_sched(tsk, PTRACE_MODE_SPEC_IBPB));
+
+       if (static_branch_unlikely(&spectre_v2_app_lite))
+               return test_tsk_thread_flag(tsk, TIF_STIBP);
+       else
+               return ptrace_may_access_sched(tsk, PTRACE_MODE_SPEC_IBPB);
 }
 
 void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
-- 
2.9.4

Reply via email to