Commit e696c231 authored by Chang S. Bae's avatar Chang S. Bae Committed by Ingo Molnar

x86/fsgsbase/64: Make ptrace use the new FS/GS base helpers

Use the new FS/GS base helper functions in <asm/fsgsbase.h> in the platform
specific ptrace implementation of the following APIs:

  PTRACE_ARCH_PRCTL,
  PTRACE_SETREG,
  PTRACE_GETREG,
  etc.

The fsgsbase code is more abstracted out this way and the FS/GS-update
mechanism will be easier to change this way.

[ mingo: Wrote new changelog. ]

Based-on-code-from: Andy Lutomirski <luto@kernel.org>
Signed-off-by: default avatarChang S. Bae <chang.seok.bae@intel.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Markus T Metzger <markus.t.metzger@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Shankar <ravi.v.shankar@intel.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1537312139-5580-4-git-send-email-chang.seok.bae@intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent b1378a56
...@@ -8,9 +8,6 @@ ...@@ -8,9 +8,6 @@
#include <asm/msr-index.h> #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 * 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 * the FS/GS base would have (if the task were to be resumed). These
......
...@@ -287,8 +287,8 @@ static __always_inline void load_seg_legacy(unsigned short prev_index, ...@@ -287,8 +287,8 @@ static __always_inline void load_seg_legacy(unsigned short prev_index,
} }
} }
unsigned long x86_fsgsbase_read_task(struct task_struct *task, static unsigned long x86_fsgsbase_read_task(struct task_struct *task,
unsigned short selector) unsigned short selector)
{ {
unsigned short idx = selector >> 3; unsigned short idx = selector >> 3;
unsigned long base; unsigned long base;
...@@ -751,54 +751,25 @@ static long prctl_map_vdso(const struct vdso_image *image, unsigned long addr) ...@@ -751,54 +751,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) long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2)
{ {
int ret = 0; int ret = 0;
int doit = task == current;
int cpu;
switch (option) { switch (option) {
case ARCH_SET_GS: case ARCH_SET_GS: {
if (arg2 >= TASK_SIZE_MAX) ret = x86_gsbase_write_task(task, arg2);
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();
break; break;
case ARCH_SET_FS: }
/* Not strictly needed for fs, but do it for symmetry case ARCH_SET_FS: {
with gs */ ret = x86_fsbase_write_task(task, arg2);
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();
break; break;
}
case ARCH_GET_FS: { 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); ret = put_user(base, (unsigned long __user *)arg2);
break; break;
} }
case ARCH_GET_GS: { 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); ret = put_user(base, (unsigned long __user *)arg2);
break; break;
} }
......
...@@ -397,12 +397,11 @@ static int putreg(struct task_struct *child, ...@@ -397,12 +397,11 @@ static int putreg(struct task_struct *child,
if (value >= TASK_SIZE_MAX) if (value >= TASK_SIZE_MAX)
return -EIO; return -EIO;
/* /*
* When changing the segment base, use do_arch_prctl_64 * When changing the FS base, use the same
* to set either thread.fs or thread.fsindex and the * mechanism as for do_arch_prctl_64().
* corresponding GDT slot.
*/ */
if (child->thread.fsbase != value) if (child->thread.fsbase != value)
return do_arch_prctl_64(child, ARCH_SET_FS, value); return x86_fsbase_write_task(child, value);
return 0; return 0;
case offsetof(struct user_regs_struct,gs_base): case offsetof(struct user_regs_struct,gs_base):
/* /*
...@@ -411,7 +410,7 @@ static int putreg(struct task_struct *child, ...@@ -411,7 +410,7 @@ static int putreg(struct task_struct *child,
if (value >= TASK_SIZE_MAX) if (value >= TASK_SIZE_MAX)
return -EIO; return -EIO;
if (child->thread.gsbase != value) if (child->thread.gsbase != value)
return do_arch_prctl_64(child, ARCH_SET_GS, value); return x86_gsbase_write_task(child, value);
return 0; return 0;
#endif #endif
} }
...@@ -435,20 +434,10 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset) ...@@ -435,20 +434,10 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset)
return get_flags(task); return get_flags(task);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
case offsetof(struct user_regs_struct, fs_base): { case offsetof(struct user_regs_struct, fs_base):
if (task->thread.fsindex == 0) return x86_fsbase_read_task(task);
return task->thread.fsbase; case offsetof(struct user_regs_struct, gs_base):
else return x86_gsbase_read_task(task);
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);
}
#endif #endif
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment