Blob Blame History Raw
From 7a3d1bf135b9ef3d9c26c5e48e9200efe932b555 Mon Sep 17 00:00:00 2001
From: Artem Savkov <asavkov@redhat.com>
Date: Fri, 19 Jun 2020 11:30:09 +0200
Subject: [KPATCH RHEL-8.2 v4] kpatch adapted patch for CVE-2020-10767 and CVE-2020-10768

Kernels:
4.18.0-193.el8
4.18.0-193.1.2.el8_2
4.18.0-193.6.3.el8_2

Changes since last build:
arches: x86_64
bugs.o: changed function: arch_prctl_spec_ctrl_get
bugs.o: changed function: arch_prctl_spec_ctrl_set
bugs.o: changed function: arch_seccomp_spec_mitigate
bugs.o: changed function: ib_prctl_set.part.1
bugs.o: new function: kpatch_cve_2020_10767_pre_patch_callback
---------------------------

Kernels:
4.18.0-193.el8
4.18.0-193.1.2.el8_2
4.18.0-193.6.3.el8_2

Modifications:
 - Dropped SPECTRE_V2_USER_STRICT_PREFERRED support as it is not a part
   of CVE fix and was only ported for patches to apply cleanly.
 - Added a pre-patch callback that would initialize spectre_v2_user_ibpb
   from scratch, parsing the command line and checking cpu capabilities.
 - spectre_v2_user_stibp is not renamed and is left as spectre_v2_user
   to limit the footprint of the patch.

Testing: reproducer provided by security team

commit eb2ce6c5ce9269a32474955bb0934359801c83fa
Author: Waiman Long <longman@redhat.com>
Date:   Tue Jun 16 19:01:42 2020 -0400

    [x86] x86/speculation: PR_SPEC_FORCE_DISABLE enforcement for indirect branches

    Message-id: <20200616190142.5674-6-longman@redhat.com>
    Patchwork-id: 320367
    Patchwork-instance: patchwork
    O-Subject: [RHEL8.2.z PATCH 5/5] x86/speculation: PR_SPEC_FORCE_DISABLE enforcement for indirect branches.
    Bugzilla: 1847396
    Z-Bugzilla: 1847395
    CVE: CVE-2020-10768
    RH-Acked-by: Rafael Aquini <aquini@redhat.com>
    RH-Acked-by: Phil Auld <pauld@redhat.com>

    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1847395
    CVE: CVE-2020-10768

    commit 4d8df8cbb9156b0a0ab3f802b80cb5db57acc0bf
    Author: Anthony Steinhauser <asteinhauser@google.com>
    Date:   Sun, 7 Jun 2020 05:44:19 -0700

        x86/speculation: PR_SPEC_FORCE_DISABLE enforcement for indirect branches.

        Currently, it is possible to enable indirect branch speculation even after
        it was force-disabled using the PR_SPEC_FORCE_DISABLE option. Moreover, the
        PR_GET_SPECULATION_CTRL command gives afterwards an incorrect result
        (force-disabled when it is in fact enabled). This also is inconsistent
        vs. STIBP and the documention which cleary states that
        PR_SPEC_FORCE_DISABLE cannot be undone.

        Fix this by actually enforcing force-disabled indirect branch
        speculation. PR_SPEC_ENABLE called after PR_SPEC_FORCE_DISABLE now fails
        with -EPERM as described in the documentation.

        Fixes: 9137bb27e60e ("x86/speculation: Add prctl() control for indirect branch speculation")
        Signed-off-by: Anthony Steinhauser <asteinhauser@google.com>
        Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
        Cc: stable@vger.kernel.org

    Signed-off-by: Waiman Long <longman@redhat.com>
    Signed-off-by: Bruno Meneguele <bmeneg@redhat.com>

