diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-08-03 05:30:05 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-08-03 05:30:05 -0400 |
commit | e0d407564b532d978b03ceccebd224a05d02f111 (patch) | |
tree | fe3149db4e412e4f1d1e11941fcc260c0e5d287e /arch/arm/kernel/process.c | |
parent | a5463cd3435475386cbbe7b06e01292ac169d36f (diff) |
ARM: fix a cockup in 48be69a02 (ARM: move signal handlers into a vdso-like page)
Unfortunately, I never committed the fix to a nasty oops which can
occur as a result of that commit:
------------[ cut here ]------------
kernel BUG at /home/olof/work/batch/include/linux/mm.h:414!
Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 0 PID: 490 Comm: killall5 Not tainted 3.11.0-rc3-00288-gabe0308 #53
task: e90acac0 ti: e9be8000 task.ti: e9be8000
PC is at special_mapping_fault+0xa4/0xc4
LR is at __do_fault+0x68/0x48c
This doesn't show up unless you do quite a bit of testing; a simple
boot test does not do this, so all my nightly tests were passing fine.
The reason for this is that install_special_mapping() expects the
page array to stick around, and as this was only inserting one page
which was stored on the kernel stack, that's why this was blowing up.
Reported-by: Olof Johansson <olof@lixom.net>
Tested-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel/process.c')
-rw-r--r-- | arch/arm/kernel/process.c | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 1e6c33d01c05..d03b5bd889c5 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -471,17 +471,18 @@ const char *arch_vma_name(struct vm_area_struct *vma) | |||
471 | "[sigpage]" : NULL; | 471 | "[sigpage]" : NULL; |
472 | } | 472 | } |
473 | 473 | ||
474 | static struct page *signal_page; | ||
474 | extern struct page *get_signal_page(void); | 475 | extern struct page *get_signal_page(void); |
475 | 476 | ||
476 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | 477 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) |
477 | { | 478 | { |
478 | struct mm_struct *mm = current->mm; | 479 | struct mm_struct *mm = current->mm; |
479 | struct page *page; | ||
480 | unsigned long addr; | 480 | unsigned long addr; |
481 | int ret; | 481 | int ret; |
482 | 482 | ||
483 | page = get_signal_page(); | 483 | if (!signal_page) |
484 | if (!page) | 484 | signal_page = get_signal_page(); |
485 | if (!signal_page) | ||
485 | return -ENOMEM; | 486 | return -ENOMEM; |
486 | 487 | ||
487 | down_write(&mm->mmap_sem); | 488 | down_write(&mm->mmap_sem); |
@@ -493,7 +494,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | |||
493 | 494 | ||
494 | ret = install_special_mapping(mm, addr, PAGE_SIZE, | 495 | ret = install_special_mapping(mm, addr, PAGE_SIZE, |
495 | VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, | 496 | VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, |
496 | &page); | 497 | &signal_page); |
497 | 498 | ||
498 | if (ret == 0) | 499 | if (ret == 0) |
499 | mm->context.sigpage = addr; | 500 | mm->context.sigpage = addr; |