mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/2] x86/FPU: FPU sanitization for in-kernel use
@ 2020-06-24 11:46 Borislav Petkov
  2020-06-24 11:46 ` [PATCH v2 1/2] x86/fpu: Reset MXCSR to default in kernel_fpu_begin() Borislav Petkov
  2020-06-24 11:46 ` [PATCH v2 2/2] selftests/fpu: Add an FPU selftest Borislav Petkov
  0 siblings, 2 replies; 6+ messages in thread
From: Borislav Petkov @ 2020-06-24 11:46 UTC (permalink / raw)
  To: X86 ML
  Cc: Andy Lutomirski, Dave Hansen, Nick Desaulniers, Petteri Aimonen, LKML

From: Borislav Petkov <bp@suse.de>

Ok,

here's v2 with build fixes and other review comments addressed.

Thx.

Changelog:
----------

v1:
==

Hi all,

here's a proper submission of the work started by Petteri. I think I've
addressed all the feedback so far. I've added the preparation work for
the test to run, to a script run_test_fpu.sh which does some basic
checks, loads the module and runs the test for 1000 times on all CPUs,
by default. Thought this is a sane default, feel free to prove me wrong
and I'll change it.

Thx.

Petteri Aimonen (2):
  x86/fpu: Reset MXCSR to default in kernel_fpu_begin()
  selftests/fpu: Add an FPU selftest

 arch/x86/include/asm/fpu/internal.h         |  5 ++
 arch/x86/kernel/fpu/core.c                  |  6 ++
 lib/Kconfig.debug                           | 11 +++
 lib/Makefile                                | 24 ++++++
 lib/test_fpu.c                              | 89 +++++++++++++++++++++
 tools/testing/selftests/Makefile            |  1 +
 tools/testing/selftests/fpu/.gitignore      |  2 +
 tools/testing/selftests/fpu/Makefile        |  9 +++
 tools/testing/selftests/fpu/run_test_fpu.sh | 46 +++++++++++
 tools/testing/selftests/fpu/test_fpu.c      | 61 ++++++++++++++
 10 files changed, 254 insertions(+)
 create mode 100644 lib/test_fpu.c
 create mode 100644 tools/testing/selftests/fpu/.gitignore
 create mode 100644 tools/testing/selftests/fpu/Makefile
 create mode 100755 tools/testing/selftests/fpu/run_test_fpu.sh
 create mode 100644 tools/testing/selftests/fpu/test_fpu.c

-- 
2.21.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/2] x86/fpu: Reset MXCSR to default in kernel_fpu_begin()
  2020-06-24 11:46 [PATCH v2 0/2] x86/FPU: FPU sanitization for in-kernel use Borislav Petkov
@ 2020-06-24 11:46 ` Borislav Petkov
  2020-06-29  8:34   ` [tip: x86/fpu] " tip-bot2 for Petteri Aimonen
  2020-06-24 11:46 ` [PATCH v2 2/2] selftests/fpu: Add an FPU selftest Borislav Petkov
  1 sibling, 1 reply; 6+ messages in thread
From: Borislav Petkov @ 2020-06-24 11:46 UTC (permalink / raw)
  To: X86 ML
  Cc: Andy Lutomirski, Dave Hansen, Nick Desaulniers, Petteri Aimonen, LKML

From: Petteri Aimonen <jpa@git.mail.kapsi.fi>

Previously, kernel floating point code would run with the MXCSR control
register value last set by userland code by the thread that was active
on the CPU core just before kernel call. This could affect calculation
results if rounding mode was changed, or a crash if a FPU/SIMD exception
was unmasked.

Restore MXCSR to the kernel's default value.

 [ bp: Carve out from a bigger patch by Petteri, add feature check, add
   FNINIT call too (amluto). ]

Signed-off-by: Petteri Aimonen <jpa@git.mail.kapsi.fi>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=207979
---
 arch/x86/include/asm/fpu/internal.h | 5 +++++
 arch/x86/kernel/fpu/core.c          | 6 ++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
index 42159f45bf9c..845e7481ab77 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -623,6 +623,11 @@ static inline void switch_fpu_finish(struct fpu *new_fpu)
  * MXCSR and XCR definitions:
  */
 
+static inline void ldmxcsr(u32 mxcsr)
+{
+	asm volatile("ldmxcsr %0" :: "m" (mxcsr));
+}
+
 extern unsigned int mxcsr_feature_mask;
 
 #define XCR_XFEATURE_ENABLED_MASK	0x00000000
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index 06c818967bb6..15247b96c6ea 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -101,6 +101,12 @@ void kernel_fpu_begin(void)
 		copy_fpregs_to_fpstate(&current->thread.fpu);
 	}
 	__cpu_invalidate_fpregs_state();
+
+	if (boot_cpu_has(X86_FEATURE_XMM))
+		ldmxcsr(MXCSR_DEFAULT);
+
+	if (boot_cpu_has(X86_FEATURE_FPU))
+		asm volatile ("fninit");
 }
 EXPORT_SYMBOL_GPL(kernel_fpu_begin);
 
-- 
2.21.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 2/2] selftests/fpu: Add an FPU selftest
  2020-06-24 11:46 [PATCH v2 0/2] x86/FPU: FPU sanitization for in-kernel use Borislav Petkov
  2020-06-24 11:46 ` [PATCH v2 1/2] x86/fpu: Reset MXCSR to default in kernel_fpu_begin() Borislav Petkov
