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

Merge branch 'audit' of git://git.linaro.org/people/rmk/linux-arm

Pull ARM audit/signal updates from Russell King:
"ARM audit/signal handling updates from Al and Will. This improves on
the work Viro did last merge window, and sorts out some of the issues
found with that work."

* 'audit' of git://git.linaro.org/people/rmk/linux-arm:
ARM: 7475/1: sys_trace: allow all syscall arguments to be updated via ptrace
ARM: 7474/1: get rid of TIF_SYSCALL_RESTARTSYS
ARM: 7473/1: deal with handlerless restarts without leaving the kernel
ARM: 7472/1: pull all work_pending logics into C function
ARM: 7471/1: Revert "7442/1: Revert "remove unused restart trampoline""
ARM: 7470/1: Revert "7443/1: Revert "new way of handling ERESTART_RESTARTBLOCK""

+58 -85
+9 -15
arch/arm/kernel/entry-common.S
··· 51 51 fast_work_pending: 52 52 str r0, [sp, #S_R0+S_OFF]! @ returned r0 53 53 work_pending: 54 - tst r1, #_TIF_NEED_RESCHED 55 - bne work_resched 56 - /* 57 - * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here 58 - */ 59 - ldr r2, [sp, #S_PSR] 60 54 mov r0, sp @ 'regs' 61 - tst r2, #15 @ are we returning to user mode? 62 - bne no_work_pending @ no? just leave, then... 63 55 mov r2, why @ 'syscall' 64 - tst r1, #_TIF_SIGPENDING @ delivering a signal? 65 - movne why, #0 @ prevent further restarts 66 - bl do_notify_resume 67 - b ret_slow_syscall @ Check work again 56 + bl do_work_pending 57 + cmp r0, #0 58 + beq no_work_pending 59 + movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE) 60 + ldmia sp, {r0 - r6} @ have to reload r0 - r6 61 + b local_restart @ ... and off we go 68 62 69 - work_resched: 70 - bl schedule 71 63 /* 72 64 * "slow" syscall return path. "why" tells us if this was a real syscall. 73 65 */ ··· 401 409 eor scno, scno, #__NR_SYSCALL_BASE @ check OS number 402 410 #endif 403 411 412 + local_restart: 404 413 ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing 405 414 stmdb sp!, {r4, r5} @ push fifth and sixth args 406 415 ··· 443 450 mov scno, r0 @ syscall number (possibly new) 444 451 add r1, sp, #S_R0 + S_OFF @ pointer to regs 445 452 cmp scno, #NR_syscalls @ check upper syscall limit 446 - ldmccia r1, {r0 - r3} @ have to reload r0 - r3 453 + ldmccia r1, {r0 - r6} @ have to reload r0 - r6 454 + stmccia sp, {r4, r5} @ and update the stack args 447 455 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine 448 456 b 2b 449 457
+1
arch/arm/kernel/ptrace.c
··· 25 25 #include <linux/regset.h> 26 26 #include <linux/audit.h> 27 27 #include <linux/tracehook.h> 28 + #include <linux/unistd.h> 28 29 29 30 #include <asm/pgtable.h> 30 31 #include <asm/traps.h>
+48 -66
arch/arm/kernel/signal.c
··· 27 27 */ 28 28 #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) 29 29 #define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) 30 - #define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE) 31 30 32 31 /* 33 32 * With EABI, the syscall number has to be loaded into r7. ··· 44 45 const unsigned long sigreturn_codes[7] = { 45 46 MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, 46 47 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, 47 - }; 48 - 49 - /* 50 - * Either we support OABI only, or we have EABI with the OABI 51 - * compat layer enabled. In the later case we don't know if 52 - * user space is EABI or not, and if not we must not clobber r7. 53 - * Always using the OABI syscall solves that issue and works for 54 - * all those cases. 55 - */ 56 - const unsigned long syscall_restart_code[2] = { 57 - SWI_SYS_RESTART, /* swi __NR_restart_syscall */ 58 - 0xe49df004, /* ldr pc, [sp], #4 */ 59 48 }; 60 49 61 50 /* ··· 569 582 * the kernel can handle, and then we build all the user-level signal handling 570 583 * stack-frames in one go after that. 571 584 */ 572 - static void do_signal(struct pt_regs *regs, int syscall) 585 + static int do_signal(struct pt_regs *regs, int syscall) 573 586 { 574 587 unsigned int retval = 0, continue_addr = 0, restart_addr = 0; 575 588 struct k_sigaction ka; 576 589 siginfo_t info; 577 590 int signr; 591 + int restart = 0; 578 592 579 593 /* 580 594 * If we were from a system call, check for system call restarting... ··· 590 602 * debugger will see the already changed PSW. 591 603 */ 592 604 switch (retval) { 605 + case -ERESTART_RESTARTBLOCK: 606 + restart -= 2; 593 607 case -ERESTARTNOHAND: 594 608 case -ERESTARTSYS: 595 609 case -ERESTARTNOINTR: 610 + restart++; 596 611 regs->ARM_r0 = regs->ARM_ORIG_r0; 597 612 regs->ARM_pc = restart_addr; 598 - break; 599 - case -ERESTART_RESTARTBLOCK: 600 - regs->ARM_r0 = -EINTR; 601 613 break; 602 614 } 603 615 } ··· 607 619 * point the debugger may change all our registers ... 608 620 */ 609 621 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 622 + /* 623 + * Depending on the signal settings we may need to revert the 624 + * decision to restart the system call. But skip this if a 625 + * debugger has chosen to restart at a different PC. 626 + */ 627 + if (regs->ARM_pc != restart_addr) 628 + restart = 0; 610 629 if (signr > 0) { 611 - /* 612 - * Depending on the signal settings we may need to revert the 613 - * decision to restart the system call. But skip this if a 614 - * debugger has chosen to restart at a different PC. 615 - */ 616 - if (regs->ARM_pc == restart_addr) { 617 - if (retval == -ERESTARTNOHAND 630 + if (unlikely(restart)) { 631 + if (retval == -ERESTARTNOHAND || 632 + retval == -ERESTART_RESTARTBLOCK 618 633 || (retval == -ERESTARTSYS 619 634 && !(ka.sa.sa_flags & SA_RESTART))) { 620 635 regs->ARM_r0 = -EINTR; ··· 626 635 } 627 636 628 637 handle_signal(signr, &ka, &info, regs); 629 - return; 630 - } 631 - 632 - if (syscall) { 633 - /* 634 - * Handle restarting a different system call. As above, 635 - * if a debugger has chosen to restart at a different PC, 636 - * ignore the restart. 637 - */ 638 - if (retval == -ERESTART_RESTARTBLOCK 639 - && regs->ARM_pc == continue_addr) { 640 - if (thumb_mode(regs)) { 641 - regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; 642 - regs->ARM_pc -= 2; 643 - } else { 644 - #if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) 645 - regs->ARM_r7 = __NR_restart_syscall; 646 - regs->ARM_pc -= 4; 647 - #else 648 - u32 __user *usp; 649 - 650 - regs->ARM_sp -= 4; 651 - usp = (u32 __user *)regs->ARM_sp; 652 - 653 - if (put_user(regs->ARM_pc, usp) == 0) { 654 - regs->ARM_pc = KERN_RESTART_CODE; 655 - } else { 656 - regs->ARM_sp += 4; 657 - force_sigsegv(0, current); 658 - } 659 - #endif 660 - } 661 - } 638 + return 0; 662 639 } 663 640 664 641 restore_saved_sigmask(); 642 + if (unlikely(restart)) 643 + regs->ARM_pc = continue_addr; 644 + return restart; 665 645 } 666 646 667 - asmlinkage void 668 - do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) 647 + asmlinkage int 648 + do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) 669 649 { 670 - if (thread_flags & _TIF_SIGPENDING) 671 - do_signal(regs, syscall); 672 - 673 - if (thread_flags & _TIF_NOTIFY_RESUME) { 674 - clear_thread_flag(TIF_NOTIFY_RESUME); 675 - tracehook_notify_resume(regs); 676 - } 650 + do { 651 + if (likely(thread_flags & _TIF_NEED_RESCHED)) { 652 + schedule(); 653 + } else { 654 + if (unlikely(!user_mode(regs))) 655 + return 0; 656 + local_irq_enable(); 657 + if (thread_flags & _TIF_SIGPENDING) { 658 + int restart = do_signal(regs, syscall); 659 + if (unlikely(restart)) { 660 + /* 661 + * Restart without handlers. 662 + * Deal with it without leaving 663 + * the kernel space. 664 + */ 665 + return restart; 666 + } 667 + syscall = 0; 668 + } else { 669 + clear_thread_flag(TIF_NOTIFY_RESUME); 670 + tracehook_notify_resume(regs); 671 + } 672 + } 673 + local_irq_disable(); 674 + thread_flags = current_thread_info()->flags; 675 + } while (thread_flags & _TIF_WORK_MASK); 676 + return 0; 677 677 }
-2
arch/arm/kernel/signal.h
··· 8 8 * published by the Free Software Foundation. 9 9 */ 10 10 #define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) 11 - #define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes)) 12 11 13 12 extern const unsigned long sigreturn_codes[7]; 14 - extern const unsigned long syscall_restart_code[2];
-2
arch/arm/kernel/traps.c
··· 844 844 */ 845 845 memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), 846 846 sigreturn_codes, sizeof(sigreturn_codes)); 847 - memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), 848 - syscall_restart_code, sizeof(syscall_restart_code)); 849 847 850 848 flush_icache_range(vectors, vectors + PAGE_SIZE); 851 849 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);