commit b7620b4e8bfb015bf494d47152751b8f07b5b215
Author: Waiman Long <longman@redhat.com>
Date:   Tue Jun 16 19:01:40 2020 -0400

    [x86] x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced IBRS

    Message-id: <20200616190142.5674-4-longman@redhat.com>
    Patchwork-id: 320366
    Patchwork-instance: patchwork
    O-Subject: [RHEL8.2.z PATCH 3/5] x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced IBRS.
    Bugzilla: 1847379
    Z-Bugzilla: 1847378
    CVE: CVE-2020-10767
    RH-Acked-by: Rafael Aquini <aquini@redhat.com>
    RH-Acked-by: Phil Auld <pauld@redhat.com>

    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1847378
    CVE: CVE-2020-10767
    Conflicts: There is a minor fuzz in bugs.c due to missing the upstream
               commit e4f358916d52 ("x86, modpost: Replace last remnants
               of RETPOLINE with CONFIG_RETPOLINE"). However, backporting
               this commit at this stage will cause unexpected retpoline
               warning when loading 3rd party modules.

    commit 21998a351512eba4ed5969006f0c55882d995ada
    Author: Anthony Steinhauser <asteinhauser@google.com>
    Date:   Tue, 19 May 2020 06:40:42 -0700

        x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced IBRS.

        When STIBP is unavailable or enhanced IBRS is available, Linux
        force-disables the IBPB mitigation of Spectre-BTB even when simultaneous
        multithreading is disabled. While attempts to enable IBPB using
        prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, ...) fail with
        EPERM, the seccomp syscall (or its prctl(PR_SET_SECCOMP, ...) equivalent)
        which are used e.g. by Chromium or OpenSSH succeed with no errors but the
        application remains silently vulnerable to cross-process Spectre v2 attacks
        (classical BTB poisoning). At the same time the SYSFS reporting
        (/sys/devices/system/cpu/vulnerabilities/spectre_v2) displays that IBPB is
        conditionally enabled when in fact it is unconditionally disabled.

        STIBP is useful only when SMT is enabled. When SMT is disabled and STIBP is
        unavailable, it makes no sense to force-disable also IBPB, because IBPB
        protects against cross-process Spectre-BTB attacks regardless of the SMT
        state. At the same time since missing STIBP was only observed on AMD CPUs,
        AMD does not recommend using STIBP, but recommends using IBPB, so disabling
        IBPB because of missing STIBP goes directly against AMD's advice:
        https://developer.amd.com/wp-content/resources/Architecture_Guidelines_Update_Indirect_Branch_Control.pdf

        Similarly, enhanced IBRS is designed to protect cross-core BTB poisoning
        and BTB-poisoning attacks from user space against kernel (and
        BTB-poisoning attacks from guest against hypervisor), it is not designed
        to prevent cross-process (or cross-VM) BTB poisoning between processes (or
        VMs) running on the same core. Therefore, even with enhanced IBRS it is
        necessary to flush the BTB during context-switches, so there is no reason
        to force disable IBPB when enhanced IBRS is available.

        Enable the prctl control of IBPB even when STIBP is unavailable or enhanced
        IBRS is available.

        Fixes: 7cc765a67d8e ("x86/speculation: Enable prctl mode for spectre_v2_user")
        Signed-off-by: Anthony Steinhauser <asteinhauser@google.com>
        Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
        Cc: stable@vger.kernel.org

    Signed-off-by: Waiman Long <longman@redhat.com>
    Signed-off-by: Bruno Meneguele <bmeneg@redhat.com>

Signed-off-by: Artem Savkov <asavkov@redhat.com>
Acked-by: Julien Thierry <jthierry@redhat.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
 arch/x86/kernel/cpu/bugs.c | 158 +++++++++++++++++++++++++++++++++----
 1 file changed, 144 insertions(+), 14 deletions(-)

diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 0316c7a04457..654c9a779caf 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -589,6 +589,9 @@ static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
 static enum spectre_v2_user_mitigation spectre_v2_user __ro_after_init =
 	SPECTRE_V2_USER_NONE;
 
+static enum spectre_v2_user_mitigation spectre_v2_user_ibpb =
+	SPECTRE_V2_USER_NONE;
+
 #ifdef RETPOLINE
 static bool spectre_v2_bad_module;
 
@@ -1291,13 +1294,17 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
 {
 	switch (ctrl) {
 	case PR_SPEC_ENABLE:
-		if (spectre_v2_user == SPECTRE_V2_USER_NONE)
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+		    spectre_v2_user == SPECTRE_V2_USER_NONE)
 			return 0;
 		/*
 		 * Indirect branch speculation is always disabled in strict
-		 * mode.
+		 * mode. It can neither be enabled if it was force-disabled
+		 * by a previous prctl call.
 		 */
-		if (spectre_v2_user == SPECTRE_V2_USER_STRICT)
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
+		    spectre_v2_user == SPECTRE_V2_USER_STRICT ||
+		    task_spec_ib_force_disable(task))
 			return -EPERM;
 		task_clear_spec_ib_disable(task);
 		task_update_spec_tif(task);
@@ -1308,9 +1315,11 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
 		 * Indirect branch speculation is always allowed when
 		 * mitigation is force disabled.
 		 */
-		if (spectre_v2_user == SPECTRE_V2_USER_NONE)
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+		    spectre_v2_user == SPECTRE_V2_USER_NONE)
 			return -EPERM;
-		if (spectre_v2_user == SPECTRE_V2_USER_STRICT)
+		if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
+		    spectre_v2_user == SPECTRE_V2_USER_STRICT)
 			return 0;
 		task_set_spec_ib_disable(task);
 		if (ctrl == PR_SPEC_FORCE_DISABLE)
@@ -1341,7 +1350,8 @@ void arch_seccomp_spec_mitigate(struct task_struct *task)
 {
 	if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP)
 		ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE);
-	if (spectre_v2_user == SPECTRE_V2_USER_SECCOMP)
+	if (spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
+	    spectre_v2_user == SPECTRE_V2_USER_SECCOMP)
 		ib_prctl_set(task, PR_SPEC_FORCE_DISABLE);
 }
 #endif
@@ -1372,21 +1382,23 @@ static int ib_prctl_get(struct task_struct *task)
 	if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
 		return PR_SPEC_NOT_AFFECTED;
 
-	switch (spectre_v2_user) {
-	case SPECTRE_V2_USER_NONE:
+	if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
+	    spectre_v2_user == SPECTRE_V2_USER_NONE)
 		return PR_SPEC_ENABLE;
