Commit e0d407564b532d978b03ceccebd224a05d02f111
1 parent
a5463cd343
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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>
Showing 2 changed files with 24 additions and 26 deletions Side-by-side Diff
arch/arm/kernel/process.c
... | ... | @@ -471,17 +471,18 @@ |
471 | 471 | "[sigpage]" : NULL; |
472 | 472 | } |
473 | 473 | |
474 | +static struct page *signal_page; | |
474 | 475 | extern struct page *get_signal_page(void); |
475 | 476 | |
476 | 477 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) |
477 | 478 | { |
478 | 479 | struct mm_struct *mm = current->mm; |
479 | - struct page *page; | |
480 | 480 | unsigned long addr; |
481 | 481 | int ret; |
482 | 482 | |
483 | - page = get_signal_page(); | |
484 | - if (!page) | |
483 | + if (!signal_page) | |
484 | + signal_page = get_signal_page(); | |
485 | + if (!signal_page) | |
485 | 486 | return -ENOMEM; |
486 | 487 | |
487 | 488 | down_write(&mm->mmap_sem); |
... | ... | @@ -493,7 +494,7 @@ |
493 | 494 | |
494 | 495 | ret = install_special_mapping(mm, addr, PAGE_SIZE, |
495 | 496 | VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, |
496 | - &page); | |
497 | + &signal_page); | |
497 | 498 | |
498 | 499 | if (ret == 0) |
499 | 500 | mm->context.sigpage = addr; |
arch/arm/kernel/signal.c
... | ... | @@ -614,36 +614,33 @@ |
614 | 614 | return 0; |
615 | 615 | } |
616 | 616 | |
617 | -static struct page *signal_page; | |
618 | - | |
619 | 617 | struct page *get_signal_page(void) |
620 | 618 | { |
621 | - if (!signal_page) { | |
622 | - unsigned long ptr; | |
623 | - unsigned offset; | |
624 | - void *addr; | |
619 | + unsigned long ptr; | |
620 | + unsigned offset; | |
621 | + struct page *page; | |
622 | + void *addr; | |
625 | 623 | |
626 | - signal_page = alloc_pages(GFP_KERNEL, 0); | |
624 | + page = alloc_pages(GFP_KERNEL, 0); | |
627 | 625 | |
628 | - if (!signal_page) | |
629 | - return NULL; | |
626 | + if (!page) | |
627 | + return NULL; | |
630 | 628 | |
631 | - addr = page_address(signal_page); | |
629 | + addr = page_address(page); | |
632 | 630 | |
633 | - /* Give the signal return code some randomness */ | |
634 | - offset = 0x200 + (get_random_int() & 0x7fc); | |
635 | - signal_return_offset = offset; | |
631 | + /* Give the signal return code some randomness */ | |
632 | + offset = 0x200 + (get_random_int() & 0x7fc); | |
633 | + signal_return_offset = offset; | |
636 | 634 | |
637 | - /* | |
638 | - * Copy signal return handlers into the vector page, and | |
639 | - * set sigreturn to be a pointer to these. | |
640 | - */ | |
641 | - memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes)); | |
635 | + /* | |
636 | + * Copy signal return handlers into the vector page, and | |
637 | + * set sigreturn to be a pointer to these. | |
638 | + */ | |
639 | + memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes)); | |
642 | 640 | |
643 | - ptr = (unsigned long)addr + offset; | |
644 | - flush_icache_range(ptr, ptr + sizeof(sigreturn_codes)); | |
645 | - } | |
641 | + ptr = (unsigned long)addr + offset; | |
642 | + flush_icache_range(ptr, ptr + sizeof(sigreturn_codes)); | |
646 | 643 | |
647 | - return signal_page; | |
644 | + return page; | |
648 | 645 | } |