From 7f1b5a9966b176e10d6cd322324a82be2379a51b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:15:42 -0400 Subject: [PATCH 1/9] arm: missing checks of __get_user()/__put_user() return values Acked-by: Russell King Signed-off-by: Al Viro --- arch/arm/kernel/signal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index d68d1b694680..d554025dbcbc 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -91,10 +91,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, old_sigset_t mask; if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } @@ -103,10 +103,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; From 84849b3ed8081e9e2eb0e441c699eda807853cb6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 16:40:34 -0400 Subject: [PATCH 2/9] arm: trim _TIF_WORK_MASK, get rid of useless test and branch... Acked-by: Russell King Signed-off-by: Al Viro --- arch/arm/include/asm/thread_info.h | 2 +- arch/arm/kernel/entry-common.S | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 0f04d84582e1..2d0cfc2ba23c 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -170,7 +170,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, /* * Change these and you break ASM code in entry-common.S */ -#define _TIF_WORK_MASK 0x000000ff +#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME) #endif /* __KERNEL__ */ #endif /* __ASM_ARM_THREAD_INFO_H */ diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 54ee265dd819..82aaf0aeb85d 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -53,8 +53,9 @@ fast_work_pending: work_pending: tst r1, #_TIF_NEED_RESCHED bne work_resched - tst r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME - beq no_work_pending + /* + * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here + */ mov r0, sp @ 'regs' mov r2, why @ 'syscall' tst r1, #_TIF_SIGPENDING @ delivering a signal? From 7dfae72027cd8345247e675a3b27439df95fe06e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 26 Apr 2012 18:15:11 -0400 Subject: [PATCH 3/9] arm: if there's no handler we need to restore sigmask, syscall or no syscall Signed-off-by: Al Viro --- arch/arm/kernel/signal.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index d554025dbcbc..a6c4e780ec7a 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -715,15 +715,13 @@ static void do_signal(struct pt_regs *regs, int syscall) #endif } } - - /* If there's no signal to deliver, we just put the saved sigmask - * back. - */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } } + + /* If there's no signal to deliver, we just put the saved sigmask + * back. + */ + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); } asmlinkage void From d9be5ea6f9b6a51535ccdd9881ffb3be2dbd48e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 27 Apr 2012 01:18:52 -0400 Subject: [PATCH 4/9] arm: don't call try_to_freeze() from do_signal() get_signal_to_deliver() will handle it itself Signed-off-by: Al Viro --- arch/arm/kernel/signal.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index a6c4e780ec7a..3b37c14c47f5 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -642,9 +642,6 @@ static void do_signal(struct pt_regs *regs, int syscall) } } - if (try_to_freeze()) - goto no_signal; - /* * Get the signal to deliver. When running under ptrace, at this * point the debugger may change all our registers ... @@ -684,7 +681,6 @@ static void do_signal(struct pt_regs *regs, int syscall) return; } - no_signal: if (syscall) { /* * Handle restarting a different system call. As above, From 21c1176a72bd019d513b26e05d491a31b50b18d2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 28 Apr 2012 17:51:42 -0400 Subject: [PATCH 5/9] arm: if we get into work_pending while returning to kernel mode, just go away checking in do_signal() is pointless - if we get there with !user_mode(regs) (and we might), we'll end up looping indefinitely. Check in work_pending and break out of the loop if so. Acked-by: Russell King Signed-off-by: Al Viro --- arch/arm/kernel/entry-common.S | 3 +++ arch/arm/kernel/signal.c | 9 --------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 82aaf0aeb85d..b669b49d7cc4 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -56,7 +56,10 @@ work_pending: /* * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here */ + ldr r2, [sp, #S_PSR] mov r0, sp @ 'regs' + tst r2, #15 @ are we returning to user mode? + bne no_work_pending @ no? just leave, then... mov r2, why @ 'syscall' tst r1, #_TIF_SIGPENDING @ delivering a signal? movne why, #0 @ prevent further restarts diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 3b37c14c47f5..6b37d4ddf0b6 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -608,15 +608,6 @@ static void do_signal(struct pt_regs *regs, int syscall) siginfo_t info; int signr; - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (!user_mode(regs)) - return; - /* * If we were from a system call, check for system call restarting... */ From 6b5c8045ecc7e726cdaa2a9d9c8e5008050e1252 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 May 2012 21:02:03 -0400 Subject: [PATCH 6/9] arm: new way of handling ERESTART_RESTARTBLOCK new "syscall start" flag; handled in syscall_trace() by switching syscall number to that of syscall_restart(2). Restarts of that kind (ERESTART_RESTARTBLOCK) are handled by setting that bit; syscall number is not modified until the actual call. Signed-off-by: Al Viro --- arch/arm/include/asm/thread_info.h | 5 ++++- arch/arm/kernel/ptrace.c | 3 +++ arch/arm/kernel/signal.c | 33 ++++++------------------------ 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 2d0cfc2ba23c..680c623a3d1f 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -148,6 +148,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_AUDIT 9 +#define TIF_SYSCALL_RESTARTSYS 10 #define TIF_POLLING_NRFLAG 16 #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ @@ -163,9 +164,11 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_SYSCALL_RESTARTSYS (1 << TIF_SYSCALL_RESTARTSYS) /* Checks for any syscall work in entry-common.S */ -#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT) +#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ + _TIF_SYSCALL_RESTARTSYS) /* * Change these and you break ASM code in entry-common.S diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 9650c143afc1..d407ebf41801 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -916,6 +917,8 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); + if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS)) + scno = __NR_restart_syscall - __NR_SYSCALL_BASE; if (!test_thread_flag(TIF_SYSCALL_TRACE)) return scno; if (!(current->ptrace & PT_PTRACED)) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 6b37d4ddf0b6..75c70d1850df 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -624,12 +624,10 @@ static void do_signal(struct pt_regs *regs, int syscall) case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: + case -ERESTART_RESTARTBLOCK: regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc = restart_addr; break; - case -ERESTART_RESTARTBLOCK: - regs->ARM_r0 = -EINTR; - break; } } @@ -647,12 +645,14 @@ static void do_signal(struct pt_regs *regs, int syscall) * debugger has chosen to restart at a different PC. */ if (regs->ARM_pc == restart_addr) { - if (retval == -ERESTARTNOHAND + if (retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK || (retval == -ERESTARTSYS && !(ka.sa.sa_flags & SA_RESTART))) { regs->ARM_r0 = -EINTR; regs->ARM_pc = continue_addr; } + clear_thread_flag(TIF_SYSCALL_RESTARTSYS); } if (test_thread_flag(TIF_RESTORE_SIGMASK)) @@ -679,29 +679,8 @@ static void do_signal(struct pt_regs *regs, int syscall) * ignore the restart. */ if (retval == -ERESTART_RESTARTBLOCK - && regs->ARM_pc == continue_addr) { - if (thumb_mode(regs)) { - regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; - regs->ARM_pc -= 2; - } else { -#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) - regs->ARM_r7 = __NR_restart_syscall; - regs->ARM_pc -= 4; -#else - u32 __user *usp; - - regs->ARM_sp -= 4; - usp = (u32 __user *)regs->ARM_sp; - - if (put_user(regs->ARM_pc, usp) == 0) { - regs->ARM_pc = KERN_RESTART_CODE; - } else { - regs->ARM_sp += 4; - force_sigsegv(0, current); - } -#endif - } - } + && regs->ARM_pc == restart_addr) + set_thread_flag(TIF_SYSCALL_RESTARTSYS); } /* If there's no signal to deliver, we just put the saved sigmask From fa18484d0947b976a769d15c83c50617493c81c1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 May 2012 21:13:45 -0400 Subject: [PATCH 7/9] arm: remove unused restart trampoline Signed-off-by: Al Viro --- arch/arm/kernel/signal.c | 13 ------------- arch/arm/kernel/signal.h | 2 -- arch/arm/kernel/traps.c | 2 -- 3 files changed, 17 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 75c70d1850df..869c4988fefc 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -29,7 +29,6 @@ */ #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) #define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) -#define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE) /* * With EABI, the syscall number has to be loaded into r7. @@ -49,18 +48,6 @@ const unsigned long sigreturn_codes[7] = { MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, }; -/* - * Either we support OABI only, or we have EABI with the OABI - * compat layer enabled. In the later case we don't know if - * user space is EABI or not, and if not we must not clobber r7. - * Always using the OABI syscall solves that issue and works for - * all those cases. - */ -const unsigned long syscall_restart_code[2] = { - SWI_SYS_RESTART, /* swi __NR_restart_syscall */ - 0xe49df004, /* ldr pc, [sp], #4 */ -}; - /* * atomically swap in the new signal mask, and wait for a signal. */ diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h index 6fcfe8398aa4..5ff067b7c752 100644 --- a/arch/arm/kernel/signal.h +++ b/arch/arm/kernel/signal.h @@ -8,7 +8,5 @@ * published by the Free Software Foundation. */ #define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) -#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes)) extern const unsigned long sigreturn_codes[7]; -extern const unsigned long syscall_restart_code[2]; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 778454750a6c..5aef330e9c54 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -819,8 +819,6 @@ void __init early_trap_init(void *vectors_base) */ memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), sigreturn_codes, sizeof(sigreturn_codes)); - memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), - syscall_restart_code, sizeof(syscall_restart_code)); flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); From 7d181b9626057c1f4fb4d231a3c176271782f459 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 6 May 2012 04:10:18 -0400 Subject: [PATCH 8/9] arm: bury unused _TIF_RESTORE_SIGMASK Signed-off-by: Al Viro --- arch/arm/include/asm/thread_info.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 680c623a3d1f..ba6bb7baadda 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -162,7 +162,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) -#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_SYSCALL_RESTARTSYS (1 << TIF_SYSCALL_RESTARTSYS) From 70b58d896b1b30e4b89d369fbeb244c0e952cf9f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 19 May 2012 14:27:27 -0400 Subject: [PATCH 9/9] arm: don't open-code ptrace_report_syscall() Signed-off-by: Al Viro --- arch/arm/kernel/ptrace.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index d407ebf41801..688a0a970c71 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -932,20 +932,7 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) */ ip = regs->ARM_ip; regs->ARM_ip = why; - - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + ptrace_report_syscall(regs); regs->ARM_ip = ip; return current_thread_info()->syscall;