aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-07-28 08:44:42 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-28 22:28:00 -0400
commitd5a2601734bcc740ee78dc4cb0c56b5687da7bd9 (patch)
tree42146e7eda57909a475ad69cee5cacbf39033cff
parent5d2edfe004f5d0f3d805967bd6b4ada95e6aa419 (diff)
[PATCH] i386/x86-64: Add user_mode checks to profile_pc for oprofile
Fixes a obscure user space triggerable crash during oprofiling. Oprofile calls profile_pc from NMIs even when user_mode(regs) is not true and the program counter is inside the kernel lock section. This opens a race - when a user program jumps to a kernel lock address and a NMI happens before the illegal page fault exception is raised and the program has a unmapped esp or ebp then the kernel could oops. NMIs have a higher priority than exceptions so that could happen. Add user_mode checks to i386/x86-64 profile_pc to prevent that. Cc: John Levon <levon@movementarian.org> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/i386/kernel/time.c2
-rw-r--r--arch/x86_64/kernel/time.c2
2 files changed, 2 insertions, 2 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 8705c0f05788..edd00f6cee37 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -135,7 +135,7 @@ unsigned long profile_pc(struct pt_regs *regs)
135{ 135{
136 unsigned long pc = instruction_pointer(regs); 136 unsigned long pc = instruction_pointer(regs);
137 137
138 if (in_lock_functions(pc)) 138 if (!user_mode_vm(regs) && in_lock_functions(pc))
139 return *(unsigned long *)(regs->ebp + 4); 139 return *(unsigned long *)(regs->ebp + 4);
140 140
141 return pc; 141 return pc;
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index b9ff75992c16..e0341c6808e5 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -193,7 +193,7 @@ unsigned long profile_pc(struct pt_regs *regs)
193 is just accounted to the spinlock function. 193 is just accounted to the spinlock function.
194 Better would be to write these functions in assembler again 194 Better would be to write these functions in assembler again
195 and check exactly. */ 195 and check exactly. */
196 if (in_lock_functions(pc)) { 196 if (!user_mode(regs) && in_lock_functions(pc)) {
197 char *v = *(char **)regs->rsp; 197 char *v = *(char **)regs->rsp;
198 if ((v >= _stext && v <= _etext) || 198 if ((v >= _stext && v <= _etext) ||
199 (v >= _sinittext && v <= _einittext) || 199 (v >= _sinittext && v <= _einittext) ||