@ 2020-06-24 11:46 ` Borislav Petkov
  2020-06-24 17:51   ` Nick Desaulniers
  2020-06-29  8:34   ` [tip: x86/fpu] " tip-bot2 for Petteri Aimonen
  1 sibling, 2 replies; 6+ messages in thread
From: Borislav Petkov @ 2020-06-24 11:46 UTC (permalink / raw)
  To: X86 ML
  Cc: Andy Lutomirski, Dave Hansen, Nick Desaulniers, Petteri Aimonen, LKML

From: Petteri Aimonen <jpa@git.mail.kapsi.fi>

Add a selftest for the usage of FPU code in kernel mode.

Currently only implemented for x86. In the future, kernel FPU testing
could be unified between the different architectures supporting it.

 [ bp:

  - Split out from a conglomerate patch, put comments over statements.
  - run the test only on debugfs write.
  - Add bare-minimum run_test_fpu.sh, run 1000 iterations on all CPUs
    by default.
  - Add conditionally -msse2 so that clang doesn't generate library
    calls.
  - Use cc-option to detect gcc 7.1 not supporting -mpreferred-stack-boundary=3.
  - Document stuff so that we don't forget.
 ]

Signed-off-by: Petteri Aimonen <jpa@git.mail.kapsi.fi>
Signed-off-by: Borislav Petkov <bp@suse.de>
---
 lib/Kconfig.debug                           | 11 +++
 lib/Makefile                                | 24 ++++++
 lib/test_fpu.c                              | 89 +++++++++++++++++++++
 tools/testing/selftests/Makefile            |  1 +
 tools/testing/selftests/fpu/.gitignore      |  2 +
 tools/testing/selftests/fpu/Makefile        |  9 +++
 tools/testing/selftests/fpu/run_test_fpu.sh | 46 +++++++++++
 tools/testing/selftests/fpu/test_fpu.c      | 61 ++++++++++++++
 8 files changed, 243 insertions(+)
 create mode 100644 lib/test_fpu.c
 create mode 100644 tools/testing/selftests/fpu/.gitignore
 create mode 100644 tools/testing/selftests/fpu/Makefile
 create mode 100755 tools/testing/selftests/fpu/run_test_fpu.sh
 create mode 100644 tools/testing/selftests/fpu/test_fpu.c

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d74ac0fd6b2d..a1963a493920 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2308,6 +2308,17 @@ config TEST_HMM
 
 	  If unsure, say N.
 
+config TEST_FPU
+	tristate "Test floating point operations in kernel space"
+	depends on X86
+	help
+	  Enable this option to add /sys/kernel/debug/selftest_helpers/test_fpu
+	  which will trigger a sequence of floating point operations. This is used
+	  for self-testing floating point control register setting in
+	  kernel_fpu_begin().
+
+	  If unsure, say N.
+
 endif # RUNTIME_TESTING_MENU
 
 config MEMTEST
diff --git a/lib/Makefile b/lib/Makefile
index b1c42c10073b..d0f17a74afaf 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -99,6 +99,30 @@ obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
 obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o
 obj-$(CONFIG_TEST_HMM) += test_hmm.o
 
+#
+# CFLAGS for compiling floating point code inside the kernel. x86/Makefile turns
+# off the generation of FPU/SSE* instructions for kernel proper but FPU_FLAGS
+# get appended last to CFLAGS and thus override those previous compiler options.
+#
+FPU_CFLAGS := -mhard-float -msse -msse2
+ifdef CONFIG_CC_IS_GCC
+# Stack alignment mismatch, proceed with caution.
+# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
+# (8B stack alignment).
+# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53383
+#
+# The "-msse" in the first argument is there so that the
+# -mpreferred-stack-boundary=3 build error:
+#
+#  -mpreferred-stack-boundary=3 is not between 4 and 12
+#
+# can be triggered. Otherwise gcc doesn't complain.
+FPU_CFLAGS += $(call cc-option,-msse -mpreferred-stack-boundary=3,-mpreferred-stack-boundary=4)
+endif
+
+obj-$(CONFIG_TEST_FPU) += test_fpu.o
+CFLAGS_test_fpu.o += $(FPU_CFLAGS)
+
 obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
 
 obj-$(CONFIG_KUNIT) += kunit/
diff --git a/lib/test_fpu.c b/lib/test_fpu.c
new file mode 100644
index 000000000000..c33764aa3eb8
--- /dev/null
+++ b/lib/test_fpu.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test cases for using floating point operations inside a kernel module.
+ *
+ * This tests kernel_fpu_begin() and kernel_fpu_end() functions, especially
+ * when userland has modified the floating point control registers. The kernel
+ * state might depend on the state set by the userland thread that was active
+ * before a syscall.
+ *
+ * To facilitate the test, this module registers file
+ * /sys/kernel/debug/selftest_helpers/test_fpu, which when read causes a
+ * sequence of floating point operations. If the operations fail, either the
+ * read returns error status or the kernel crashes.
+ * If the operations succeed, the read returns "1\n".
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <asm/fpu/api.h>
+
+static int test_fpu(void)
+{
+	/*
+	 * This sequence of operations tests that rounding mode is
+	 * to nearest and that denormal numbers are supported.
+	 * Volatile variables are used to avoid compiler optimizing
+	 * the calculations away.
+	 */
+	volatile double a, b, c, d, e, f, g;
+
+	a = 4.0;
+	b = 1e-15;
+	c = 1e-310;
+
+	/* Sets precision flag */
+	d = a + b;
+
+	/* Result depends on rounding mode */
+	e = a + b / 2;
+
+	/* Denormal and very large values */
+	f = b / c;
+
+	/* Depends on denormal support */
+	g = a + c * f;
+
+	if (d > a && e > a && g > a)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int test_fpu_get(void *data, u64 *val)
+{
+	int status = -EINVAL;
+
+	kernel_fpu_begin();
+	status = test_fpu();
+	kernel_fpu_end();
+
+	*val = 1;
+	return status;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(test_fpu_fops, test_fpu_get, NULL, "%lld\n");
+static struct dentry *selftest_dir;
+
+static int __init test_fpu_init(void)
+{
+	selftest_dir = debugfs_create_dir("selftest_helpers", NULL);
+	if (!selftest_dir)
+		return -ENOMEM;
+
+	debugfs_create_file("test_fpu", 0444, selftest_dir, NULL,
+			    &test_fpu_fops);
+
+	return 0;
+}
+
+static void __exit test_fpu_exit(void)
+{
+	debugfs_remove(selftest_dir);
+}
+
+module_init(test_fpu_init);
+module_exit(test_fpu_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 1195bd85af38..227ca78a5b7f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -15,6 +15,7 @@ TARGETS += filesystems
 TARGETS += filesystems/binderfs
 TARGETS += filesystems/epoll
 TARGETS += firmware
+TARGETS += fpu
 TARGETS += ftrace
 TARGETS += futex
 TARGETS += gpio
diff --git a/tools/testing/selftests/fpu/.gitignore b/tools/testing/selftests/fpu/.gitignore
new file mode 100644
index 000000000000..d6d12ac1d9c3
--- /dev/null
+++ b/tools/testing/selftests/fpu/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0+
+test_fpu
diff --git a/tools/testing/selftests/fpu/Makefile b/tools/testing/selftests/fpu/Makefile
new file mode 100644
index 000000000000..ea62c176ede7
--- /dev/null
+++ b/tools/testing/selftests/fpu/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+LDLIBS := -lm
+
+TEST_GEN_PROGS := test_fpu
+
+TEST_PROGS := run_test_fpu.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/fpu/run_test_fpu.sh b/tools/testing/selftests/fpu/run_test_fpu.sh
new file mode 100755
index 000000000000..d77be93ec139
--- /dev/null
+++ b/tools/testing/selftests/fpu/run_test_fpu.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Load kernel module for FPU tests
+
+uid=$(id -u)
+if [ $uid -ne 0 ]; then
+	echo "$0: Must be run as root"
+	exit 1
+fi
+
+if ! which modprobe > /dev/null 2>&1; then
+	echo "$0: You need modprobe installed"
+        exit 4
+fi
+
+if ! modinfo test_fpu > /dev/null 2>&1; then
+	echo "$0: You must have the following enabled in your kernel:"
+	echo "CONFIG_TEST_FPU=m"
+	exit 4
+fi
+
+NR_CPUS=$(getconf _NPROCESSORS_ONLN)
+if [ ! $NR_CPUS ]; then
+	NR_CPUS=1
+fi
+
+modprobe test_fpu
+
+if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then
+	mount -t debugfs none /sys/kernel/debug
+
+	if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then
+		echo "$0: Error mounting debugfs"
+		exit 4
+	fi
+fi
+
+echo "Running 1000 iterations on all CPUs... "
+for i in $(seq 1 1000); do
+	for c in $(seq 1 $NR_CPUS); do
+		./test_fpu &
+	done
+done
+
+rmmod test_fpu
diff --git a/tools/testing/selftests/fpu/test_fpu.c b/tools/testing/selftests/fpu/test_fpu.c
new file mode 100644
index 000000000000..200238522a9d
--- /dev/null
+++ b/tools/testing/selftests/fpu/test_fpu.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* This testcase operates with the test_fpu kernel driver.
+ * It modifies the FPU control register in user mode and calls the kernel
+ * module to perform floating point operations in the kernel. The control
+ * register value should be independent between kernel and user mode.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fenv.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+const char *test_fpu_path = "/sys/kernel/debug/selftest_helpers/test_fpu";
+
+int main(void)
+{
+	char dummy[1];
+	int fd = open(test_fpu_path, O_RDONLY);
+
+	if (fd < 0) {
+		printf("[SKIP]\tcan't access %s: %s\n",
+		       test_fpu_path, strerror(errno));
+		return 0;
+	}
+
+	if (read(fd, dummy, 1) < 0) {
+		printf("[FAIL]\taccess with default rounding mode failed\n");
+		return 1;
+	}
+
+	fesetround(FE_DOWNWARD);
+	if (read(fd, dummy, 1) < 0) {
+		printf("[FAIL]\taccess with downward rounding mode failed\n");
+		return 2;
+	}
+	if (fegetround() != FE_DOWNWARD) {
+		printf("[FAIL]\tusermode rounding mode clobbered\n");
+		return 3;
+	}
+
+	/* Note: the tests up to this point are quite safe and will only return
+	 * an error. But the exception mask setting can cause misbehaving kernel
+	 * to crash.
+	 */
+	feclearexcept(FE_ALL_EXCEPT);
+	feenableexcept(FE_ALL_EXCEPT);
+	if (read(fd, dummy, 1) < 0) {
+		printf("[FAIL]\taccess with fpu exceptions unmasked failed\n");
+		return 4;
+	}
+	if (fegetexcept() != FE_ALL_EXCEPT) {
+		printf("[FAIL]\tusermode fpu exception mask clobbered\n");
+		return 5;
+	}
+
+	printf("[OK]\ttest_fpu\n");
+	return 0;
+}
-- 
2.21.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 2/2] selftests/fpu: Add an FPU selftest
  2020-06-24 11:46 ` [PATCH v2 2/2] selftests/fpu: Add an FPU selftest Borislav Petkov