-	case SPECTRE_V2_USER_PRCTL:
-	case SPECTRE_V2_USER_SECCOMP:
+	else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
+	    spectre_v2_user == SPECTRE_V2_USER_STRICT)
+		return PR_SPEC_DISABLE;
+	else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
+	    spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
+	    spectre_v2_user == SPECTRE_V2_USER_PRCTL ||
+	    spectre_v2_user == SPECTRE_V2_USER_SECCOMP) {
 		if (task_spec_ib_force_disable(task))
 			return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
 		if (task_spec_ib_disable(task))
 			return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
 		return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
-	case SPECTRE_V2_USER_STRICT:
-		return PR_SPEC_DISABLE;
-	default:
+	} else
 		return PR_SPEC_NOT_AFFECTED;
-	}
 }
 
 int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
@@ -1755,3 +1767,121 @@ ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *
 	return cpu_show_common(dev, attr, buf, X86_BUG_SRBDS);
 }
 #endif
+
+static inline bool kpatch_cve_2020_10767_match_option(const char *arg, int arglen, const char *opt)
+{
+	int len = strlen(opt);
+
+	return len == arglen && !strncmp(arg, opt, len);
+}
+
+static enum spectre_v2_mitigation_cmd kpatch_cve_2020_10767_spectre_v2_parse_cmdline(void)
+{
+	enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO;
+	char arg[20];
+	int ret, i;
+
+	if (cmdline_find_option_bool(boot_command_line, "nospectre_v2") ||
+	    cpu_mitigations_off())
+		return SPECTRE_V2_CMD_NONE;
+
+	ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg));
+	if (ret < 0)
+		return SPECTRE_V2_CMD_AUTO;
+
+	for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
+		if (!kpatch_cve_2020_10767_match_option(arg, ret, mitigation_options[i].option))
+			continue;
+		cmd = mitigation_options[i].cmd;
+		break;
+	}
+
+	if (i >= ARRAY_SIZE(mitigation_options)) {
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
+	     cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
+	     cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+	    !IS_ENABLED(CONFIG_RETPOLINE)) {
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD &&
+	    boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+		return SPECTRE_V2_CMD_AUTO;
+	}
+
+	return cmd;
+}
+
+static enum spectre_v2_user_cmd
+kpatch_cve_2020_10767_spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
+{
+	char arg[20];
+	int ret, i;
+
+	switch (v2_cmd) {
+	case SPECTRE_V2_CMD_NONE:
+		return SPECTRE_V2_USER_CMD_NONE;
+	case SPECTRE_V2_CMD_FORCE:
+		return SPECTRE_V2_USER_CMD_FORCE;
+	default:
+		break;
+	}
+
+	ret = cmdline_find_option(boot_command_line, "spectre_v2_user",
+				  arg, sizeof(arg));
+	if (ret < 0)
+		return SPECTRE_V2_USER_CMD_AUTO;
+
+	for (i = 0; i < ARRAY_SIZE(v2_user_options); i++) {
+		if (kpatch_cve_2020_10767_match_option(arg, ret, v2_user_options[i].option)) {
+			return v2_user_options[i].cmd;
+		}
+	}
+
+	return SPECTRE_V2_USER_CMD_AUTO;
+}
+
+static void kpatch_cve_2020_10767_spectre_v2_user_select_mitigation(void)
+{
+	enum spectre_v2_mitigation_cmd v2_cmd = kpatch_cve_2020_10767_spectre_v2_parse_cmdline();
+	enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
+	enum spectre_v2_user_cmd cmd;
+
+	if (!boot_cpu_has(X86_FEATURE_IBPB))
+		return;
+
+	cmd = kpatch_cve_2020_10767_spectre_v2_parse_user_cmdline(v2_cmd);
+	switch (cmd) {
+	case SPECTRE_V2_USER_CMD_NONE:
+		return;
+	case SPECTRE_V2_USER_CMD_FORCE:
+		mode = SPECTRE_V2_USER_STRICT;
+		break;
+	case SPECTRE_V2_USER_CMD_PRCTL:
+	case SPECTRE_V2_USER_CMD_PRCTL_IBPB:
+		mode = SPECTRE_V2_USER_PRCTL;
+		break;
+	case SPECTRE_V2_USER_CMD_AUTO:
+	case SPECTRE_V2_USER_CMD_SECCOMP:
+	case SPECTRE_V2_USER_CMD_SECCOMP_IBPB:
+		if (IS_ENABLED(CONFIG_SECCOMP))
+			mode = SPECTRE_V2_USER_SECCOMP;
+		else
+			mode = SPECTRE_V2_USER_PRCTL;
+		break;
+	}
+
+	spectre_v2_user_ibpb = mode;
+}
+
+#include "kpatch-macros.h"
+
+static int kpatch_cve_2020_10767_pre_patch_callback(struct klp_object *obj)
+{
+	kpatch_cve_2020_10767_spectre_v2_user_select_mitigation();
+	return 0;
+}
+KPATCH_PRE_PATCH_CALLBACK(kpatch_cve_2020_10767_pre_patch_callback);
-- 
2.21.3