From: "Chang S. Bae" <[email protected]> When a ptracer writes a ptracee's FS/GS base with a different value, the selector is also cleared. While this behavior is incorrect as the selector should be preserved, most userspace applications did not notice that as they do not use non-zero segments to begin with.
Instead, with this patch, when a tracee sets the base we will let it do so without clearing the selector. The change above means that a tracee that already has a selector set will fail in an attempt to set the base - the change won't stick and the value will be instead based on the value of the selector. As with the above, we haven't found userspace that would be affected by this change. Suggested-by: Andy Lutomirski <[email protected]> Signed-off-by: Chang S. Bae <[email protected]> [sasha: rewrite commit message] Signed-off-by: Sasha Levin <[email protected]> Reviewed-by: Tony Luck <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Tony Luck <[email protected]> Cc: Andi Kleen <[email protected]> --- arch/x86/kernel/ptrace.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index f0e1ddbc2fd78..cc56efb75d275 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -380,25 +380,12 @@ static int putreg(struct task_struct *child, case offsetof(struct user_regs_struct,fs_base): if (value >= TASK_SIZE_MAX) return -EIO; - /* - * When changing the FS base, use do_arch_prctl_64() - * to set the index to zero and to set the base - * as requested. - * - * NB: This behavior is nonsensical and likely needs to - * change when FSGSBASE support is added. - */ - if (child->thread.fsbase != value) - return do_arch_prctl_64(child, ARCH_SET_FS, value); + x86_fsbase_write_task(child, value); return 0; case offsetof(struct user_regs_struct,gs_base): - /* - * Exactly the same here as the %fs handling above. - */ if (value >= TASK_SIZE_MAX) return -EIO; - if (child->thread.gsbase != value) - return do_arch_prctl_64(child, ARCH_SET_GS, value); + x86_gsbase_write_task(child, value); return 0; #endif } -- 2.20.1

