aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2021-02-19 21:18:54 -0800
committerAndy Lutomirski <luto@kernel.org>2021-02-19 21:18:54 -0800
commitbfaecaf0dad8f61e80285125f4895c9737e3d6d8 (patch)
treed5f48d736a45bda394e3cbee97ac491158b02724
parentbf85057ed696c8996a5f5b924a3fd58698450511 (diff)
downloadlinux-x86/no_sce.tar.gz
[EVIL] Run with EFER.SCE = 0x86/no_sce
Don't think too hard about this patch. Definitely don't expect it to work reliably.
-rw-r--r--arch/x86/kernel/cpu/common.c6
-rw-r--r--arch/x86/kernel/traps.c15
2 files changed, 21 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index cf43d7eef5a7a2..190ccf8281fa2f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1748,6 +1748,8 @@ EXPORT_PER_CPU_SYMBOL(__preempt_count);
/* May not be marked __init: used by software suspend */
void syscall_init(void)
{
+ u64 val;
+
wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
wrmsrl(MSR_CSTAR, (unsigned long)entry_SYSCALL_compat);
@@ -1774,6 +1776,10 @@ void syscall_init(void)
wrmsrl(MSR_SYSCALL_MASK,
X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|
X86_EFLAGS_IOPL|X86_EFLAGS_AC|X86_EFLAGS_NT);
+
+ rdmsrl(MSR_EFER, val);
+ val &= ~EFER_SCE;
+ wrmsrl(MSR_EFER, val);
}
#else /* CONFIG_X86_64 */
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 7f5aec758f0eea..a71421de74f3b5 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -61,6 +61,7 @@
#include <asm/insn.h>
#include <asm/insn-eval.h>
#include <asm/vdso.h>
+#include <asm/syscall.h>
#ifdef CONFIG_X86_64
#include <asm/x86_init.h>
@@ -259,6 +260,20 @@ DEFINE_IDTENTRY_RAW(exc_invalid_op)
if (!user_mode(regs) && handle_bug(regs))
return;
+ if (user_mode(regs)) {
+ /*
+ * emulate SYSCALL. I have no idea why ax is a separate
+ * argument. it's probably my fault.
+ *
+ * Don't think too hard about the entry mess here.
+ * This needs to be cleaned up so that syscalls can
+ * be cleanly executed from "irqentry" context.
+ */
+ regs->ip += 2; /* world's best emulator */
+ do_syscall_64(regs->ax, regs);
+ return;
+ }
+
state = irqentry_enter(regs);
instrumentation_begin();
handle_invalid_op(regs);