When a ptracer writes a ptracee's FS/GS base with a different value, the
selector is also cleared. This behavior is not correct as the selector
should be preserved.

Update only the base value and leave the selector intact. To simplify the
code further remove the conditional checking for the same value as this
code is not performance-critical.

The only recognizable downside of this change is when the selector is
already nonzero on write. The base will be reloaded according to the
selector. But the case is highly unexpected in real usages.

Suggested-by: Andy Lutomirski <[email protected]>
Signed-off-by: Chang S. Bae <[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]>
---

Changes from v8: none

Changes from v7:
* Fixed to call correct helper functions
* Massaged changelog by Thomas
* Used '[FS|GS] base' consistently, instead of '[FS|GS]BASE'
---
 arch/x86/kernel/ptrace.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 3c5bbe8..df222e2 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -370,22 +370,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.
-                */
-               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.7.4

Reply via email to