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 for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1458576969-13309-9-git-send-email-andi@firstfloor.org>
Date:	Mon, 21 Mar 2016 09:16:08 -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 8/9] x86: Support arbitrary fs/gs base in getregs

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

The ptrace code for fs/gs base made some assumptions on
the state of fs/gs which are not true anymore on kernels
running with FSGSBASE.

With the new instructions it is very easy to access
the values, and they are always stored in the thread
struct. So just implement the straight forward code
to access it directly.

Note the direct access code path is only used for core dumps,
as with real ptrace the process is always blocked
and the state can be read from memory.

Signed-off-by: Andi Kleen <ak@...ux.intel.com>
---
 arch/x86/include/asm/proto.h |  1 +
 arch/x86/kernel/process_64.c | 15 +++++++++++++--
 arch/x86/kernel/ptrace.c     | 15 ++++++++++++++-
 3 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h
index 9b9b30b..9f235e0 100644
--- a/arch/x86/include/asm/proto.h
+++ b/arch/x86/include/asm/proto.h
@@ -31,5 +31,6 @@ void x86_report_nx(void);
 extern int reboot_force;
 
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
+unsigned long read_user_gsbase(void);
 
 #endif /* _ASM_X86_PROTO_H */
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 5f40517..d7674d9 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -272,7 +272,7 @@ static noinline __kprobes void switch_gs_base(unsigned long gs)
 }
 
 /* Interrupts are disabled here. */
-static noinline __kprobes unsigned long read_user_gsbase(void)
+static noinline __kprobes unsigned long __read_user_gsbase(void)
 {
 	unsigned long gs;
 
@@ -282,6 +282,17 @@ static noinline __kprobes unsigned long read_user_gsbase(void)
 	return gs;
 }
 
+unsigned long read_user_gsbase(void)
+{
+	unsigned long flags;
+	unsigned long gs;
+
+	local_irq_save(flags);
+	gs = __read_user_gsbase();
+	local_irq_restore(flags);
+	return gs;
+}
+
 /*
  *	switch_to(x,y) should switch tasks from x to y.
  *
@@ -315,7 +326,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 	savesegment(gs, gsindex);
 	if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
 		prev->fs = rdfsbase();
-		prev->gs = read_user_gsbase();
+		prev->gs = __read_user_gsbase();
 	}
 
 	/*
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 32e9d9c..b68b15b 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -38,6 +38,7 @@
 #include <asm/hw_breakpoint.h>
 #include <asm/traps.h>
 #include <asm/syscall.h>
+#include <asm/fsgs.h>
 
 #include "tls.h"
 
@@ -452,12 +453,18 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset)
 
 #ifdef CONFIG_X86_64
 	case offsetof(struct user_regs_struct, fs_base): {
+		unsigned int seg = task->thread.fsindex;
+		if (boot_cpu_has(X86_FEATURE_FSGSBASE)) {
+			if (task == current)
+				return rdfsbase();
+			else
+				return task->thread.fs;
+		}
 		/*
 		 * do_arch_prctl may have used a GDT slot instead of
 		 * the MSR.  To userland, it appears the same either
 		 * way, except the %fs segment selector might not be 0.
 		 */
-		unsigned int seg = task->thread.fsindex;
 		if (task->thread.fs != 0)
 			return task->thread.fs;
 		if (task == current)
@@ -471,6 +478,12 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset)
 		 * Exactly the same here as the %fs handling above.
 		 */
 		unsigned int seg = task->thread.gsindex;
+		if (boot_cpu_has(X86_FEATURE_FSGSBASE)) {
+			if (task == current)
+				return read_user_gsbase();
+			else
+				return task->thread.gs;
+		}
 		if (task->thread.gs != 0)
 			return task->thread.gs;
 		if (task == current)
-- 
2.5.5

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