Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757232AbcCUQSQ (ORCPT ); Mon, 21 Mar 2016 12:18:16 -0400 Received: from mga11.intel.com ([192.55.52.93]:42805 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756403AbcCUQQP (ORCPT ); Mon, 21 Mar 2016 12:16:15 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.24,372,1455004800"; d="scan'208";a="915706560" From: Andi Kleen To: x86@kernel.org Cc: luto@amacapital.net, linux-kernel@vger.kernel.org, Andi Kleen Subject: [PATCH 8/9] x86: Support arbitrary fs/gs base in getregs Date: Mon, 21 Mar 2016 09:16:08 -0700 Message-Id: <1458576969-13309-9-git-send-email-andi@firstfloor.org> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1458576969-13309-1-git-send-email-andi@firstfloor.org> References: <1458576969-13309-1-git-send-email-andi@firstfloor.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3622 Lines: 120 From: Andi Kleen 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 --- 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 #include #include +#include #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