Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1373897 > unrolled thread
| Started by | Andy Lutomirski <luto@kernel.org> |
|---|---|
| First post | 2016-04-08 02:40 +0200 |
| Last post | 2016-04-08 12:50 +0200 |
| Articles | 14 — 7 participants |
Back to article view | Back to linux.kernel
[PATCH v3 0/7] x86: Pile o' FS/GS changes Andy Lutomirski <luto@kernel.org> - 2016-04-08 02:40 +0200
[PATCH v3 1/7] selftests/x86: Test the FSBASE/GSBASE API and context switching Andy Lutomirski <luto@kernel.org> - 2016-04-08 02:40 +0200
[tip:x86/asm] selftests/x86: Test the FSBASE/GSBASE API and context switching tip-bot for Andy Lutomirski <tipbot@zytor.com> - 2016-04-13 13:40 +0200
[PATCH v3 5/7] x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify Andy Lutomirski <luto@kernel.org> - 2016-04-08 02:40 +0200
[tip:x86/asm] x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify() tip-bot for Andy Lutomirski <tipbot@zytor.com> - 2016-04-13 13:40 +0200
[PATCH v3 7/7] x86/entry: Make gs_change a local label Andy Lutomirski <luto@kernel.org> - 2016-04-08 02:40 +0200
[tip:x86/asm] x86/entry/64: Make gs_change a local label tip-bot for Borislav Petkov <tipbot@zytor.com> - 2016-04-13 13:40 +0200
Re: [PATCH v3 6/7] x86/cpu: Add Erratum 88 detection on AMD Andy Lutomirski <luto@amacapital.net> - 2016-04-08 03:50 +0200
Re: [PATCH v3 6/7] x86/cpu: Add Erratum 88 detection on AMD Borislav Petkov <bp@alien8.de> - 2016-04-08 12:00 +0200
Re: [PATCH v3 2/7] x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS Ingo Molnar <mingo@kernel.org> - 2016-04-08 09:20 +0200
Re: [PATCH v3 2/7] x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS Dmitry Safonov <0x7f454c46@gmail.com> - 2016-04-08 11:40 +0200
Re: [PATCH v3 2/7] x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS Andy Lutomirski <luto@amacapital.net> - 2016-04-08 18:10 +0200
Re: [PATCH v3 0/7] x86: Pile o' FS/GS changes Borislav Petkov <bp@alien8.de> - 2016-04-08 12:40 +0200
Re: [PATCH v3 0/7] x86: Pile o' FS/GS changes Borislav Petkov <bp@alien8.de> - 2016-04-08 12:50 +0200
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-04-08 02:40 +0200 |
| Subject | [PATCH v3 0/7] x86: Pile o' FS/GS changes |
| Message-ID | <rlsCT-3LP-15@gated-at.bofh.it> |
Hi all- This whole mess is intended for x86/urgent. It fixes several bugs. It's probably a tiny performance regression on some workloads on Intel CPUs. It's probably varies between a less tiny regression and a small speedup on newer AMD CPUs. It's a bigger regression on AMD K8. The AMD code could be further sped up by adding a new 'clear_gs' pvop with a better native implementation. I don't particularly want to deal with a backported new pvop, so I didn't do that. Maybe I'll do it later on for new kernels, though. (For people who care about such things, there are probably three bugs in here depending how you count. Somewhere between one and two of them were independently discovered by Rudolf Marek.) Andy Lutomirski (5): selftests/x86: Test the FSBASE/GSBASE API and context switching x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS x86/cpu: Probe the behavior of nulling out a segment at boot time x86/switch_to: Rewrite the FS and GS context switch code x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify Borislav Petkov (2): x86/cpu: Add Erratum 88 detection on AMD x86/entry: Make gs_change a local label arch/x86/entry/entry_64.S | 12 +- arch/x86/include/asm/cpufeatures.h | 3 + arch/x86/kernel/cpu/amd.c | 1 + arch/x86/kernel/cpu/common.c | 71 ++++-- arch/x86/kernel/process_64.c | 167 ++++++++------ tools/testing/selftests/x86/Makefile | 1 + tools/testing/selftests/x86/fsgsbase.c | 398 +++++++++++++++++++++++++++++++++ 7 files changed, 560 insertions(+), 93 deletions(-) create mode 100644 tools/testing/selftests/x86/fsgsbase.c -- 2.5.5
[toc] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-04-08 02:40 +0200 |
| Subject | [PATCH v3 1/7] selftests/x86: Test the FSBASE/GSBASE API and context switching |
| Message-ID | <rlsCT-3LP-31@gated-at.bofh.it> |
| In reply to | #1373897 |
This catches two distinct bugs in the current code. I'll fix them.
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
tools/testing/selftests/x86/Makefile | 1 +
tools/testing/selftests/x86/fsgsbase.c | 398 +++++++++++++++++++++++++++++++++
2 files changed, 399 insertions(+)
create mode 100644 tools/testing/selftests/x86/fsgsbase.c
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index b47ebd170690..c73425de3cfe 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -9,6 +9,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc
TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \
vdso_restorer
+TARGETS_C_64BIT_ONLY := fsgsbase
TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c
new file mode 100644
index 000000000000..b7733055a359
--- /dev/null
+++ b/tools/testing/selftests/x86/fsgsbase.c
@@ -0,0 +1,398 @@
+/*
+ * fsgsbase.c, an fsgsbase test
+ * Copyright (c) 2014-2016 Andy Lutomirski
+ * GPL v2
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <err.h>
+#include <sys/user.h>
+#include <asm/prctl.h>
+#include <sys/prctl.h>
+#include <signal.h>
+#include <limits.h>
+#include <sys/ucontext.h>
+#include <sched.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <asm/ldt.h>
+#include <sys/mman.h>
+
+#ifndef __x86_64__
+# error This test is 64-bit only
+#endif
+
+static volatile sig_atomic_t want_segv;
+static volatile unsigned long segv_addr;
+
+static int nerrs;
+
+static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
+ int flags)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = handler;
+ sa.sa_flags = SA_SIGINFO | flags;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(sig, &sa, 0))
+ err(1, "sigaction");
+}
+
+static void clearhandler(int sig)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(sig, &sa, 0))
+ err(1, "sigaction");
+}
+
+static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
+{
+ ucontext_t *ctx = (ucontext_t*)ctx_void;
+
+ if (!want_segv) {
+ clearhandler(SIGSEGV);
+ return; /* Crash cleanly. */
+ }
+
+ want_segv = false;
+ segv_addr = (unsigned long)si->si_addr;
+
+ ctx->uc_mcontext.gregs[REG_RIP] += 4; /* Skip the faulting mov */
+
+}
+
+enum which_base { FS, GS };
+
+static unsigned long read_base(enum which_base which)
+{
+ unsigned long offset;
+ /*
+ * Unless we have FSGSBASE, there's no direct way to do this from
+ * user mode. We can get at it indirectly using signals, though.
+ */
+
+ want_segv = true;
+
+ offset = 0;
+ if (which == FS) {
+ /* Use a constant-length instruction here. */
+ asm volatile ("mov %%fs:(%%rcx), %%rax" : : "c" (offset) : "rax");
+ } else {
+ asm volatile ("mov %%gs:(%%rcx), %%rax" : : "c" (offset) : "rax");
+ }
+ if (!want_segv)
+ return segv_addr + offset;
+
+ /*
+ * If that didn't segfault, try the other end of the address space.
+ * Unless we get really unlucky and run into the vsyscall page, this
+ * is guaranteed to segfault.
+ */
+
+ offset = (ULONG_MAX >> 1) + 1;
+ if (which == FS) {
+ asm volatile ("mov %%fs:(%%rcx), %%rax"
+ : : "c" (offset) : "rax");
+ } else {
+ asm volatile ("mov %%gs:(%%rcx), %%rax"
+ : : "c" (offset) : "rax");
+ }
+ if (!want_segv)
+ return segv_addr + offset;
+
+ abort();
+}
+
+static void check_gs_value(unsigned long value)
+{
+ unsigned long base;
+ unsigned short sel;
+
+ printf("[RUN]\tARCH_SET_GS to 0x%lx\n", value);
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, value) != 0)
+ err(1, "ARCH_SET_GS");
+
+ asm volatile ("mov %%gs, %0" : "=rm" (sel));
+ base = read_base(GS);
+ if (base == value) {
+ printf("[OK]\tGSBASE was set as expected (selector 0x%hx)\n",
+ sel);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE was not as expected: got 0x%lx (selector 0x%hx)\n",
+ base, sel);
+ }
+
+ if (syscall(SYS_arch_prctl, ARCH_GET_GS, &base) != 0)
+ err(1, "ARCH_GET_GS");
+ if (base == value) {
+ printf("[OK]\tARCH_GET_GS worked as expected (selector 0x%hx)\n",
+ sel);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tARCH_GET_GS was not as expected: got 0x%lx (selector 0x%hx)\n",
+ base, sel);
+ }
+}
+
+static void mov_0_gs(unsigned long initial_base, bool schedule)
+{
+ unsigned long base, arch_base;
+
+ printf("[RUN]\tARCH_SET_GS to 0x%lx then mov 0 to %%gs%s\n", initial_base, schedule ? " and schedule " : "");
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, initial_base) != 0)
+ err(1, "ARCH_SET_GS");
+
+ if (schedule)
+ usleep(10);
+
+ asm volatile ("mov %0, %%gs" : : "rm" (0));
+ base = read_base(GS);
+ if (syscall(SYS_arch_prctl, ARCH_GET_GS, &arch_base) != 0)
+ err(1, "ARCH_GET_GS");
+ if (base == arch_base) {
+ printf("[OK]\tGSBASE is 0x%lx\n", base);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE changed to 0x%lx but kernel reports 0x%lx\n", base, arch_base);
+ }
+}
+
+static volatile unsigned long remote_base;
+static volatile bool remote_hard_zero;
+static volatile unsigned int ftx;
+
+/*
+ * ARCH_SET_FS/GS(0) may or may not program a selector of zero. HARD_ZERO
+ * means to force the selector to zero to improve test coverage.
+ */
+#define HARD_ZERO 0xa1fa5f343cb85fa4
+
+static void do_remote_base()
+{
+ unsigned long to_set = remote_base;
+ bool hard_zero = false;
+ if (to_set == HARD_ZERO) {
+ to_set = 0;
+ hard_zero = true;
+ }
+
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, to_set) != 0)
+ err(1, "ARCH_SET_GS");
+
+ if (hard_zero)
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+
+ unsigned short sel;
+ asm volatile ("mov %%gs, %0" : "=rm" (sel));
+ printf("\tother thread: ARCH_SET_GS(0x%lx)%s -- sel is 0x%hx\n",
+ to_set, hard_zero ? " and clear gs" : "", sel);
+}
+
+void do_unexpected_base(void)
+{
+ /*
+ * The goal here is to try to arrange for GS == 0, GSBASE !=
+ * 0, and for the the kernel the think that GSBASE == 0.
+ *
+ * To make the test as reliable as possible, this uses
+ * explicit descriptorss. (This is not the only way. This
+ * could use ARCH_SET_GS with a low, nonzero base, but the
+ * relevant side effect of ARCH_SET_GS could change.)
+ */
+
+ /* Step 1: tell the kernel that we have GSBASE == 0. */
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
+ err(1, "ARCH_SET_GS");
+
+ /* Step 2: change GSBASE without telling the kernel. */
+ struct user_desc desc = {
+ .entry_number = 0,
+ .base_addr = 0xBAADF00D,
+ .limit = 0xfffff,
+ .seg_32bit = 1,
+ .contents = 0, /* Data, grow-up */
+ .read_exec_only = 0,
+ .limit_in_pages = 1,
+ .seg_not_present = 0,
+ .useable = 0
+ };
+ if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) == 0) {
+ printf("\tother thread: using LDT slot 0\n");
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0x7));
+ } else {
+ /* No modify_ldt for us (configured out, perhaps) */
+
+ struct user_desc *low_desc = mmap(
+ NULL, sizeof(desc),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+ memcpy(low_desc, &desc, sizeof(desc));
+
+ low_desc->entry_number = -1;
+
+ /* 32-bit set_thread_area */
+ long ret;
+ asm volatile ("int $0x80"
+ : "=a" (ret) : "a" (243), "b" (low_desc)
+ : "flags");
+ memcpy(&desc, low_desc, sizeof(desc));
+ munmap(low_desc, sizeof(desc));
+
+ if (ret != 0) {
+ printf("[NOTE]\tcould not create a segment -- test won't do anything\n");
+ return;
+ }
+ printf("\tother thread: using GDT slot %d\n", desc.entry_number);
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)((desc.entry_number << 3) | 0x3)));
+ }
+
+ /*
+ * Step 3: set the selector back to zero. On AMD chips, this will
+ * preserve GSBASE.
+ */
+
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+}
+
+static void *threadproc(void *ctx)
+{
+ while (1) {
+ while (ftx == 0)
+ syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);
+ if (ftx == 3)
+ return NULL;
+
+ if (ftx == 1)
+ do_remote_base();
+ else if (ftx == 2)
+ do_unexpected_base();
+ else
+ errx(1, "helper thread got bad command");
+
+ ftx = 0;
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+ }
+}
+
+static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
+{
+ unsigned long base;
+
+ bool hard_zero = false;
+ if (local == HARD_ZERO) {
+ hard_zero = true;
+ local = 0;
+ }
+
+ printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
+ local, hard_zero ? " and clear gs" : "", remote);
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
+ err(1, "ARCH_SET_GS");
+ if (hard_zero)
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+
+ if (read_base(GS) != local) {
+ nerrs++;
+ printf("[FAIL]\tGSBASE wasn't set as expected\n");
+ }
+
+ remote_base = remote;
+ ftx = 1;
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+ while (ftx != 0)
+ syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
+
+ base = read_base(GS);
+ if (base == local) {
+ printf("[OK]\tGSBASE remained 0x%lx\n", local);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
+ }
+}
+
+static void test_unexpected_base(void)
+{
+ unsigned long base;
+
+ printf("[RUN]\tARCH_SET_GS(0), clear gs, then manipulate GSBASE in a different thread\n");
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
+ err(1, "ARCH_SET_GS");
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+
+ ftx = 2;
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+ while (ftx != 0)
+ syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
+
+ base = read_base(GS);
+ if (base == 0) {
+ printf("[OK]\tGSBASE remained 0\n");
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
+ }
+}
+
+int main()
+{
+ pthread_t thread;
+
+ sethandler(SIGSEGV, sigsegv, 0);
+
+ check_gs_value(0);
+ check_gs_value(1);
+ check_gs_value(0x200000000);
+ check_gs_value(0);
+ check_gs_value(0x200000000);
+ check_gs_value(1);
+
+ for (int sched = 0; sched < 2; sched++) {
+ mov_0_gs(0, !!sched);
+ mov_0_gs(1, !!sched);
+ mov_0_gs(0x200000000, !!sched);
+ }
+
+ /* Set up for multithreading. */
+
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ CPU_SET(0, &cpuset);
+ if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
+ err(1, "sched_setaffinity to CPU 0"); /* should never fail */
+
+ if (pthread_create(&thread, 0, threadproc, 0) != 0)
+ err(1, "pthread_create");
+
+ static unsigned long bases_with_hard_zero[] = {
+ 0, HARD_ZERO, 1, 0x200000000,
+ };
+
+ for (int local = 0; local < 4; local++) {
+ for (int remote = 0; remote < 4; remote++) {
+ set_gs_and_switch_to(bases_with_hard_zero[local],
+ bases_with_hard_zero[remote]);
+ }
+ }
+
+ test_unexpected_base();
+
+ ftx = 3; /* Kill the thread. */
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+
+ if (pthread_join(thread, NULL) != 0)
+ err(1, "pthread_join");
+
+ return nerrs == 0 ? 0 : 1;
+}
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Andy Lutomirski <tipbot@zytor.com> |
|---|---|
| Date | 2016-04-13 13:40 +0200 |
| Subject | [tip:x86/asm] selftests/x86: Test the FSBASE/GSBASE API and context switching |
| Message-ID | <rnrjk-x5-33@gated-at.bofh.it> |
| In reply to | #1373902 |
Commit-ID: 0051202f6ad5fd9c04d220343e66d1eb890f7b81
Gitweb: http://git.kernel.org/tip/0051202f6ad5fd9c04d220343e66d1eb890f7b81
Author: Andy Lutomirski <luto@kernel.org>
AuthorDate: Thu, 7 Apr 2016 17:31:44 -0700
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Wed, 13 Apr 2016 10:20:41 +0200
selftests/x86: Test the FSBASE/GSBASE API and context switching
This catches two distinct bugs in the current code. I'll fix them.
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Reviewed-by: Borislav Petkov <bp@suse.de>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rudolf Marek <r.marek@assembler.cz>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/7e5941148d1e2199f070dadcdf7355959f5f8e85.1460075211.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
tools/testing/selftests/x86/Makefile | 1 +
tools/testing/selftests/x86/fsgsbase.c | 398 +++++++++++++++++++++++++++++++++
2 files changed, 399 insertions(+)
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index b47ebd1..c73425d 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -9,6 +9,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc
TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \
vdso_restorer
+TARGETS_C_64BIT_ONLY := fsgsbase
TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c
new file mode 100644
index 0000000..5b2b4b3
--- /dev/null
+++ b/tools/testing/selftests/x86/fsgsbase.c
@@ -0,0 +1,398 @@
+/*
+ * fsgsbase.c, an fsgsbase test
+ * Copyright (c) 2014-2016 Andy Lutomirski
+ * GPL v2
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <err.h>
+#include <sys/user.h>
+#include <asm/prctl.h>
+#include <sys/prctl.h>
+#include <signal.h>
+#include <limits.h>
+#include <sys/ucontext.h>
+#include <sched.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <asm/ldt.h>
+#include <sys/mman.h>
+
+#ifndef __x86_64__
+# error This test is 64-bit only
+#endif
+
+static volatile sig_atomic_t want_segv;
+static volatile unsigned long segv_addr;
+
+static int nerrs;
+
+static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
+ int flags)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = handler;
+ sa.sa_flags = SA_SIGINFO | flags;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(sig, &sa, 0))
+ err(1, "sigaction");
+}
+
+static void clearhandler(int sig)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(sig, &sa, 0))
+ err(1, "sigaction");
+}
+
+static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
+{
+ ucontext_t *ctx = (ucontext_t*)ctx_void;
+
+ if (!want_segv) {
+ clearhandler(SIGSEGV);
+ return; /* Crash cleanly. */
+ }
+
+ want_segv = false;
+ segv_addr = (unsigned long)si->si_addr;
+
+ ctx->uc_mcontext.gregs[REG_RIP] += 4; /* Skip the faulting mov */
+
+}
+
+enum which_base { FS, GS };
+
+static unsigned long read_base(enum which_base which)
+{
+ unsigned long offset;
+ /*
+ * Unless we have FSGSBASE, there's no direct way to do this from
+ * user mode. We can get at it indirectly using signals, though.
+ */
+
+ want_segv = true;
+
+ offset = 0;
+ if (which == FS) {
+ /* Use a constant-length instruction here. */
+ asm volatile ("mov %%fs:(%%rcx), %%rax" : : "c" (offset) : "rax");
+ } else {
+ asm volatile ("mov %%gs:(%%rcx), %%rax" : : "c" (offset) : "rax");
+ }
+ if (!want_segv)
+ return segv_addr + offset;
+
+ /*
+ * If that didn't segfault, try the other end of the address space.
+ * Unless we get really unlucky and run into the vsyscall page, this
+ * is guaranteed to segfault.
+ */
+
+ offset = (ULONG_MAX >> 1) + 1;
+ if (which == FS) {
+ asm volatile ("mov %%fs:(%%rcx), %%rax"
+ : : "c" (offset) : "rax");
+ } else {
+ asm volatile ("mov %%gs:(%%rcx), %%rax"
+ : : "c" (offset) : "rax");
+ }
+ if (!want_segv)
+ return segv_addr + offset;
+
+ abort();
+}
+
+static void check_gs_value(unsigned long value)
+{
+ unsigned long base;
+ unsigned short sel;
+
+ printf("[RUN]\tARCH_SET_GS to 0x%lx\n", value);
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, value) != 0)
+ err(1, "ARCH_SET_GS");
+
+ asm volatile ("mov %%gs, %0" : "=rm" (sel));
+ base = read_base(GS);
+ if (base == value) {
+ printf("[OK]\tGSBASE was set as expected (selector 0x%hx)\n",
+ sel);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE was not as expected: got 0x%lx (selector 0x%hx)\n",
+ base, sel);
+ }
+
+ if (syscall(SYS_arch_prctl, ARCH_GET_GS, &base) != 0)
+ err(1, "ARCH_GET_GS");
+ if (base == value) {
+ printf("[OK]\tARCH_GET_GS worked as expected (selector 0x%hx)\n",
+ sel);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tARCH_GET_GS was not as expected: got 0x%lx (selector 0x%hx)\n",
+ base, sel);
+ }
+}
+
+static void mov_0_gs(unsigned long initial_base, bool schedule)
+{
+ unsigned long base, arch_base;
+
+ printf("[RUN]\tARCH_SET_GS to 0x%lx then mov 0 to %%gs%s\n", initial_base, schedule ? " and schedule " : "");
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, initial_base) != 0)
+ err(1, "ARCH_SET_GS");
+
+ if (schedule)
+ usleep(10);
+
+ asm volatile ("mov %0, %%gs" : : "rm" (0));
+ base = read_base(GS);
+ if (syscall(SYS_arch_prctl, ARCH_GET_GS, &arch_base) != 0)
+ err(1, "ARCH_GET_GS");
+ if (base == arch_base) {
+ printf("[OK]\tGSBASE is 0x%lx\n", base);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE changed to 0x%lx but kernel reports 0x%lx\n", base, arch_base);
+ }
+}
+
+static volatile unsigned long remote_base;
+static volatile bool remote_hard_zero;
+static volatile unsigned int ftx;
+
+/*
+ * ARCH_SET_FS/GS(0) may or may not program a selector of zero. HARD_ZERO
+ * means to force the selector to zero to improve test coverage.
+ */
+#define HARD_ZERO 0xa1fa5f343cb85fa4
+
+static void do_remote_base()
+{
+ unsigned long to_set = remote_base;
+ bool hard_zero = false;
+ if (to_set == HARD_ZERO) {
+ to_set = 0;
+ hard_zero = true;
+ }
+
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, to_set) != 0)
+ err(1, "ARCH_SET_GS");
+
+ if (hard_zero)
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+
+ unsigned short sel;
+ asm volatile ("mov %%gs, %0" : "=rm" (sel));
+ printf("\tother thread: ARCH_SET_GS(0x%lx)%s -- sel is 0x%hx\n",
+ to_set, hard_zero ? " and clear gs" : "", sel);
+}
+
+void do_unexpected_base(void)
+{
+ /*
+ * The goal here is to try to arrange for GS == 0, GSBASE !=
+ * 0, and for the the kernel the think that GSBASE == 0.
+ *
+ * To make the test as reliable as possible, this uses
+ * explicit descriptorss. (This is not the only way. This
+ * could use ARCH_SET_GS with a low, nonzero base, but the
+ * relevant side effect of ARCH_SET_GS could change.)
+ */
+
+ /* Step 1: tell the kernel that we have GSBASE == 0. */
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
+ err(1, "ARCH_SET_GS");
+
+ /* Step 2: change GSBASE without telling the kernel. */
+ struct user_desc desc = {
+ .entry_number = 0,
+ .base_addr = 0xBAADF00D,
+ .limit = 0xfffff,
+ .seg_32bit = 1,
+ .contents = 0, /* Data, grow-up */
+ .read_exec_only = 0,
+ .limit_in_pages = 1,
+ .seg_not_present = 0,
+ .useable = 0
+ };
+ if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) == 0) {
+ printf("\tother thread: using LDT slot 0\n");
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0x7));
+ } else {
+ /* No modify_ldt for us (configured out, perhaps) */
+
+ struct user_desc *low_desc = mmap(
+ NULL, sizeof(desc),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+ memcpy(low_desc, &desc, sizeof(desc));
+
+ low_desc->entry_number = -1;
+
+ /* 32-bit set_thread_area */
+ long ret;
+ asm volatile ("int $0x80"
+ : "=a" (ret) : "a" (243), "b" (low_desc)
+ : "flags");
+ memcpy(&desc, low_desc, sizeof(desc));
+ munmap(low_desc, sizeof(desc));
+
+ if (ret != 0) {
+ printf("[NOTE]\tcould not create a segment -- test won't do anything\n");
+ return;
+ }
+ printf("\tother thread: using GDT slot %d\n", desc.entry_number);
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)((desc.entry_number << 3) | 0x3)));
+ }
+
+ /*
+ * Step 3: set the selector back to zero. On AMD chips, this will
+ * preserve GSBASE.
+ */
+
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+}
+
+static void *threadproc(void *ctx)
+{
+ while (1) {
+ while (ftx == 0)
+ syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);
+ if (ftx == 3)
+ return NULL;
+
+ if (ftx == 1)
+ do_remote_base();
+ else if (ftx == 2)
+ do_unexpected_base();
+ else
+ errx(1, "helper thread got bad command");
+
+ ftx = 0;
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+ }
+}
+
+static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
+{
+ unsigned long base;
+
+ bool hard_zero = false;
+ if (local == HARD_ZERO) {
+ hard_zero = true;
+ local = 0;
+ }
+
+ printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
+ local, hard_zero ? " and clear gs" : "", remote);
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
+ err(1, "ARCH_SET_GS");
+ if (hard_zero)
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+
+ if (read_base(GS) != local) {
+ nerrs++;
+ printf("[FAIL]\tGSBASE wasn't set as expected\n");
+ }
+
+ remote_base = remote;
+ ftx = 1;
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+ while (ftx != 0)
+ syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
+
+ base = read_base(GS);
+ if (base == local) {
+ printf("[OK]\tGSBASE remained 0x%lx\n", local);
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
+ }
+}
+
+static void test_unexpected_base(void)
+{
+ unsigned long base;
+
+ printf("[RUN]\tARCH_SET_GS(0), clear gs, then manipulate GSBASE in a different thread\n");
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
+ err(1, "ARCH_SET_GS");
+ asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
+
+ ftx = 2;
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+ while (ftx != 0)
+ syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
+
+ base = read_base(GS);
+ if (base == 0) {
+ printf("[OK]\tGSBASE remained 0\n");
+ } else {
+ nerrs++;
+ printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
+ }
+}
+
+int main()
+{
+ pthread_t thread;
+
+ sethandler(SIGSEGV, sigsegv, 0);
+
+ check_gs_value(0);
+ check_gs_value(1);
+ check_gs_value(0x200000000);
+ check_gs_value(0);
+ check_gs_value(0x200000000);
+ check_gs_value(1);
+
+ for (int sched = 0; sched < 2; sched++) {
+ mov_0_gs(0, !!sched);
+ mov_0_gs(1, !!sched);
+ mov_0_gs(0x200000000, !!sched);
+ }
+
+ /* Set up for multithreading. */
+
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ CPU_SET(0, &cpuset);
+ if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
+ err(1, "sched_setaffinity to CPU 0"); /* should never fail */
+
+ if (pthread_create(&thread, 0, threadproc, 0) != 0)
+ err(1, "pthread_create");
+
+ static unsigned long bases_with_hard_zero[] = {
+ 0, HARD_ZERO, 1, 0x200000000,
+ };
+
+ for (int local = 0; local < 4; local++) {
+ for (int remote = 0; remote < 4; remote++) {
+ set_gs_and_switch_to(bases_with_hard_zero[local],
+ bases_with_hard_zero[remote]);
+ }
+ }
+
+ test_unexpected_base();
+
+ ftx = 3; /* Kill the thread. */
+ syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+
+ if (pthread_join(thread, NULL) != 0)
+ err(1, "pthread_join");
+
+ return nerrs == 0 ? 0 : 1;
+}
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-04-08 02:40 +0200 |
| Subject | [PATCH v3 5/7] x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify |
| Message-ID | <rlsCT-3LP-35@gated-at.bofh.it> |
| In reply to | #1373897 |
It was in detect_nopl, which was either a mistake by me or some kind
of mis-merge.
Fixes: ff236456f072 ("x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify")
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
arch/x86/kernel/cpu/common.c | 50 ++++++++++++++++++++++----------------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index ceef584ae8b0..9ede8aa41f18 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -862,31 +862,6 @@ static void detect_nopl(struct cpuinfo_x86 *c)
#else
set_cpu_cap(c, X86_FEATURE_NOPL);
#endif
-
- /*
- * ESPFIX is a strange bug. All real CPUs have it. Paravirt
- * systems that run Linux at CPL > 0 may or may not have the
- * issue, but, even if they have the issue, there's absolutely
- * nothing we can do about it because we can't use the real IRET
- * instruction.
- *
- * NB: For the time being, only 32-bit kernels support
- * X86_BUG_ESPFIX as such. 64-bit kernels directly choose
- * whether to apply espfix using paravirt hooks. If any
- * non-paravirt system ever shows up that does *not* have the
- * ESPFIX issue, we can change this.
- */
-#ifdef CONFIG_X86_32
-#ifdef CONFIG_PARAVIRT
- do {
- extern void native_iret(void);
- if (pv_cpu_ops.iret == native_iret)
- set_cpu_bug(c, X86_BUG_ESPFIX);
- } while (0);
-#else
- set_cpu_bug(c, X86_BUG_ESPFIX);
-#endif
-#endif
}
static void detect_null_seg_behavior(struct cpuinfo_x86 *c)
@@ -952,6 +927,31 @@ static void generic_identify(struct cpuinfo_x86 *c)
detect_nopl(c);
detect_null_seg_behavior(c);
+
+ /*
+ * ESPFIX is a strange bug. All real CPUs have it. Paravirt
+ * systems that run Linux at CPL > 0 may or may not have the
+ * issue, but, even if they have the issue, there's absolutely
+ * nothing we can do about it because we can't use the real IRET
+ * instruction.
+ *
+ * NB: For the time being, only 32-bit kernels support
+ * X86_BUG_ESPFIX as such. 64-bit kernels directly choose
+ * whether to apply espfix using paravirt hooks. If any
+ * non-paravirt system ever shows up that does *not* have the
+ * ESPFIX issue, we can change this.
+ */
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_PARAVIRT
+ do {
+ extern void native_iret(void);
+ if (pv_cpu_ops.iret == native_iret)
+ set_cpu_bug(c, X86_BUG_ESPFIX);
+ } while (0);
+#else
+ set_cpu_bug(c, X86_BUG_ESPFIX);
+#endif
+#endif
}
static void x86_init_cache_qos(struct cpuinfo_x86 *c)
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Andy Lutomirski <tipbot@zytor.com> |
|---|---|
| Date | 2016-04-13 13:40 +0200 |
| Subject | [tip:x86/asm] x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify() |
| Message-ID | <rnrjk-x5-27@gated-at.bofh.it> |
| In reply to | #1373904 |
Commit-ID: 0230bb038fa99af0c425fc4cffed307e545a9642
Gitweb: http://git.kernel.org/tip/0230bb038fa99af0c425fc4cffed307e545a9642
Author: Andy Lutomirski <luto@kernel.org>
AuthorDate: Thu, 7 Apr 2016 17:31:48 -0700
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Wed, 13 Apr 2016 10:20:42 +0200
x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify()
It was in detect_nopl(), which was either a mistake by me or some kind
of mis-merge.
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Reviewed-by: Borislav Petkov <bp@suse.de>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rudolf Marek <r.marek@assembler.cz>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: ff236456f072 ("x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify")
Link: http://lkml.kernel.org/r/0949337f13660461edca08ab67d1a841441289c9.1460075211.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
arch/x86/kernel/cpu/common.c | 50 ++++++++++++++++++++++----------------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 8e40eee..28d3255 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -862,31 +862,6 @@ static void detect_nopl(struct cpuinfo_x86 *c)
#else
set_cpu_cap(c, X86_FEATURE_NOPL);
#endif
-
- /*
- * ESPFIX is a strange bug. All real CPUs have it. Paravirt
- * systems that run Linux at CPL > 0 may or may not have the
- * issue, but, even if they have the issue, there's absolutely
- * nothing we can do about it because we can't use the real IRET
- * instruction.
- *
- * NB: For the time being, only 32-bit kernels support
- * X86_BUG_ESPFIX as such. 64-bit kernels directly choose
- * whether to apply espfix using paravirt hooks. If any
- * non-paravirt system ever shows up that does *not* have the
- * ESPFIX issue, we can change this.
- */
-#ifdef CONFIG_X86_32
-#ifdef CONFIG_PARAVIRT
- do {
- extern void native_iret(void);
- if (pv_cpu_ops.iret == native_iret)
- set_cpu_bug(c, X86_BUG_ESPFIX);
- } while (0);
-#else
- set_cpu_bug(c, X86_BUG_ESPFIX);
-#endif
-#endif
}
static void detect_null_seg_behavior(struct cpuinfo_x86 *c)
@@ -952,6 +927,31 @@ static void generic_identify(struct cpuinfo_x86 *c)
detect_nopl(c);
detect_null_seg_behavior(c);
+
+ /*
+ * ESPFIX is a strange bug. All real CPUs have it. Paravirt
+ * systems that run Linux at CPL > 0 may or may not have the
+ * issue, but, even if they have the issue, there's absolutely
+ * nothing we can do about it because we can't use the real IRET
+ * instruction.
+ *
+ * NB: For the time being, only 32-bit kernels support
+ * X86_BUG_ESPFIX as such. 64-bit kernels directly choose
+ * whether to apply espfix using paravirt hooks. If any
+ * non-paravirt system ever shows up that does *not* have the
+ * ESPFIX issue, we can change this.
+ */
+#ifdef CONFIG_X86_32
+# ifdef CONFIG_PARAVIRT
+ do {
+ extern void native_iret(void);
+ if (pv_cpu_ops.iret == native_iret)
+ set_cpu_bug(c, X86_BUG_ESPFIX);
+ } while (0);
+# else
+ set_cpu_bug(c, X86_BUG_ESPFIX);
+# endif
+#endif
}
static void x86_init_cache_qos(struct cpuinfo_x86 *c)
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-04-08 02:40 +0200 |
| Subject | [PATCH v3 7/7] x86/entry: Make gs_change a local label |
| Message-ID | <rlsCU-3LP-45@gated-at.bofh.it> |
| In reply to | #1373897 |
From: Borislav Petkov <bp@suse.de> ... so that it doesn't appear in objdump output. Signed-off-by: Borislav Petkov <bp@suse.de> Signed-off-by: Andy Lutomirski <luto@kernel.org> --- arch/x86/entry/entry_64.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 64d2033d1e49..1693c17dbf81 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -781,7 +781,7 @@ ENTRY(native_load_gs_index) pushfq DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI) SWAPGS -gs_change: +.Lgs_change: movl %edi, %gs 2: ALTERNATIVE "", "mfence", X86_BUG_SWAPGS_FENCE SWAPGS @@ -789,7 +789,7 @@ gs_change: ret END(native_load_gs_index) - _ASM_EXTABLE(gs_change, bad_gs) + _ASM_EXTABLE(.Lgs_change, bad_gs) .section .fixup, "ax" /* running with kernelgs */ bad_gs: @@ -1019,13 +1019,13 @@ ENTRY(error_entry) movl %ecx, %eax /* zero extend */ cmpq %rax, RIP+8(%rsp) je .Lbstep_iret - cmpq $gs_change, RIP+8(%rsp) + cmpq $.Lgs_change, RIP+8(%rsp) jne .Lerror_entry_done /* - * hack: gs_change can fail with user gsbase. If this happens, fix up + * hack: .Lgs_change can fail with user gsbase. If this happens, fix up * gsbase and proceed. We'll fix up the exception and land in - * gs_change's error handler with kernel gsbase. + * .Lgs_change's error handler with kernel gsbase. */ jmp .Lerror_entry_from_usermode_swapgs -- 2.5.5
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Borislav Petkov <tipbot@zytor.com> |
|---|---|
| Date | 2016-04-13 13:40 +0200 |
| Subject | [tip:x86/asm] x86/entry/64: Make gs_change a local label |
| Message-ID | <rnrjj-x5-1@gated-at.bofh.it> |
| In reply to | #1373909 |
Commit-ID: 42c748bb2544f21c3d115240527fe4478e193641 Gitweb: http://git.kernel.org/tip/42c748bb2544f21c3d115240527fe4478e193641 Author: Borislav Petkov <bp@suse.de> AuthorDate: Thu, 7 Apr 2016 17:31:50 -0700 Committer: Ingo Molnar <mingo@kernel.org> CommitDate: Wed, 13 Apr 2016 10:20:42 +0200 x86/entry/64: Make gs_change a local label ... so that it doesn't appear in objdump output. Signed-off-by: Borislav Petkov <bp@suse.de> Signed-off-by: Andy Lutomirski <luto@kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rudolf Marek <r.marek@assembler.cz> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/b9c532a0e5f8d56dede2bd59767d40024d5a75e2.1460075211.git.luto@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org> --- arch/x86/entry/entry_64.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 64d2033..1693c17 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -781,7 +781,7 @@ ENTRY(native_load_gs_index) pushfq DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI) SWAPGS -gs_change: +.Lgs_change: movl %edi, %gs 2: ALTERNATIVE "", "mfence", X86_BUG_SWAPGS_FENCE SWAPGS @@ -789,7 +789,7 @@ gs_change: ret END(native_load_gs_index) - _ASM_EXTABLE(gs_change, bad_gs) + _ASM_EXTABLE(.Lgs_change, bad_gs) .section .fixup, "ax" /* running with kernelgs */ bad_gs: @@ -1019,13 +1019,13 @@ ENTRY(error_entry) movl %ecx, %eax /* zero extend */ cmpq %rax, RIP+8(%rsp) je .Lbstep_iret - cmpq $gs_change, RIP+8(%rsp) + cmpq $.Lgs_change, RIP+8(%rsp) jne .Lerror_entry_done /* - * hack: gs_change can fail with user gsbase. If this happens, fix up + * hack: .Lgs_change can fail with user gsbase. If this happens, fix up * gsbase and proceed. We'll fix up the exception and land in - * gs_change's error handler with kernel gsbase. + * .Lgs_change's error handler with kernel gsbase. */ jmp .Lerror_entry_from_usermode_swapgs
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-04-08 03:50 +0200 |
| Subject | Re: [PATCH v3 6/7] x86/cpu: Add Erratum 88 detection on AMD |
| Message-ID | <rltIC-4zb-3@gated-at.bofh.it> |
| In reply to | #1373897 |
On Thu, Apr 7, 2016 at 5:31 PM, Andy Lutomirski <luto@kernel.org> wrote: > From: Borislav Petkov <bp@suse.de> > > Erratum 88 affects old AMD K8s, where a SWAPGS fails to cause an input > dependency on GS. Therefore, we need to MFENCE before it. > > But that MFENCE is expensive and unnecessary on the remaining x86 CPUs > out there so patch it out on the CPUs which don't require it. This is basically identical to: https://lkml.kernel.org/g/1458576969-13309-4-git-send-email-andi@firstfloor.org Whoops! I thought I'd seen that somewhere but I couldn't spot it. Ingo, etc: we should probably apply one of those patches with a -stable tag (to mitigate the otherwise potentially unpleasant performance regression in here), but I don't really care which one. Andi's has a name for the bug that seems nicer by one character to me, but it would have to be (trivally) rebased. --Andy > > Signed-off-by: Borislav Petkov <bp@suse.de> > Cc: <stable@vger.kernel.org> > Signed-off-by: Andy Lutomirski <luto@kernel.org > --- > arch/x86/entry/entry_64.S | 2 +- > arch/x86/include/asm/cpufeatures.h | 2 ++ > arch/x86/kernel/cpu/amd.c | 1 + > 3 files changed, 4 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S > index 858b555e274b..64d2033d1e49 100644 > --- a/arch/x86/entry/entry_64.S > +++ b/arch/x86/entry/entry_64.S > @@ -783,7 +783,7 @@ ENTRY(native_load_gs_index) > SWAPGS > gs_change: > movl %edi, %gs > -2: mfence /* workaround */ > +2: ALTERNATIVE "", "mfence", X86_BUG_SWAPGS_FENCE > SWAPGS > popfq > ret > diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h > index 2a052302bc43..7bfb6b70c745 100644 > --- a/arch/x86/include/asm/cpufeatures.h > +++ b/arch/x86/include/asm/cpufeatures.h > @@ -295,6 +295,8 @@ > #define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ > #define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ > #define X86_BUG_NULL_SEG X86_BUG(9) /* Nulling a selector preserves the base */ > +#define X86_BUG_SWAPGS_FENCE X86_BUG(10) /* SWAPGS without input dep on GS */ > + > > #ifdef CONFIG_X86_32 > /* > diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c > index 6e47e3a916f1..b7cc9efe08b5 100644 > --- a/arch/x86/kernel/cpu/amd.c > +++ b/arch/x86/kernel/cpu/amd.c > @@ -632,6 +632,7 @@ static void init_amd_k8(struct cpuinfo_x86 *c) > */ > msr_set_bit(MSR_K7_HWCR, 6); > #endif > + set_cpu_bug(c, X86_BUG_SWAPGS_FENCE); > } > > static void init_amd_gh(struct cpuinfo_x86 *c) > -- > 2.5.5 > -- Andy Lutomirski AMA Capital Management, LLC
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-04-08 12:00 +0200 |
| Subject | Re: [PATCH v3 6/7] x86/cpu: Add Erratum 88 detection on AMD |
| Message-ID | <rlBmO-1PG-11@gated-at.bofh.it> |
| In reply to | #1373930 |
On Thu, Apr 07, 2016 at 06:40:13PM -0700, Andy Lutomirski wrote:
> Ingo, etc: we should probably apply one of those patches with a
> -stable tag (to mitigate the otherwise potentially unpleasant
> performance regression in here), but I don't really care which one.
> Andi's has a name for the bug that seems nicer by one character to me,
> but it would have to be (trivally) rebased.
I don't care which one as long as the commit message says "erratum 88"
somewhere.
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [next] | [standalone]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2016-04-08 09:20 +0200 |
| Subject | Re: [PATCH v3 2/7] x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS |
| Message-ID | <rlyRY-eV-15@gated-at.bofh.it> |
| In reply to | #1373897 |
* Andy Lutomirski <luto@kernel.org> wrote: > ARCH_GET_FS and ARCH_GET_GS attempted to figure out the fsbase and > gsbase respectively from saved thread state. This was wrong: fsbase > and gsbase live in registers while a thread is running, not in > memory. So I'm wondering, the current code looks totally broken,what user-space code can possibly use this? I checked glibc and Wine, and neither of them does. Wine uses ARCH_SET_GS and glibc uses ARCH_SET_FS, but that's all - neither actually tries to use the ARCH_GET_* reading APIs. So for backporting purposes I'd be much happier about simply returning -EINVAL or -ENOSYS, and we could re-introduce this code in v4.7. Thanks, Ingo
[toc] | [prev] | [next] | [standalone]
| From | Dmitry Safonov <0x7f454c46@gmail.com> |
|---|---|
| Date | 2016-04-08 11:40 +0200 |
| Subject | Re: [PATCH v3 2/7] x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS |
| Message-ID | <rlB3s-1Hc-21@gated-at.bofh.it> |
| In reply to | #1374033 |
2016-04-08 10:13 GMT+03:00 Ingo Molnar <mingo@kernel.org>:
>
> * Andy Lutomirski <luto@kernel.org> wrote:
>
>> ARCH_GET_FS and ARCH_GET_GS attempted to figure out the fsbase and
>> gsbase respectively from saved thread state. This was wrong: fsbase
>> and gsbase live in registers while a thread is running, not in
>> memory.
>
> So I'm wondering, the current code looks totally broken,what user-space code can
> possibly use this? I checked glibc and Wine, and neither of them does. Wine uses
> ARCH_SET_GS and glibc uses ARCH_SET_FS, but that's all - neither actually tries to
> use the ARCH_GET_* reading APIs.
Just FYI, CRIU also does not use ARCH_GET_{FS,GS}, only ARCH_SET_{FS,GS}.
It gets them with the help of PTRACE_GETREGSET.
> So for backporting purposes I'd be much happier about simply returning -EINVAL or
> -ENOSYS, and we could re-introduce this code in v4.7.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-04-08 18:10 +0200 |
| Subject | Re: [PATCH v3 2/7] x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS |
| Message-ID | <rlH8R-6t5-15@gated-at.bofh.it> |
| In reply to | #1374033 |
On Fri, Apr 8, 2016 at 12:13 AM, Ingo Molnar <mingo@kernel.org> wrote: > > * Andy Lutomirski <luto@kernel.org> wrote: > >> ARCH_GET_FS and ARCH_GET_GS attempted to figure out the fsbase and >> gsbase respectively from saved thread state. This was wrong: fsbase >> and gsbase live in registers while a thread is running, not in >> memory. > > So I'm wondering, the current code looks totally broken,what user-space code can > possibly use this? I checked glibc and Wine, and neither of them does. Wine uses > ARCH_SET_GS and glibc uses ARCH_SET_FS, but that's all - neither actually tries to > use the ARCH_GET_* reading APIs. > > So for backporting purposes I'd be much happier about simply returning -EINVAL or > -ENOSYS, and we could re-introduce this code in v4.7. > Let's just not backport this one. There's no security issue here. If you like the rest of the series, can you remove the stable tag from this patch when you apply it? I think the old code was at least correct enough that if you did ARCH_GET_FS after ARCH_SET_FS with no funny business in between, it would work. --Andy -- Andy Lutomirski AMA Capital Management, LLC
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-04-08 12:40 +0200 |
| Message-ID | <rlBZw-2oe-5@gated-at.bofh.it> |
| In reply to | #1373897 |
On Thu, Apr 07, 2016 at 05:31:43PM -0700, Andy Lutomirski wrote:
> Hi all-
>
> This whole mess is intended for x86/urgent. It fixes several bugs.
>
> It's probably a tiny performance regression on some workloads on
> Intel CPUs. It's probably varies between a less tiny regression and
> a small speedup on newer AMD CPUs. It's a bigger regression on AMD
> K8.
Shhh, otherwise the 2-3 K8 users left would crawl out of the woodwork
complaining. ;-)
> The AMD code could be further sped up by adding a new 'clear_gs'
> pvop with a better native implementation. I don't particularly want
> to deal with a backported new pvop, so I didn't do that. Maybe I'll
> do it later on for new kernels, though.
Yeah, before you do that, we should probably measure that first to see
whether it is worth the trouble and the added pvop gunk at all.
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-04-08 12:50 +0200 |
| Message-ID | <rlC9b-2s3-5@gated-at.bofh.it> |
| In reply to | #1373897 |
On Thu, Apr 07, 2016 at 05:31:43PM -0700, Andy Lutomirski wrote:
> Hi all-
>
> This whole mess is intended for x86/urgent. It fixes several bugs.
>
> It's probably a tiny performance regression on some workloads on
> Intel CPUs. It's probably varies between a less tiny regression and
> a small speedup on newer AMD CPUs. It's a bigger regression on AMD
> K8.
>
> The AMD code could be further sped up by adding a new 'clear_gs'
> pvop with a better native implementation. I don't particularly want
> to deal with a backported new pvop, so I didn't do that. Maybe I'll
> do it later on for new kernels, though.
>
> (For people who care about such things, there are probably three
> bugs in here depending how you count. Somewhere between one and two
> of them were independently discovered by Rudolf Marek.)
>
> Andy Lutomirski (5):
> selftests/x86: Test the FSBASE/GSBASE API and context switching
> x86/arch_prctl: Fix ARCH_GET_FS and ARCH_GET_GS
> x86/cpu: Probe the behavior of nulling out a segment at boot time
> x86/switch_to: Rewrite the FS and GS context switch code
> x86/cpu: Move X86_BUG_ESPFIX initialization to generic_identify
>
> Borislav Petkov (2):
> x86/cpu: Add Erratum 88 detection on AMD
> x86/entry: Make gs_change a local label
>
> arch/x86/entry/entry_64.S | 12 +-
> arch/x86/include/asm/cpufeatures.h | 3 +
> arch/x86/kernel/cpu/amd.c | 1 +
> arch/x86/kernel/cpu/common.c | 71 ++++--
> arch/x86/kernel/process_64.c | 167 ++++++++------
> tools/testing/selftests/x86/Makefile | 1 +
> tools/testing/selftests/x86/fsgsbase.c | 398 +++++++++++++++++++++++++++++++++
> 7 files changed, 560 insertions(+), 93 deletions(-)
> create mode 100644 tools/testing/selftests/x86/fsgsbase.c
Forgot to add:
Reviewed-by: Borislav Petkov <bp@suse.de>
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web