Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] arm: fix SIGBUS handling

)


From: Russell King <rmk+lkml@arm.linux.org.uk>

ARM wasn't raising a SIGBUS with a siginfo structure. Fix
__do_user_fault() to allow us to use it for SIGBUS conditions, and arrange
for the sigbus path to use this.

We need to prevent the siginfo code being called if we do not have a user
space context to call it, so consolidate the "user_mode()" tests.

Thanks to Ian Campbell who spotted this oversight.

Signed-off-by: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

akpm@osdl.org and committed by
Linus Torvalds
2d137c24 baaa2c51

+39 -47
+39 -47
arch/arm/mm/fault.c
··· 108 108 */ 109 109 static void 110 110 __do_user_fault(struct task_struct *tsk, unsigned long addr, 111 - unsigned int fsr, int code, struct pt_regs *regs) 111 + unsigned int fsr, unsigned int sig, int code, 112 + struct pt_regs *regs) 112 113 { 113 114 struct siginfo si; 114 115 115 116 #ifdef CONFIG_DEBUG_USER 116 117 if (user_debug & UDBG_SEGV) { 117 - printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n", 118 - tsk->comm, addr, fsr); 118 + printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n", 119 + tsk->comm, sig, addr, fsr); 119 120 show_pte(tsk->mm, addr); 120 121 show_regs(regs); 121 122 } ··· 125 124 tsk->thread.address = addr; 126 125 tsk->thread.error_code = fsr; 127 126 tsk->thread.trap_no = 14; 128 - si.si_signo = SIGSEGV; 127 + si.si_signo = sig; 129 128 si.si_errno = 0; 130 129 si.si_code = code; 131 130 si.si_addr = (void __user *)addr; 132 - force_sig_info(SIGSEGV, &si, tsk); 131 + force_sig_info(sig, &si, tsk); 133 132 } 134 133 135 134 void ··· 141 140 * have no context to handle this fault with. 142 141 */ 143 142 if (user_mode(regs)) 144 - __do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs); 143 + __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs); 145 144 else 146 145 __do_kernel_fault(mm, addr, fsr, regs); 147 146 } ··· 202 201 goto out; 203 202 204 203 /* 205 - * If we are out of memory for pid1, 206 - * sleep for a while and retry 204 + * If we are out of memory for pid1, sleep for a while and retry 207 205 */ 206 + up_read(&mm->mmap_sem); 208 207 yield(); 208 + down_read(&mm->mmap_sem); 209 209 goto survive; 210 210 211 211 check_stack: ··· 221 219 { 222 220 struct task_struct *tsk; 223 221 struct mm_struct *mm; 224 - int fault; 222 + int fault, sig, code; 225 223 226 224 tsk = current; 227 225 mm = tsk->mm; ··· 244 242 return 0; 245 243 246 244 /* 247 - * We had some memory, but were unable to 248 - * successfully fix up this page fault. 249 - */ 250 - if (fault == 0) 251 - goto do_sigbus; 252 - 253 - /* 254 245 * If we are in kernel mode at this point, we 255 246 * have no context to handle this fault with. 256 247 */ 257 248 if (!user_mode(regs)) 258 249 goto no_context; 259 250 260 - if (fault == VM_FAULT_OOM) { 251 + switch (fault) { 252 + case VM_FAULT_OOM: 261 253 /* 262 - * We ran out of memory, or some other thing happened to 263 - * us that made us unable to handle the page fault gracefully. 254 + * We ran out of memory, or some other thing 255 + * happened to us that made us unable to handle 256 + * the page fault gracefully. 264 257 */ 265 258 printk("VM: killing process %s\n", tsk->comm); 266 259 do_exit(SIGKILL); 267 - } else 268 - __do_user_fault(tsk, addr, fsr, fault == VM_FAULT_BADACCESS ? 269 - SEGV_ACCERR : SEGV_MAPERR, regs); 270 - return 0; 271 - 272 - 273 - /* 274 - * We ran out of memory, or some other thing happened to us that made 275 - * us unable to handle the page fault gracefully. 276 - */ 277 - do_sigbus: 278 - /* 279 - * Send a sigbus, regardless of whether we were in kernel 280 - * or user mode. 281 - */ 282 - tsk->thread.address = addr; 283 - tsk->thread.error_code = fsr; 284 - tsk->thread.trap_no = 14; 285 - force_sig(SIGBUS, tsk); 286 - #ifdef CONFIG_DEBUG_USER 287 - if (user_debug & UDBG_BUS) { 288 - printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n", 289 - current->comm, addr, instruction_pointer(regs)); 290 - } 291 - #endif 292 - 293 - /* Kernel mode? Handle exceptions or die */ 294 - if (user_mode(regs)) 295 260 return 0; 261 + 262 + case 0: 263 + /* 264 + * We had some memory, but were unable to 265 + * successfully fix up this page fault. 266 + */ 267 + sig = SIGBUS; 268 + code = BUS_ADRERR; 269 + break; 270 + 271 + default: 272 + /* 273 + * Something tried to access memory that 274 + * isn't in our memory map.. 275 + */ 276 + sig = SIGSEGV; 277 + code = fault == VM_FAULT_BADACCESS ? 278 + SEGV_ACCERR : SEGV_MAPERR; 279 + break; 280 + } 281 + 282 + __do_user_fault(tsk, addr, fsr, sig, code, regs); 283 + return 0; 296 284 297 285 no_context: 298 286 __do_kernel_fault(mm, addr, fsr, regs);