@ 2020-06-24 17:51   ` Nick Desaulniers
  2020-06-29  8:34   ` [tip: x86/fpu] " tip-bot2 for Petteri Aimonen
  1 sibling, 0 replies; 6+ messages in thread
From: Nick Desaulniers @ 2020-06-24 17:51 UTC (permalink / raw)
  To: Borislav Petkov, Petteri Aimonen
  Cc: X86 ML, Andy Lutomirski, Dave Hansen, LKML

On Wed, Jun 24, 2020 at 4:46 AM Borislav Petkov <bp@alien8.de> wrote:
>
> From: Petteri Aimonen <jpa@git.mail.kapsi.fi>
>
> Add a selftest for the usage of FPU code in kernel mode.
>
> Currently only implemented for x86. In the future, kernel FPU testing
> could be unified between the different architectures supporting it.
>
>  [ bp:
>
>   - Split out from a conglomerate patch, put comments over statements.
>   - run the test only on debugfs write.
>   - Add bare-minimum run_test_fpu.sh, run 1000 iterations on all CPUs
>     by default.
>   - Add conditionally -msse2 so that clang doesn't generate library
>     calls.
>   - Use cc-option to detect gcc 7.1 not supporting -mpreferred-stack-boundary=3.
>   - Document stuff so that we don't forget.
>  ]
>
> Signed-off-by: Petteri Aimonen <jpa@git.mail.kapsi.fi>
> Signed-off-by: Borislav Petkov <bp@suse.de>

