mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
[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>
This commit is contained in:
parent
baaa2c512d
commit
2d137c24e9
@ -108,14 +108,15 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
__do_user_fault(struct task_struct *tsk, unsigned long addr,
|
__do_user_fault(struct task_struct *tsk, unsigned long addr,
|
||||||
unsigned int fsr, int code, struct pt_regs *regs)
|
unsigned int fsr, unsigned int sig, int code,
|
||||||
|
struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct siginfo si;
|
struct siginfo si;
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_USER
|
#ifdef CONFIG_DEBUG_USER
|
||||||
if (user_debug & UDBG_SEGV) {
|
if (user_debug & UDBG_SEGV) {
|
||||||
printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n",
|
printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
|
||||||
tsk->comm, addr, fsr);
|
tsk->comm, sig, addr, fsr);
|
||||||
show_pte(tsk->mm, addr);
|
show_pte(tsk->mm, addr);
|
||||||
show_regs(regs);
|
show_regs(regs);
|
||||||
}
|
}
|
||||||
@ -124,11 +125,11 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
|
|||||||
tsk->thread.address = addr;
|
tsk->thread.address = addr;
|
||||||
tsk->thread.error_code = fsr;
|
tsk->thread.error_code = fsr;
|
||||||
tsk->thread.trap_no = 14;
|
tsk->thread.trap_no = 14;
|
||||||
si.si_signo = SIGSEGV;
|
si.si_signo = sig;
|
||||||
si.si_errno = 0;
|
si.si_errno = 0;
|
||||||
si.si_code = code;
|
si.si_code = code;
|
||||||
si.si_addr = (void __user *)addr;
|
si.si_addr = (void __user *)addr;
|
||||||
force_sig_info(SIGSEGV, &si, tsk);
|
force_sig_info(sig, &si, tsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -140,7 +141,7 @@ do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
|
|||||||
* have no context to handle this fault with.
|
* have no context to handle this fault with.
|
||||||
*/
|
*/
|
||||||
if (user_mode(regs))
|
if (user_mode(regs))
|
||||||
__do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs);
|
__do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
|
||||||
else
|
else
|
||||||
__do_kernel_fault(mm, addr, fsr, regs);
|
__do_kernel_fault(mm, addr, fsr, regs);
|
||||||
}
|
}
|
||||||
@ -201,10 +202,11 @@ survive:
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are out of memory for pid1,
|
* If we are out of memory for pid1, sleep for a while and retry
|
||||||
* sleep for a while and retry
|
|
||||||
*/
|
*/
|
||||||
|
up_read(&mm->mmap_sem);
|
||||||
yield();
|
yield();
|
||||||
|
down_read(&mm->mmap_sem);
|
||||||
goto survive;
|
goto survive;
|
||||||
|
|
||||||
check_stack:
|
check_stack:
|
||||||
@ -219,7 +221,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||||||
{
|
{
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
struct mm_struct *mm;
|
struct mm_struct *mm;
|
||||||
int fault;
|
int fault, sig, code;
|
||||||
|
|
||||||
tsk = current;
|
tsk = current;
|
||||||
mm = tsk->mm;
|
mm = tsk->mm;
|
||||||
@ -241,13 +243,6 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||||||
if (fault > 0)
|
if (fault > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* We had some memory, but were unable to
|
|
||||||
* successfully fix up this page fault.
|
|
||||||
*/
|
|
||||||
if (fault == 0)
|
|
||||||
goto do_sigbus;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are in kernel mode at this point, we
|
* If we are in kernel mode at this point, we
|
||||||
* have no context to handle this fault with.
|
* have no context to handle this fault with.
|
||||||
@ -255,43 +250,40 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||||||
if (!user_mode(regs))
|
if (!user_mode(regs))
|
||||||
goto no_context;
|
goto no_context;
|
||||||
|
|
||||||
if (fault == VM_FAULT_OOM) {
|
switch (fault) {
|
||||||
|
case VM_FAULT_OOM:
|
||||||
/*
|
/*
|
||||||
* We ran out of memory, or some other thing happened to
|
* We ran out of memory, or some other thing
|
||||||
* us that made us unable to handle the page fault gracefully.
|
* happened to us that made us unable to handle
|
||||||
|
* the page fault gracefully.
|
||||||
*/
|
*/
|
||||||
printk("VM: killing process %s\n", tsk->comm);
|
printk("VM: killing process %s\n", tsk->comm);
|
||||||
do_exit(SIGKILL);
|
do_exit(SIGKILL);
|
||||||
} else
|
|
||||||
__do_user_fault(tsk, addr, fsr, fault == VM_FAULT_BADACCESS ?
|
|
||||||
SEGV_ACCERR : SEGV_MAPERR, regs);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We ran out of memory, or some other thing happened to us that made
|
|
||||||
* us unable to handle the page fault gracefully.
|
|
||||||
*/
|
|
||||||
do_sigbus:
|
|
||||||
/*
|
|
||||||
* Send a sigbus, regardless of whether we were in kernel
|
|
||||||
* or user mode.
|
|
||||||
*/
|
|
||||||
tsk->thread.address = addr;
|
|
||||||
tsk->thread.error_code = fsr;
|
|
||||||
tsk->thread.trap_no = 14;
|
|
||||||
force_sig(SIGBUS, tsk);
|
|
||||||
#ifdef CONFIG_DEBUG_USER
|
|
||||||
if (user_debug & UDBG_BUS) {
|
|
||||||
printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
|
|
||||||
current->comm, addr, instruction_pointer(regs));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Kernel mode? Handle exceptions or die */
|
|
||||||
if (user_mode(regs))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
/*
|
||||||
|
* We had some memory, but were unable to
|
||||||
|
* successfully fix up this page fault.
|
||||||
|
*/
|
||||||
|
sig = SIGBUS;
|
||||||
|
code = BUS_ADRERR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* Something tried to access memory that
|
||||||
|
* isn't in our memory map..
|
||||||
|
*/
|
||||||
|
sig = SIGSEGV;
|
||||||
|
code = fault == VM_FAULT_BADACCESS ?
|
||||||
|
SEGV_ACCERR : SEGV_MAPERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
__do_user_fault(tsk, addr, fsr, sig, code, regs);
|
||||||
|
return 0;
|
||||||
|
|
||||||
no_context:
|
no_context:
|
||||||
__do_kernel_fault(mm, addr, fsr, regs);
|
__do_kernel_fault(mm, addr, fsr, regs);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user