diff options
author | Andy Lutomirski <luto@kernel.org> | 2020-06-26 10:24:29 -0700 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2020-07-01 15:27:20 +0200 |
commit | 40c45904f818c1f6555294ca27afc5fda4f09e68 (patch) | |
tree | ad8cc885117f022d4b9a6b4ed8f76f294ce7c266 /arch/x86/include | |
parent | 8e259031c67a5ea0666428edb64c89e8c6ebd18e (diff) | |
download | linux-40c45904f818c1f6555294ca27afc5fda4f09e68.tar.gz linux-40c45904f818c1f6555294ca27afc5fda4f09e68.tar.bz2 linux-40c45904f818c1f6555294ca27afc5fda4f09e68.zip |
x86/ptrace: Fix 32-bit PTRACE_SETREGS vs fsbase and gsbase
Debuggers expect that doing PTRACE_GETREGS, then poking at a tracee
and maybe letting it run for a while, then doing PTRACE_SETREGS will
put the tracee back where it was. In the specific case of a 32-bit
tracer and tracee, the PTRACE_GETREGS/SETREGS data structure doesn't
have fs_base or gs_base fields, so FSBASE and GSBASE fields are
never stored anywhere. Everything used to still work because
nonzero FS or GS would result full reloads of the segment registers
when the tracee resumes, and the bases associated with FS==0 or
GS==0 are irrelevant to 32-bit code.
Adding FSGSBASE support broke this: when FSGSBASE is enabled, FSBASE
and GSBASE are now restored independently of FS and GS for all tasks
when context-switched in. This means that, if a 32-bit tracer
restores a previous state using PTRACE_SETREGS but the tracee's
pre-restore and post-restore bases don't match, then the tracee is
resumed with the wrong base.
Fix it by explicitly loading the base when a 32-bit tracer pokes FS
or GS on a 64-bit kernel.
Also add a test case.
Fixes: 673903495c85 ("x86/process/64: Use FSBSBASE in switch_to() if available")
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/229cc6a50ecbb701abd50fe4ddaf0eda888898cd.1593192140.git.luto@kernel.org
Diffstat (limited to 'arch/x86/include')
-rw-r--r-- | arch/x86/include/asm/fsgsbase.h | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/arch/x86/include/asm/fsgsbase.h b/arch/x86/include/asm/fsgsbase.h index aefd53767a5d..d552646411a9 100644 --- a/arch/x86/include/asm/fsgsbase.h +++ b/arch/x86/include/asm/fsgsbase.h @@ -75,6 +75,8 @@ static inline void x86_fsbase_write_cpu(unsigned long fsbase) extern unsigned long x86_gsbase_read_cpu_inactive(void); extern void x86_gsbase_write_cpu_inactive(unsigned long gsbase); +extern unsigned long x86_fsgsbase_read_task(struct task_struct *task, + unsigned short selector); #endif /* CONFIG_X86_64 */ |