aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/trap.c
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2013-09-23 11:38:02 -0400
committerRichard Weinberger <richard@nod.at>2013-11-17 05:27:30 -0500
commitf72c22e45e8f8fe78c7f793d983bee5bed63497e (patch)
tree0e3051e2d357548d086a2ac00c4bfe201fe4e31d /arch/um/kernel/trap.c
parent9d1ee8ce92e16c6aa0a3fd91ee8ed9e403b3a2eb (diff)
um: Make stack trace reliable against kernel mode faults
As UML uses an alternative signal stack we cannot use the current stack pointer for stack dumping if UML itself dies by SIGSEGV. To bypass this issue we save regs taken from mcontext in our segv handler into thread_struct and use these regs to obtain the stack pointer in show_stack(). Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/kernel/trap.c')
-rw-r--r--arch/um/kernel/trap.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 5c3aef74237f..974b87474a99 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -206,9 +206,12 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
206 int is_write = FAULT_WRITE(fi); 206 int is_write = FAULT_WRITE(fi);
207 unsigned long address = FAULT_ADDRESS(fi); 207 unsigned long address = FAULT_ADDRESS(fi);
208 208
209 if (regs)
210 current->thread.segv_regs = container_of(regs, struct pt_regs, regs);
211
209 if (!is_user && (address >= start_vm) && (address < end_vm)) { 212 if (!is_user && (address >= start_vm) && (address < end_vm)) {
210 flush_tlb_kernel_vm(); 213 flush_tlb_kernel_vm();
211 return 0; 214 goto out;
212 } 215 }
213 else if (current->mm == NULL) { 216 else if (current->mm == NULL) {
214 show_regs(container_of(regs, struct pt_regs, regs)); 217 show_regs(container_of(regs, struct pt_regs, regs));
@@ -230,7 +233,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
230 233
231 catcher = current->thread.fault_catcher; 234 catcher = current->thread.fault_catcher;
232 if (!err) 235 if (!err)
233 return 0; 236 goto out;
234 else if (catcher != NULL) { 237 else if (catcher != NULL) {
235 current->thread.fault_addr = (void *) address; 238 current->thread.fault_addr = (void *) address;
236 UML_LONGJMP(catcher, 1); 239 UML_LONGJMP(catcher, 1);
@@ -238,7 +241,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
238 else if (current->thread.fault_addr != NULL) 241 else if (current->thread.fault_addr != NULL)
239 panic("fault_addr set but no fault catcher"); 242 panic("fault_addr set but no fault catcher");
240 else if (!is_user && arch_fixup(ip, regs)) 243 else if (!is_user && arch_fixup(ip, regs))
241 return 0; 244 goto out;
242 245
243 if (!is_user) { 246 if (!is_user) {
244 show_regs(container_of(regs, struct pt_regs, regs)); 247 show_regs(container_of(regs, struct pt_regs, regs));
@@ -262,6 +265,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
262 current->thread.arch.faultinfo = fi; 265 current->thread.arch.faultinfo = fi;
263 force_sig_info(SIGSEGV, &si, current); 266 force_sig_info(SIGSEGV, &si, current);
264 } 267 }
268
269out:
270 if (regs)
271 current->thread.segv_regs = NULL;
272
265 return 0; 273 return 0;
266} 274}
267 275