lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 21 Mar 2016 09:16:07 -0700
From:	Andi Kleen <andi@...stfloor.org>
To:	x86@...nel.org
Cc:	luto@...capital.net, linux-kernel@...r.kernel.org,
	Andi Kleen <ak@...ux.intel.com>
Subject: [PATCH 7/9] x86: Add self test code for fsgsbase

From: Andi Kleen <ak@...ux.intel.com>

Add a simple tester. By default it runs 10000 iterations,
but can also run forever with tfsgs_64 0

Signed-off-by: Andi Kleen <ak@...ux.intel.com>
---
 tools/testing/selftests/x86/Makefile |   3 +-
 tools/testing/selftests/x86/tfsgs.c  | 151 +++++++++++++++++++++++++++++++++++
 2 files changed, 153 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/x86/tfsgs.c

diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index d5ce7d7..e4a3ef9 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -9,11 +9,12 @@ 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 := tfsgs
 
 TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
 TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
 BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
-BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64)
+BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64) $(TARGETS_C_64BIT_ONLY:%=%_64)
 
 CFLAGS := -O2 -g -std=gnu99 -pthread -Wall
 
diff --git a/tools/testing/selftests/x86/tfsgs.c b/tools/testing/selftests/x86/tfsgs.c
new file mode 100644
index 0000000..15bb472
--- /dev/null
+++ b/tools/testing/selftests/x86/tfsgs.c
@@ -0,0 +1,151 @@
+/* Test kernel RD/WR FS/GS BASE support
+ * Run tfsgs 0 to run forever, otherwise iterations (default 10000)
+ * For stress testing run many in parallel to test context switching too
+ *
+ * This program destroys TLS, which means most of normal glibc
+ * doesn't work. So it uses its own libc replacement.
+ *
+ * It also breaks some versions of gdb
+ * (workaround available in https://sourceware.org/bugzilla/show_bug.cgi?id=19684)
+ */
+#include <stdlib.h>
+#include <assert.h>
+#include <asm/prctl.h>
+#include <asm/unistd.h>
+#include <cpuid.h>
+#include <sys/auxv.h>
+#include <elf.h>
+
+#ifndef __always_inline
+#define __always_inline inline __attribute__((always_inline))
+#endif
+
+static __always_inline unsigned long rdgsbase(void)
+{
+	unsigned long gs;
+	asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xc8 # rdgsbaseq %%rax"
+			: "=a" (gs)
+			:: "memory");
+	return gs;
+}
+
+static __always_inline unsigned long rdfsbase(void)
+{
+	unsigned long fs;
+	asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xc0 # rdfsbaseq %%rax"
+			: "=a" (fs)
+			:: "memory");
+	return fs;
+}
+
+static __always_inline void wrgsbase(unsigned long gs)
+{
+	asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xd8 # wrgsbaseq %%rax"
+			:: "a" (gs)
+			: "memory");
+}
+
+static __always_inline void wrfsbase(unsigned long fs)
+{
+	asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xd0 # wrfsbaseq %%rax"
+			:: "a" (fs)
+			: "memory");
+}
+
+/* Custom assert because we can't access errno with changed fs */
+
+int my_strlen(char *s)
+{
+	int len = 0;
+	while (*s++)
+		len++;
+	return len;
+}
+
+int arch_prctl(int cmd, unsigned long arg)
+{
+	int ret;
+	asm volatile("syscall" : "=a" (ret)
+			: "0" (__NR_arch_prctl), "D" (cmd), "S" (arg)
+			: "memory", "rcx", "r11");
+	return ret;
+}
+
+__attribute__((noinline)) void my_assert(int flag, char *msg)
+{
+	if (!flag) {
+		int ret;
+		asm volatile("syscall"
+				: "=a" (ret)
+				: "0" (__NR_write),
+				"D" (2), "S" (msg),
+				"d" (my_strlen(msg))
+				: "memory", "rcx", "r11");
+		*(int *)0 = 0;
+	}
+}
+
+long iter = 10000;
+
+#ifndef bit_FSGSBASE
+#define bit_FSGSBASE 1
+#endif
+
+/* Will be eventually in asm/hwcap.h */
+#define HWCAP2_FSGSBASE        (1 << 0)
+
+unsigned long nfs, ngs, x;
+
+int main(int ac, char **av)
+{
+	long i;
+	unsigned a, b, c, d;
+
+	if (__get_cpuid_max(0, NULL) < 7)
+		exit(0);
+	__cpuid_count(7, 0, a, b, c, d);
+	if (!(b & bit_FSGSBASE))
+		exit(0);
+
+	/* Kernel support? */
+        if (!(getauxval(AT_HWCAP2) & HWCAP2_FSGSBASE))
+		exit(0);
+
+	if (av[1])
+		iter = strtoul(av[1], NULL, 0);
+
+	srandom(1);
+	unsigned long count = random();
+	unsigned long orig_fs = rdfsbase();
+	for (i = 0; i < iter || iter == 0; i++) {
+		unsigned long x = count++;
+		x = ((long)(x << 16)) >> 16; /* sign extend 48->64 */
+
+		wrgsbase(x);
+		wrfsbase(x);
+
+		int i;
+		for (i = 0; i < 1000; i++)
+			asm volatile("pause" ::: "memory");
+
+		ngs = rdgsbase();
+		nfs = rdfsbase();
+
+		my_assert(ngs == x, "gs check 1 failed\n");
+		my_assert(nfs == x, "fs check 1 failed\n");
+
+		unsigned long n;
+		const unsigned long MASK = 0x7fffffffffff;
+		arch_prctl(ARCH_SET_FS, (x + 1) & MASK);
+		arch_prctl(ARCH_SET_GS, (x - 1) & MASK);
+		n = rdfsbase();
+		my_assert(n == ((x + 1) & MASK), "fs check 2 failed\n");
+
+		for (i = 0; i < 1000; i++)
+			asm volatile("pause" ::: "memory");
+
+		n = rdgsbase();
+		my_assert(n == ((x - 1) & MASK), "gs check 2 failed\n");
+	}
+	wrfsbase(orig_fs);
+}
-- 
2.5.5

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