• Andy Lutomirski's avatar
    x86/ptrace: Fix 32-bit PTRACE_SETREGS vs fsbase and gsbase · 40c45904
    Andy Lutomirski authored
    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: 67390349 ("x86/process/64: Use FSBSBASE in switch_to() if available")
    Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Link: https://lkml.kernel.org/r/229cc6a50ecbb701abd50fe4ddaf0eda888898cd.1593192140.git.luto@kernel.org
    40c45904
ptrace.c 33.7 KB