Re: [PATCH] selftests/x86: Add mov_to_ss

2018-05-14 Thread Ingo Molnar

* Pavel Machek  wrote:

> Hi!
> 
> > +#ifdef __x86_64__
> > +   , "r8", "r9", "r10", "r11"
> > +#endif
> > +   );
> > +   }
> > +
> > +   printf("[OK]\tI aten't dead\n");
> > +   return 0;
> 
> aren't? am not?

It's a joke, Google it ...

Thanks,

Ingo


Re: [PATCH] selftests/x86: Add mov_to_ss

2018-05-14 Thread Ingo Molnar

* Pavel Machek  wrote:

> Hi!
> 
> > +#ifdef __x86_64__
> > +   , "r8", "r9", "r10", "r11"
> > +#endif
> > +   );
> > +   }
> > +
> > +   printf("[OK]\tI aten't dead\n");
> > +   return 0;
> 
> aren't? am not?

It's a joke, Google it ...

Thanks,

Ingo


Re: [PATCH] selftests/x86: Add mov_to_ss

2018-05-13 Thread Pavel Machek
Hi!

> +#ifdef __x86_64__
> + , "r8", "r9", "r10", "r11"
> +#endif
> + );
> + }
> +
> + printf("[OK]\tI aten't dead\n");
> + return 0;

aren't? am not?
Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) 
http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Re: [PATCH] selftests/x86: Add mov_to_ss

2018-05-13 Thread Pavel Machek
Hi!

> +#ifdef __x86_64__
> + , "r8", "r9", "r10", "r11"
> +#endif
> + );
> + }
> +
> + printf("[OK]\tI aten't dead\n");
> + return 0;

aren't? am not?
Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) 
http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


[PATCH] selftests/x86: Add mov_to_ss

2018-05-08 Thread Andy Lutomirski
This exercises a nasty corner case of the x86 ISA.

Signed-off-by: Andy Lutomirski 
---
 tools/testing/selftests/x86/Makefile  |   2 +-
 tools/testing/selftests/x86/mov_ss_trap.c | 285 ++
 2 files changed, 286 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/x86/mov_ss_trap.c

diff --git a/tools/testing/selftests/x86/Makefile 
b/tools/testing/selftests/x86/Makefile
index d744991c0f4f..39f66bc29b82 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -11,7 +11,7 @@ CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) 
trivial_64bit_program.c)
 
 TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt 
test_mremap_vdso \
check_initial_reg_state sigreturn iopl mpx-mini-test 
ioperm \
-   protection_keys test_vdso test_vsyscall
+   protection_keys test_vdso test_vsyscall mov_ss_trap
 TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso 
unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \
vdso_restorer
diff --git a/tools/testing/selftests/x86/mov_ss_trap.c 
b/tools/testing/selftests/x86/mov_ss_trap.c
new file mode 100644
index ..3c3a022654f3
--- /dev/null
+++ b/tools/testing/selftests/x86/mov_ss_trap.c
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mov_ss_trap.c: Exercise the bizarre side effects of a watchpoint on MOV SS
+ *
+ * This does MOV SS from a watchpointed address followed by various
+ * types of kernel entries.  A MOV SS that hits a watchpoint will queue
+ * up a #DB trap but will not actually deliver that trap.  The trap
+ * will be delivered after the next instruction instead.  The CPU's logic
+ * seems to be:
+ *
+ *  - Any fault: drop the pending #DB trap.
+ *  - INT $N, INT3, INTO, SYSCALL, SYSENTER: enter the kernel and then
+ *deliver #DB.
+ *  - ICEBP: enter the kernel but do not deliver the watchpoint trap
+ *  - breakpoint: only one #DB is delivered (phew!)
+ *
+ * There are plenty of ways for a kernel to handle this incorrectly.  This
+ * test tries to exercise all the cases.
+ *
+ * This should mostly cover CVE-2018-1087 and CVE-2018-8897.
+ */
+#define _GNU_SOURCE
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define X86_EFLAGS_RF (1UL << 16)
+
+#if __x86_64__
+# define REG_IP REG_RIP
+#else
+# define REG_IP REG_EIP
+#endif
+
+unsigned short ss;
+extern unsigned char breakpoint_insn[];
+sigjmp_buf jmpbuf;
+static unsigned char altstack_data[SIGSTKSZ];
+
+static void enable_watchpoint(void)
+{
+   pid_t parent = getpid();
+   int status;
+
+   pid_t child = fork();
+   if (child < 0)
+   err(1, "fork");
+
+   if (child) {
+   if (waitpid(child, , 0) != child)
+   err(1, "waitpid for child");
+   } else {
+   unsigned long dr0, dr1, dr7;
+
+   dr0 = (unsigned long)
+   dr1 = (unsigned long)breakpoint_insn;
+   dr7 = ((1UL << 1) | /* G0 */
+  (3UL << 16) |/* RW0 = read or write */
+  (1UL << 18) |/* LEN0 = 2 bytes */
+  (1UL << 3)); /* G1, RW1 = insn */
+
+   if (ptrace(PTRACE_ATTACH, parent, NULL, NULL) != 0)
+   err(1, "PTRACE_ATTACH");
+
+   if (waitpid(parent, , 0) != parent)
+   err(1, "waitpid for child");
+
+   if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct 
user, u_debugreg[0]), dr0) != 0)
+   err(1, "PTRACE_POKEUSER DR0");
+
+   if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct 
user, u_debugreg[1]), dr1) != 0)
+   err(1, "PTRACE_POKEUSER DR1");
+
+   if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct 
user, u_debugreg[7]), dr7) != 0)
+   err(1, "PTRACE_POKEUSER DR7");
+
+   printf("\tDR0 = %lx, DR1 = %lx, DR7 = %lx\n", dr0, dr1, dr7);
+
+   if (ptrace(PTRACE_DETACH, parent, NULL, NULL) != 0)
+   err(1, "PTRACE_DETACH");
+
+   exit(0);
+   }
+}
+
+static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
+  int flags)
+{
+   struct sigaction sa;
+   memset(, 0, sizeof(sa));
+   sa.sa_sigaction = handler;
+   sa.sa_flags = SA_SIGINFO | flags;
+   sigemptyset(_mask);
+   if (sigaction(sig, , 0))
+   err(1, "sigaction");
+}
+
+static char const * const signames[] = {
+   [SIGSEGV] = "SIGSEGV",
+   [SIGBUS] = "SIBGUS",
+   [SIGTRAP] = "SIGTRAP",
+   [SIGILL] = "SIGILL",
+};
+
+static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
+{
+   ucontext_t *ctx = 

[PATCH] selftests/x86: Add mov_to_ss

2018-05-08 Thread Andy Lutomirski
This exercises a nasty corner case of the x86 ISA.

Signed-off-by: Andy Lutomirski 
---
 tools/testing/selftests/x86/Makefile  |   2 +-
 tools/testing/selftests/x86/mov_ss_trap.c | 285 ++
 2 files changed, 286 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/x86/mov_ss_trap.c

diff --git a/tools/testing/selftests/x86/Makefile 
b/tools/testing/selftests/x86/Makefile
index d744991c0f4f..39f66bc29b82 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -11,7 +11,7 @@ CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) 
trivial_64bit_program.c)
 
 TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt 
test_mremap_vdso \
check_initial_reg_state sigreturn iopl mpx-mini-test 
ioperm \
-   protection_keys test_vdso test_vsyscall
+   protection_keys test_vdso test_vsyscall mov_ss_trap
 TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso 
unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \
vdso_restorer
diff --git a/tools/testing/selftests/x86/mov_ss_trap.c 
b/tools/testing/selftests/x86/mov_ss_trap.c
new file mode 100644
index ..3c3a022654f3
--- /dev/null
+++ b/tools/testing/selftests/x86/mov_ss_trap.c
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mov_ss_trap.c: Exercise the bizarre side effects of a watchpoint on MOV SS
+ *
+ * This does MOV SS from a watchpointed address followed by various
+ * types of kernel entries.  A MOV SS that hits a watchpoint will queue
+ * up a #DB trap but will not actually deliver that trap.  The trap
+ * will be delivered after the next instruction instead.  The CPU's logic
+ * seems to be:
+ *
+ *  - Any fault: drop the pending #DB trap.
+ *  - INT $N, INT3, INTO, SYSCALL, SYSENTER: enter the kernel and then
+ *deliver #DB.
+ *  - ICEBP: enter the kernel but do not deliver the watchpoint trap
+ *  - breakpoint: only one #DB is delivered (phew!)
+ *
+ * There are plenty of ways for a kernel to handle this incorrectly.  This
+ * test tries to exercise all the cases.
+ *
+ * This should mostly cover CVE-2018-1087 and CVE-2018-8897.
+ */
+#define _GNU_SOURCE
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define X86_EFLAGS_RF (1UL << 16)
+
+#if __x86_64__
+# define REG_IP REG_RIP
+#else
+# define REG_IP REG_EIP
+#endif
+
+unsigned short ss;
+extern unsigned char breakpoint_insn[];
+sigjmp_buf jmpbuf;
+static unsigned char altstack_data[SIGSTKSZ];
+
+static void enable_watchpoint(void)
+{
+   pid_t parent = getpid();
+   int status;
+
+   pid_t child = fork();
+   if (child < 0)
+   err(1, "fork");
+
+   if (child) {
+   if (waitpid(child, , 0) != child)
+   err(1, "waitpid for child");
+   } else {
+   unsigned long dr0, dr1, dr7;
+
+   dr0 = (unsigned long)
+   dr1 = (unsigned long)breakpoint_insn;
+   dr7 = ((1UL << 1) | /* G0 */
+  (3UL << 16) |/* RW0 = read or write */
+  (1UL << 18) |/* LEN0 = 2 bytes */
+  (1UL << 3)); /* G1, RW1 = insn */
+
+   if (ptrace(PTRACE_ATTACH, parent, NULL, NULL) != 0)
+   err(1, "PTRACE_ATTACH");
+
+   if (waitpid(parent, , 0) != parent)
+   err(1, "waitpid for child");
+
+   if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct 
user, u_debugreg[0]), dr0) != 0)
+   err(1, "PTRACE_POKEUSER DR0");
+
+   if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct 
user, u_debugreg[1]), dr1) != 0)
+   err(1, "PTRACE_POKEUSER DR1");
+
+   if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct 
user, u_debugreg[7]), dr7) != 0)
+   err(1, "PTRACE_POKEUSER DR7");
+
+   printf("\tDR0 = %lx, DR1 = %lx, DR7 = %lx\n", dr0, dr1, dr7);
+
+   if (ptrace(PTRACE_DETACH, parent, NULL, NULL) != 0)
+   err(1, "PTRACE_DETACH");
+
+   exit(0);
+   }
+}
+
+static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
+  int flags)
+{
+   struct sigaction sa;
+   memset(, 0, sizeof(sa));
+   sa.sa_sigaction = handler;
+   sa.sa_flags = SA_SIGINFO | flags;
+   sigemptyset(_mask);
+   if (sigaction(sig, , 0))
+   err(1, "sigaction");
+}
+
+static char const * const signames[] = {
+   [SIGSEGV] = "SIGSEGV",
+   [SIGBUS] = "SIBGUS",
+   [SIGTRAP] = "SIGTRAP",
+   [SIGILL] = "SIGILL",
+};
+
+static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
+{
+   ucontext_t *ctx = ctx_void;
+
+