More tests make me happy.  Thanks for taking the time to write all
this.  In the future, it should be straightforward for us to test
single precision in test_fpu().  Exercising anything that would
otherwise generate a soft-fp call might be interesting
https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html
(plz no `long double`).
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>

> ---
>  lib/Kconfig.debug                           | 11 +++
>  lib/Makefile                                | 24 ++++++
>  lib/test_fpu.c                              | 89 +++++++++++++++++++++
>  tools/testing/selftests/Makefile            |  1 +
>  tools/testing/selftests/fpu/.gitignore      |  2 +
>  tools/testing/selftests/fpu/Makefile        |  9 +++
>  tools/testing/selftests/fpu/run_test_fpu.sh | 46 +++++++++++
>  tools/testing/selftests/fpu/test_fpu.c      | 61 ++++++++++++++
>  8 files changed, 243 insertions(+)
>  create mode 100644 lib/test_fpu.c
>  create mode 100644 tools/testing/selftests/fpu/.gitignore
>  create mode 100644 tools/testing/selftests/fpu/Makefile
>  create mode 100755 tools/testing/selftests/fpu/run_test_fpu.sh
>  create mode 100644 tools/testing/selftests/fpu/test_fpu.c
>
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index d74ac0fd6b2d..a1963a493920 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2308,6 +2308,17 @@ config TEST_HMM
>
>           If unsure, say N.
>
> +config TEST_FPU
> +       tristate "Test floating point operations in kernel space"
> +       depends on X86
> +       help
> +         Enable this option to add /sys/kernel/debug/selftest_helpers/test_fpu
> +         which will trigger a sequence of floating point operations. This is used
> +         for self-testing floating point control register setting in
> +         kernel_fpu_begin().
> +
> +         If unsure, say N.
> +
>  endif # RUNTIME_TESTING_MENU
>
>  config MEMTEST
> diff --git a/lib/Makefile b/lib/Makefile
> index b1c42c10073b..d0f17a74afaf 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -99,6 +99,30 @@ obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
>  obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o
>  obj-$(CONFIG_TEST_HMM) += test_hmm.o
>
> +#
> +# CFLAGS for compiling floating point code inside the kernel. x86/Makefile turns
> +# off the generation of FPU/SSE* instructions for kernel proper but FPU_FLAGS
> +# get appended last to CFLAGS and thus override those previous compiler options.
> +#
> +FPU_CFLAGS := -mhard-float -msse -msse2
> +ifdef CONFIG_CC_IS_GCC
> +# Stack alignment mismatch, proceed with caution.
> +# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
> +# (8B stack alignment).
> +# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53383
> +#
> +# The "-msse" in the first argument is there so that the
> +# -mpreferred-stack-boundary=3 build error:
> +#
> +#  -mpreferred-stack-boundary=3 is not between 4 and 12
> +#
> +# can be triggered. Otherwise gcc doesn't complain.
> +FPU_CFLAGS += $(call cc-option,-msse -mpreferred-stack-boundary=3,-mpreferred-stack-boundary=4)
> +endif
> +
> +obj-$(CONFIG_TEST_FPU) += test_fpu.o
> +CFLAGS_test_fpu.o += $(FPU_CFLAGS)
> +
>  obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
>
>  obj-$(CONFIG_KUNIT) += kunit/
> diff --git a/lib/test_fpu.c b/lib/test_fpu.c
> new file mode 100644
> index 000000000000..c33764aa3eb8
> --- /dev/null
> +++ b/lib/test_fpu.c
> @@ -0,0 +1,89 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Test cases for using floating point operations inside a kernel module.
> + *
> + * This tests kernel_fpu_begin() and kernel_fpu_end() functions, especially
> + * when userland has modified the floating point control registers. The kernel
> + * state might depend on the state set by the userland thread that was active
> + * before a syscall.
> + *
> + * To facilitate the test, this module registers file
> + * /sys/kernel/debug/selftest_helpers/test_fpu, which when read causes a
> + * sequence of floating point operations. If the operations fail, either the
> + * read returns error status or the kernel crashes.
> + * If the operations succeed, the read returns "1\n".
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/debugfs.h>
> +#include <asm/fpu/api.h>
> +
> +static int test_fpu(void)
> +{
> +       /*
> +        * This sequence of operations tests that rounding mode is
> +        * to nearest and that denormal numbers are supported.
> +        * Volatile variables are used to avoid compiler optimizing
> +        * the calculations away.
> +        */
> +       volatile double a, b, c, d, e, f, g;
> +
> +       a = 4.0;
> +       b = 1e-15;
> +       c = 1e-310;
> +
> +       /* Sets precision flag */
> +       d = a + b;
> +
> +       /* Result depends on rounding mode */
> +       e = a + b / 2;
> +
> +       /* Denormal and very large values */
> +       f = b / c;
> +
> +       /* Depends on denormal support */
> +       g = a + c * f;
> +
> +       if (d > a && e > a && g > a)
> +               return 0;
> +       else
> +               return -EINVAL;
> +}
> +
> +static int test_fpu_get(void *data, u64 *val)
> +{
> +       int status = -EINVAL;
> +
> +       kernel_fpu_begin();
> +       status = test_fpu();
> +       kernel_fpu_end();
> +
> +       *val = 1;
> +       return status;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE(test_fpu_fops, test_fpu_get, NULL, "%lld\n");
> +static struct dentry *selftest_dir;
> +
> +static int __init test_fpu_init(void)
> +{
> +       selftest_dir = debugfs_create_dir("selftest_helpers", NULL);
> +       if (!selftest_dir)
> +               return -ENOMEM;
> +
> +       debugfs_create_file("test_fpu", 0444, selftest_dir, NULL,
> +                           &test_fpu_fops);
> +
> +       return 0;
> +}
> +
> +static void __exit test_fpu_exit(void)
> +{
> +       debugfs_remove(selftest_dir);
> +}
> +
> +module_init(test_fpu_init);
> +module_exit(test_fpu_exit);
> +
> +MODULE_LICENSE("GPL");
> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> index 1195bd85af38..227ca78a5b7f 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -15,6 +15,7 @@ TARGETS += filesystems
>  TARGETS += filesystems/binderfs
>  TARGETS += filesystems/epoll
>  TARGETS += firmware
> +TARGETS += fpu
>  TARGETS += ftrace
>  TARGETS += futex
>  TARGETS += gpio
> diff --git a/tools/testing/selftests/fpu/.gitignore b/tools/testing/selftests/fpu/.gitignore
> new file mode 100644
> index 000000000000..d6d12ac1d9c3
> --- /dev/null
> +++ b/tools/testing/selftests/fpu/.gitignore
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +test_fpu
> diff --git a/tools/testing/selftests/fpu/Makefile b/tools/testing/selftests/fpu/Makefile
> new file mode 100644
> index 000000000000..ea62c176ede7
> --- /dev/null
> +++ b/tools/testing/selftests/fpu/Makefile
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +
> +LDLIBS := -lm
> +
> +TEST_GEN_PROGS := test_fpu
> +
> +TEST_PROGS := run_test_fpu.sh
> +
> +include ../lib.mk
> diff --git a/tools/testing/selftests/fpu/run_test_fpu.sh b/tools/testing/selftests/fpu/run_test_fpu.sh
> new file mode 100755
> index 000000000000..d77be93ec139
> --- /dev/null
> +++ b/tools/testing/selftests/fpu/run_test_fpu.sh
> @@ -0,0 +1,46 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Load kernel module for FPU tests
> +
> +uid=$(id -u)
> +if [ $uid -ne 0 ]; then
> +       echo "$0: Must be run as root"
> +       exit 1
> +fi
> +
> +if ! which modprobe > /dev/null 2>&1; then
> +       echo "$0: You need modprobe installed"
> +        exit 4
> +fi
> +
> +if ! modinfo test_fpu > /dev/null 2>&1; then
> +       echo "$0: You must have the following enabled in your kernel:"
> +       echo "CONFIG_TEST_FPU=m"
> +       exit 4
> +fi
> +
> +NR_CPUS=$(getconf _NPROCESSORS_ONLN)
> +if [ ! $NR_CPUS ]; then
> +       NR_CPUS=1
> +fi
> +
> +modprobe test_fpu
> +
> +if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then
> +       mount -t debugfs none /sys/kernel/debug
> +
> +       if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then
> +               echo "$0: Error mounting debugfs"
> +               exit 4
> +       fi
> +fi
> +
> +echo "Running 1000 iterations on all CPUs... "
> +for i in $(seq 1 1000); do
> +       for c in $(seq 1 $NR_CPUS); do
> +               ./test_fpu &
> +       done
> +done
> +
> +rmmod test_fpu
> diff --git a/tools/testing/selftests/fpu/test_fpu.c b/tools/testing/selftests/fpu/test_fpu.c
> new file mode 100644
> index 000000000000..200238522a9d
> --- /dev/null
> +++ b/tools/testing/selftests/fpu/test_fpu.c
> @@ -0,0 +1,61 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* This testcase operates with the test_fpu kernel driver.
> + * It modifies the FPU control register in user mode and calls the kernel
> + * module to perform floating point operations in the kernel. The control
> + * register value should be independent between kernel and user mode.
> + */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <fenv.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +
> +const char *test_fpu_path = "/sys/kernel/debug/selftest_helpers/test_fpu";
> +
> +int main(void)
> +{
> +       char dummy[1];
> +       int fd = open(test_fpu_path, O_RDONLY);
> +
> +       if (fd < 0) {
> +               printf("[SKIP]\tcan't access %s: %s\n",
> +                      test_fpu_path, strerror(errno));
> +               return 0;
> +       }
> +
> +       if (read(fd, dummy, 1) < 0) {
> +               printf("[FAIL]\taccess with default rounding mode failed\n");
> +               return 1;
> +       }
> +
> +       fesetround(FE_DOWNWARD);
> +       if (read(fd, dummy, 1) < 0) {
> +               printf("[FAIL]\taccess with downward rounding mode failed\n");
> +               return 2;
> +       }
> +       if (fegetround() != FE_DOWNWARD) {
> +               printf("[FAIL]\tusermode rounding mode clobbered\n");
> +               return 3;
> +       }
> +
> +       /* Note: the tests up to this point are quite safe and will only return
> +        * an error. But the exception mask setting can cause misbehaving kernel
> +        * to crash.
> +        */
> +       feclearexcept(FE_ALL_EXCEPT);
> +       feenableexcept(FE_ALL_EXCEPT);
> +       if (read(fd, dummy, 1) < 0) {
> +               printf("[FAIL]\taccess with fpu exceptions unmasked failed\n");
> +               return 4;
> +       }
> +       if (fegetexcept() != FE_ALL_EXCEPT) {
> +               printf("[FAIL]\tusermode fpu exception mask clobbered\n");
> +               return 5;
> +       }
> +
> +       printf("[OK]\ttest_fpu\n");
> +       return 0;
> +}
> --
> 2.21.0
>


-- 
Thanks,
~Nick Desaulniers

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [tip: x86/fpu] selftests/fpu: Add an FPU selftest
  2020-06-24 11:46 ` [PATCH v2 2/2] selftests/fpu: Add an FPU selftest Borislav Petkov
  2020-06-24 17:51   ` Nick Desaulniers
@ 2020-06-29  8:34   ` tip-bot2 for Petteri Aimonen
  1 sibling, 0 replies; 6+ messages in thread
From: tip-bot2 for Petteri Aimonen @ 2020-06-29  8:34 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: kernel test robot, Petteri Aimonen, Borislav Petkov,
	Nick Desaulniers, x86, LKML

The following commit has been merged into the x86/fpu branch of tip:

Commit-ID:     4185b3b92792eaec5869266e594338343421ffb0
Gitweb:        https://git.kernel.org/tip/4185b3b92792eaec5869266e594338343421ffb0
Author:        Petteri Aimonen <jpa@git.mail.kapsi.fi>
AuthorDate:    Thu, 18 Jun 2020 16:37:37 +02:00
Committer:     Borislav Petkov <bp@suse.de>
CommitterDate: Mon, 29 Jun 2020 10:02:23 +02:00

selftests/fpu: Add an FPU selftest

Add a selftest for the usage of FPU code in kernel mode.

Currently only implemented for x86. In the future, kernel FPU testing
could be unified between the different architectures supporting it.

 [ bp:

  - Split out from a conglomerate patch, put comments over statements.
  - run the test only on debugfs write.
  - Add bare-minimum run_test_fpu.sh, run 1000 iterations on all CPUs
    by default.
  - Add conditionally -msse2 so that clang doesn't generate library
    calls.
  - Use cc-option to detect gcc 7.1 not supporting -mpreferred-stack-boundary=3 (amluto).
  - Document stuff so that we don't forget.
  - Fix:
     ld: lib/test_fpu.o: in function `test_fpu_get':
     >> test_fpu.c:(.text+0x16e): undefined reference to `__sanitizer_cov_trace_cmpd'
     >> ld: test_fpu.c:(.text+0x1a7): undefined reference to `__sanitizer_cov_trace_cmpd'
     ld: test_fpu.c:(.text+0x1e0): undefined reference to `__sanitizer_cov_trace_cmpd'
  ]

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Petteri Aimonen <jpa@git.mail.kapsi.fi>
Signed-off-by: Borislav Petkov <bp@suse.de>
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Link: https://lkml.kernel.org/r/20200624114646.28953-3-bp@alien8.de
---
 lib/Kconfig.debug                           | 11 ++-
 lib/Makefile                                | 24 +++++-
 lib/test_fpu.c                              | 89 ++++++++++++++++++++-
 tools/testing/selftests/Makefile            |  1 +-
 tools/testing/selftests/fpu/.gitignore      |  2 +-
 tools/testing/selftests/fpu/Makefile        |  9 ++-
 tools/testing/selftests/fpu/run_test_fpu.sh | 46 ++++++++++-
 tools/testing/selftests/fpu/test_fpu.c      | 61 ++++++++++++++-
 8 files changed, 243 insertions(+)
 create mode 100644 lib/test_fpu.c
 create mode 100644 tools/testing/selftests/fpu/.gitignore
 create mode 100644 tools/testing/selftests/fpu/Makefile
 create mode 100755 tools/testing/selftests/fpu/run_test_fpu.sh
 create mode 100644 tools/testing/selftests/fpu/test_fpu.c

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 9ad9210..5842885 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2307,6 +2307,17 @@ config TEST_HMM
 
 	  If unsure, say N.
 
+config TEST_FPU
+	tristate "Test floating point operations in kernel space"
+	depends on X86 && !KCOV_INSTRUMENT_ALL
+	help
+	  Enable this option to add /sys/kernel/debug/selftest_helpers/test_fpu
+	  which will trigger a sequence of floating point operations. This is used
+	  for self-testing floating point control register setting in
+	  kernel_fpu_begin().
+
+	  If unsure, say N.
+
 endif # RUNTIME_TESTING_MENU
 
 config MEMTEST
diff --git a/lib/Makefile b/lib/Makefile
index b1c42c1..d0f17a7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -99,6 +99,30 @@ obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
 obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o
 obj-$(CONFIG_TEST_HMM) += test_hmm.o
 
+#
+# CFLAGS for compiling floating point code inside the kernel. x86/Makefile turns
+# off the generation of FPU/SSE* instructions for kernel proper but FPU_FLAGS
+# get appended last to CFLAGS and thus override those previous compiler options.
+#
+FPU_CFLAGS := -mhard-float -msse -msse2
+ifdef CONFIG_CC_IS_GCC
+# Stack alignment mismatch, proceed with caution.
+# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
+# (8B stack alignment).
+# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53383
+#
+# The "-msse" in the first argument is there so that the
+# -mpreferred-stack-boundary=3 build error:
+#
+#  -mpreferred-stack-boundary=3 is not between 4 and 12
+#
+# can be triggered. Otherwise gcc doesn't complain.
+FPU_CFLAGS += $(call cc-option,-msse -mpreferred-stack-boundary=3,-mpreferred-stack-boundary=4)
+endif
+
+obj-$(CONFIG_TEST_FPU) += test_fpu.o
+CFLAGS_test_fpu.o += $(FPU_CFLAGS)
+
 obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
 
 obj-$(CONFIG_KUNIT) += kunit/
diff --git a/lib/test_fpu.c b/lib/test_fpu.c
new file mode 100644
index 0000000..c33764a
--- /dev/null
+++ b/lib/test_fpu.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test cases for using floating point operations inside a kernel module.
+ *
+ * This tests kernel_fpu_begin() and kernel_fpu_end() functions, especially
+ * when userland has modified the floating point control registers. The kernel
+ * state might depend on the state set by the userland thread that was active
+ * before a syscall.
+ *
+ * To facilitate the test, this module registers file
+ * /sys/kernel/debug/selftest_helpers/test_fpu, which when read causes a
+ * sequence of floating point operations. If the operations fail, either the
+ * read returns error status or the kernel crashes.
+ * If the operations succeed, the read returns "1\n".
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <asm/fpu/api.h>
+
+static int test_fpu(void)
+{
+	/*
+	 * This sequence of operations tests that rounding mode is
+	 * to nearest and that denormal numbers are supported.
+	 * Volatile variables are used to avoid compiler optimizing
+	 * the calculations away.
+	 */
+	volatile double a, b, c, d, e, f, g;
+
+	a = 4.0;
+	b = 1e-15;
+	c = 1e-310;
+
+	/* Sets precision flag */
+	d = a + b;
+
+	/* Result depends on rounding mode */
+	e = a + b / 2;
+
+	/* Denormal and very large values */
+	f = b / c;
+
+	/* Depends on denormal support */
+	g = a + c * f;
+
+	if (d > a && e > a && g > a)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int test_fpu_get(void *data, u64 *val)
+{
+	int status = -EINVAL;
+
+	kernel_fpu_begin();
+	status = test_fpu();
+	kernel_fpu_end();
+
+	*val = 1;
+	return status;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(test_fpu_fops, test_fpu_get, NULL, "%lld\n");
+static struct dentry *selftest_dir;
+
+static int __init test_fpu_init(void)
+{
+	selftest_dir = debugfs_create_dir("selftest_helpers", NULL);
+	if (!selftest_dir)
+		return -ENOMEM;
+
+	debugfs_create_file("test_fpu", 0444, selftest_dir, NULL,
+			    &test_fpu_fops);
+
+	return 0;
+}
+
+static void __exit test_fpu_exit(void)
+{
+	debugfs_remove(selftest_dir);
+}
+
+module_init(test_fpu_init);
+module_exit(test_fpu_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 1195bd8..227ca78 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -15,6 +15,7 @@ TARGETS += filesystems
 TARGETS += filesystems/binderfs
 TARGETS += filesystems/epoll
 TARGETS += firmware
+TARGETS += fpu
 TARGETS += ftrace
 TARGETS += futex
 TARGETS += gpio
diff --git a/tools/testing/selftests/fpu/.gitignore b/tools/testing/selftests/fpu/.gitignore
new file mode 100644
index 0000000..d6d12ac
--- /dev/null
+++ b/tools/testing/selftests/fpu/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0+
+test_fpu
diff --git a/tools/testing/selftests/fpu/Makefile b/tools/testing/selftests/fpu/Makefile
new file mode 100644
index 0000000..ea62c17
--- /dev/null
+++ b/tools/testing/selftests/fpu/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+LDLIBS := -lm
+
+TEST_GEN_PROGS := test_fpu
+
+TEST_PROGS := run_test_fpu.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/fpu/run_test_fpu.sh b/tools/testing/selftests/fpu/run_test_fpu.sh
new file mode 100755
index 0000000..d77be93
--- /dev/null
+++ b/tools/testing/selftests/fpu/run_test_fpu.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Load kernel module for FPU tests
+
+uid=$(id -u)
+if [ $uid -ne 0 ]; then
+	echo "$0: Must be run as root"
+	exit 1
+fi
+
+if ! which modprobe > /dev/null 2>&1; then
+	echo "$0: You need modprobe installed"
+        exit 4
+fi
+
+if ! modinfo test_fpu > /dev/null 2>&1; then
+	echo "$0: You must have the following enabled in your kernel:"
+	echo "CONFIG_TEST_FPU=m"
+	exit 4
+fi
+
+NR_CPUS=$(getconf _NPROCESSORS_ONLN)
+if [ ! $NR_CPUS ]; then
+	NR_CPUS=1
+fi
+
+modprobe test_fpu
+
+if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then
+	mount -t debugfs none /sys/kernel/debug
+
+	if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then
+		echo "$0: Error mounting debugfs"
+		exit 4
+	fi
+fi
+
+echo "Running 1000 iterations on all CPUs... "
+for i in $(seq 1 1000); do
+	for c in $(seq 1 $NR_CPUS); do
+		./test_fpu &
+	done
+done
+
+rmmod test_fpu
diff --git a/tools/testing/selftests/fpu/test_fpu.c b/tools/testing/selftests/fpu/test_fpu.c
new file mode 100644
index 0000000..2002385
--- /dev/null
+++ b/tools/testing/selftests/fpu/test_fpu.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* This testcase operates with the test_fpu kernel driver.
+ * It modifies the FPU control register in user mode and calls the kernel
+ * module to perform floating point operations in the kernel. The control
+ * register value should be independent between kernel and user mode.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fenv.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+const char *test_fpu_path = "/sys/kernel/debug/selftest_helpers/test_fpu";
+
+int main(void)
+{
+	char dummy[1];
+	int fd = open(test_fpu_path, O_RDONLY);
+
+	if (fd < 0) {
+		printf("[SKIP]\tcan't access %s: %s\n",
+		       test_fpu_path, strerror(errno));
+		return 0;
+	}
+
+	if (read(fd, dummy, 1) < 0) {
+		printf("[FAIL]\taccess with default rounding mode failed\n");
+		return 1;
+	}
+
+	fesetround(FE_DOWNWARD);
+	if (read(fd, dummy, 1) < 0) {
+		printf("[FAIL]\taccess with downward rounding mode failed\n");
+		return 2;
+	}
+	if (fegetround() != FE_DOWNWARD) {
+		printf("[FAIL]\tusermode rounding mode clobbered\n");
+		return 3;
+	}
+
+	/* Note: the tests up to this point are quite safe and will only return
+	 * an error. But the exception mask setting can cause misbehaving kernel
+	 * to crash.
+	 */
+	feclearexcept(FE_ALL_EXCEPT);
+	feenableexcept(FE_ALL_EXCEPT);
+	if (read(fd, dummy, 1) < 0) {
+		printf("[FAIL]\taccess with fpu exceptions unmasked failed\n");
+		return 4;
+	}
+	if (fegetexcept() != FE_ALL_EXCEPT) {
+		printf("[FAIL]\tusermode fpu exception mask clobbered\n");
+		return 5;
+	}
+
+	printf("[OK]\ttest_fpu\n");
+	return 0;
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [tip: x86/fpu] x86/fpu: Reset MXCSR to default in kernel_fpu_begin()
  2020-06-24 11:46 ` [PATCH v2 1/2] x86/fpu: Reset MXCSR to default in kernel_fpu_begin() Borislav Petkov
@ 2020-06-29  8:34   ` tip-bot2 for Petteri Aimonen
  0 siblings, 0 replies; 6+ messages in thread
From: tip-bot2 for Petteri Aimonen @ 2020-06-29  8:34 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: Petteri Aimonen, Borislav Petkov, x86, LKML

The following commit has been merged into the x86/fpu branch of tip:

Commit-ID:     7ad816762f9bf89e940e618ea40c43138b479e10
Gitweb:        https://git.kernel.org/tip/7ad816762f9bf89e940e618ea40c43138b479e10
Author:        Petteri Aimonen <jpa@git.mail.kapsi.fi>
AuthorDate:    Tue, 16 Jun 2020 11:12:57 +02:00
Committer:     Borislav Petkov <bp@suse.de>
CommitterDate: Mon, 29 Jun 2020 10:02:00 +02:00

x86/fpu: Reset MXCSR to default in kernel_fpu_begin()

Previously, kernel floating point code would run with the MXCSR control
register value last set by userland code by the thread that was active
on the CPU core just before kernel call. This could affect calculation
results if rounding mode was changed, or a crash if a FPU/SIMD exception
was unmasked.

Restore MXCSR to the kernel's default value.

 [ bp: Carve out from a bigger patch by Petteri, add feature check, add
   FNINIT call too (amluto). ]

Signed-off-by: Petteri Aimonen <jpa@git.mail.kapsi.fi>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=207979
Link: https://lkml.kernel.org/r/20200624114646.28953-2-bp@alien8.de
---
 arch/x86/include/asm/fpu/internal.h | 5 +++++
 arch/x86/kernel/fpu/core.c          | 6 ++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
index 42159f4..845e748 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -623,6 +623,11 @@ static inline void switch_fpu_finish(struct fpu *new_fpu)
  * MXCSR and XCR definitions:
  */
 
+static inline void ldmxcsr(u32 mxcsr)
+{
+	asm volatile("ldmxcsr %0" :: "m" (mxcsr));
+}
+
 extern unsigned int mxcsr_feature_mask;
 
 #define XCR_XFEATURE_ENABLED_MASK	0x00000000
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index 06c8189..15247b9 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -101,6 +101,12 @@ void kernel_fpu_begin(void)
 		copy_fpregs_to_fpstate(&current->thread.fpu);
 	}
 	__cpu_invalidate_fpregs_state();
+
+	if (boot_cpu_has(X86_FEATURE_XMM))
+		ldmxcsr(MXCSR_DEFAULT);
+
+	if (boot_cpu_has(X86_FEATURE_FPU))
+		asm volatile ("fninit");
 }
 EXPORT_SYMBOL_GPL(kernel_fpu_begin);
 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-06-29 20:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-24 11:46 [PATCH v2 0/2] x86/FPU: FPU sanitization for in-kernel use Borislav Petkov
2020-06-24 11:46 ` [PATCH v2 1/2] x86/fpu: Reset MXCSR to default in kernel_fpu_begin() Borislav Petkov
2020-06-29  8:34   ` [tip: x86/fpu] " tip-bot2 for Petteri Aimonen
2020-06-24 11:46 ` [PATCH v2 2/2] selftests/fpu: Add an FPU selftest Borislav Petkov
2020-06-24 17:51   ` Nick Desaulniers
2020-06-29  8:34   ` [tip: x86/fpu] " tip-bot2 for Petteri Aimonen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®