From: John Blackwood <john.blackwood@ccur.com>
To: linux-kernel@vger.kernel.org
Cc: ak@suse.de, bugsy@ccur.com
Subject: [PATCH] arch/x86_64/kernel/process.c do_arch_prctl() ARCH_GET_GS
Date: Mon, 03 Apr 2006 10:48:41 -0400 [thread overview]
Message-ID: <443135C9.7070008@ccur.com> (raw)
Hi Andi,
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.
I guess that there might be two approaches to fixing this problem:
1. 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.
2. The second approach would would be to the __switch_to() code, and while
it keeps another task's gs base value from lying around in the
MSR_KERNEL_GS_BASE msr register after that task has been switched out,
it does add overhead to __switch_to() when ever the current and/or
next task has a non-zero gs value.
In this case, always write the next tasks's next-gs value to the
MSR_KERNEL_GS_BASE msr register when the previous and/or next task has
a non-zero gsindex or (prev) gs value. Thus, the zero gs base value
will be written into this msr register when ever transitioning from
a non-zero gs base value to a zero gs base value.
This approach is shown below in the 2nd patch.
Maybe one of these approaches could be used as a fix.
I have tested both approaches with tasks that have a 0 gs base value
along with tasks that have set their gs base value with 32 and 64 bit
values via the arch_prctl() ARCH_GET_GS interface, and also with the
modify_ldt()/set gs interface.
Thank you for you time and considerations.
============== Approach 1 =================
diff -up linux-2.6.16/arch/x86_64/kernel/process.c
new/arch/x86_64/kernel/process.c
--- linux-2.6.16/arch/x86_64/kernel/process.c 2006-03-20
00:53:29.000000000 -0500
+++ new/arch/x86_64/kernel/process.c 2006-04-03 09:27:09.000000000 -0400
@@ -794,10 +794,16 @@ long do_arch_prctl(struct task_struct *t
}
case ARCH_GET_GS: {
unsigned long base;
+ unsigned gsindex;
if (task->thread.gsindex == GS_TLS_SEL)
base = read_32bit_tls(task, GS_TLS);
- else if (doit)
- rdmsrl(MSR_KERNEL_GS_BASE, base);
+ else if (doit) {
+ asm("movl %%gs,%0" : "=r" (gsindex));
+ if (gsindex)
+ rdmsrl(MSR_KERNEL_GS_BASE, base);
+ else
+ base = task->thread.gs;
+ }
else
base = task->thread.gs;
ret = put_user(base, (unsigned long __user *)addr);
============== Approach 2 =================
diff -up linux-2.6.16/arch/x86_64/kernel/process.c
new/arch/x86_64/kernel/process.c
--- linux-2.6.16/arch/x86_64/kernel/process.c 2006-04-03
09:29:30.000000000 -0400
+++ new/arch/x86_64/kernel/process.c 2006-04-03 09:35:51.000000000 -0400
@@ -579,8 +579,9 @@ __switch_to(struct task_struct *prev_p,
load_gs_index(next->gsindex);
if (gsindex)
prev->gs = 0;
+ wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
}
- if (next->gs)
+ else if (next->gs)
wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
prev->gsindex = gsindex;
}
next reply other threads:[~2006-04-03 14:48 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-04-03 14:48 John Blackwood [this message]
2006-04-03 10:52 ` [PATCH] arch/x86_64/kernel/process.c do_arch_prctl() ARCH_GET_GS Andi Kleen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=443135C9.7070008@ccur.com \
--to=john.blackwood@ccur.com \
--cc=ak@suse.de \
--cc=bugsy@ccur.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.