[PATCH] x86_64: Plug GS leak in arch_prctl()
In linux-2.6.16, we have noticed a problem where the gs base value returned from an arch_prtcl(ARCH_GET_GS, ...) call will be incorrect if: - the current/calling task has NOT set its own gs base yet to a non-zero value, - some other task that ran on the same processor previously set their own gs base to a non-zero value. In this situation, the ARCH_GET_GS code will read and return the MSR_KERNEL_GS_BASE msr register. However, since the __switch_to() code does NOT load/zero the MSR_KERNEL_GS_BASE register when the task that is switched IN has a zero next->gs value, the caller of arch_prctl(ARCH_GET_GS, ...) will get back the value of some previous tasks's gs base value instead of 0. Change the arch_prctl() ARCH_GET_GS code to only read and return the MSR_KERNEL_GS_BASE msr register if the 'gs' register of the calling task is non-zero. Side note: Since in addition to using arch_prctl(ARCH_SET_GS, ...), a task can also setup a gs base value by using modify_ldt() and write an index value into 'gs' from user space, the patch below reads 'gs' instead of using thread.gs, since in the modify_ldt() case, the thread.gs value will be 0, and incorrect value would be returned (the task->thread.gs value). When the user has not set its own gs base value and the 'gs' register is zero, then the MSR_KERNEL_GS_BASE register will not be read and a value of zero will be returned by reading and returning 'task->thread.gs'. The first patch shown below is an attempt at implementing this approach. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
e48c4729d2
commit
97c2803c9c
@ -781,10 +781,16 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
|
|||||||
}
|
}
|
||||||
case ARCH_GET_GS: {
|
case ARCH_GET_GS: {
|
||||||
unsigned long base;
|
unsigned long base;
|
||||||
|
unsigned gsindex;
|
||||||
if (task->thread.gsindex == GS_TLS_SEL)
|
if (task->thread.gsindex == GS_TLS_SEL)
|
||||||
base = read_32bit_tls(task, GS_TLS);
|
base = read_32bit_tls(task, GS_TLS);
|
||||||
else if (doit)
|
else if (doit) {
|
||||||
rdmsrl(MSR_KERNEL_GS_BASE, base);
|
asm("movl %%gs,%0" : "=r" (gsindex));
|
||||||
|
if (gsindex)
|
||||||
|
rdmsrl(MSR_KERNEL_GS_BASE, base);
|
||||||
|
else
|
||||||
|
base = task->thread.gs;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
base = task->thread.gs;
|
base = task->thread.gs;
|
||||||
ret = put_user(base, (unsigned long __user *)addr);
|
ret = put_user(base, (unsigned long __user *)addr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user