The FS/GS base helper functions are used on ptrace APIs
(PTRACE_ARCH_PRCTL, PTRACE_SETREG, PTRACE_GETREG, etc).
The FS/GS-update mechanism is now a bit organized.

Based-on-code-from: Andy Lutomirski <l...@kernel.org>
Signed-off-by: Chang S. Bae <chang.seok....@intel.com>
Cc: Andy Lutomirski <l...@kernel.org>
Cc: H. Peter Anvin <h...@zytor.com>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: Ingo Molnar <mi...@kernel.org>
Cc: Andi Kleen <a...@linux.intel.com>
Cc: Dave Hansen <dave.han...@linux.intel.com>
---
 arch/x86/include/asm/fsgsbase.h |  3 ---
 arch/x86/kernel/process_64.c    | 49 +++++++++--------------------------------
 arch/x86/kernel/ptrace.c        | 27 +++++++----------------
 3 files changed, 18 insertions(+), 61 deletions(-)

diff --git a/arch/x86/include/asm/fsgsbase.h b/arch/x86/include/asm/fsgsbase.h
index 0404dab..949eefc 100644
--- a/arch/x86/include/asm/fsgsbase.h
+++ b/arch/x86/include/asm/fsgsbase.h
@@ -8,9 +8,6 @@
 
 #include <asm/msr-index.h>
 
-unsigned long x86_fsgsbase_read_task(struct task_struct *task,
-                                    unsigned short selector);
-
 /*
  * Read/write a task's fsbase or gsbase. This returns the value that
  * the FS/GS base would have (if the task were to be resumed). These
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 52af8c1..710f639 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -285,8 +285,8 @@ static __always_inline void load_seg_legacy(unsigned short 
prev_index,
        }
 }
 
-unsigned long x86_fsgsbase_read_task(struct task_struct *task,
-                                    unsigned short selector)
+static unsigned long x86_fsgsbase_read_task(struct task_struct *task,
+                                           unsigned short selector)
 {
        unsigned short idx = selector >> 3;
        unsigned long base;
@@ -749,54 +749,25 @@ static long prctl_map_vdso(const struct vdso_image 
*image, unsigned long addr)
 long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2)
 {
        int ret = 0;
-       int doit = task == current;
-       int cpu;
 
        switch (option) {
-       case ARCH_SET_GS:
-               if (arg2 >= TASK_SIZE_MAX)
-                       return -EPERM;
-               cpu = get_cpu();
-               task->thread.gsindex = 0;
-               task->thread.gsbase = arg2;
-               if (doit) {
-                       load_gs_index(0);
-                       ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, arg2);
-               }
-               put_cpu();
+       case ARCH_SET_GS: {
+               ret = x86_gsbase_write_task(task, arg2);
                break;
-       case ARCH_SET_FS:
-               /* Not strictly needed for fs, but do it for symmetry
-                  with gs */
-               if (arg2 >= TASK_SIZE_MAX)
-                       return -EPERM;
-               cpu = get_cpu();
-               task->thread.fsindex = 0;
-               task->thread.fsbase = arg2;
-               if (doit) {
-                       /* set the selector to 0 to not confuse __switch_to */
-                       loadsegment(fs, 0);
-                       ret = wrmsrl_safe(MSR_FS_BASE, arg2);
-               }
-               put_cpu();
+       }
+       case ARCH_SET_FS: {
+               ret = x86_fsbase_write_task(task, arg2);
                break;
+       }
        case ARCH_GET_FS: {
-               unsigned long base;
+               unsigned long base = x86_fsbase_read_task(task);
 
-               if (doit)
-                       rdmsrl(MSR_FS_BASE, base);
-               else
-                       base = task->thread.fsbase;
                ret = put_user(base, (unsigned long __user *)arg2);
                break;
        }
        case ARCH_GET_GS: {
-               unsigned long base;
+               unsigned long base = x86_gsbase_read_task(task);
 
-               if (doit)
-                       rdmsrl(MSR_KERNEL_GS_BASE, base);
-               else
-                       base = task->thread.gsbase;
                ret = put_user(base, (unsigned long __user *)arg2);
                break;
        }
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index fbde2a7..d8f49c7 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -397,12 +397,11 @@ static int putreg(struct task_struct *child,
                if (value >= TASK_SIZE_MAX)
                        return -EIO;
                /*
-                * When changing the segment base, use do_arch_prctl_64
-                * to set either thread.fs or thread.fsindex and the
-                * corresponding GDT slot.
+                * When changing the FS base, use the same
+                * mechanism as for do_arch_prctl_64().
                 */
                if (child->thread.fsbase != value)
-                       return do_arch_prctl_64(child, ARCH_SET_FS, value);
+                       return x86_fsbase_write_task(child, value);
                return 0;
        case offsetof(struct user_regs_struct,gs_base):
                /*
@@ -411,7 +410,7 @@ static int putreg(struct task_struct *child,
                if (value >= TASK_SIZE_MAX)
                        return -EIO;
                if (child->thread.gsbase != value)
-                       return do_arch_prctl_64(child, ARCH_SET_GS, value);
+                       return x86_gsbase_write_task(child, value);
                return 0;
 #endif
        }
@@ -435,20 +434,10 @@ static unsigned long getreg(struct task_struct *task, 
unsigned long offset)
                return get_flags(task);
 
 #ifdef CONFIG_X86_64
-       case offsetof(struct user_regs_struct, fs_base): {
-               if (task->thread.fsindex == 0)
-                       return task->thread.fsbase;
-               else
-                       return x86_fsgsbase_read_task(task,
-                                                     task->thread.fsindex);
-       }
-       case offsetof(struct user_regs_struct, gs_base): {
-               if (task->thread.gsindex == 0)
-                       return task->thread.gsbase;
-               else
-                       return x86_fsgsbase_read_task(task,
-                                                     task->thread.gsindex);
-       }
+       case offsetof(struct user_regs_struct, fs_base):
+               return x86_fsbase_read_task(task);
+       case offsetof(struct user_regs_struct, gs_base):
+               return x86_gsbase_read_task(task);
 #endif
        }
 
-- 
2.7.4

Reply via email to