Commit e94c805f authored by Russell King's avatar Russell King

Merge branch 'for-arm' of...

Merge branch 'for-arm' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal.git into for-linus

Conflicts:
	arch/arm/kernel/ptrace.c
parents ef0c1484 70b58d89
...@@ -148,6 +148,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, ...@@ -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_NOTIFY_RESUME 2 /* callback before returning to user */
#define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_TRACE 8
#define TIF_SYSCALL_AUDIT 9 #define TIF_SYSCALL_AUDIT 9
#define TIF_SYSCALL_RESTARTSYS 10
#define TIF_POLLING_NRFLAG 16 #define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17 #define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */
...@@ -162,16 +163,17 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, ...@@ -162,16 +163,17 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_SYSCALL_RESTARTSYS (1 << TIF_SYSCALL_RESTARTSYS)
/* Checks for any syscall work in entry-common.S */ /* 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 * 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 /* __KERNEL__ */
#endif /* __ASM_ARM_THREAD_INFO_H */ #endif /* __ASM_ARM_THREAD_INFO_H */
...@@ -53,9 +53,13 @@ fast_work_pending: ...@@ -53,9 +53,13 @@ fast_work_pending:
work_pending: work_pending:
tst r1, #_TIF_NEED_RESCHED tst r1, #_TIF_NEED_RESCHED
bne work_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
*/
ldr r2, [sp, #S_PSR]
mov r0, sp @ 'regs' 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' mov r2, why @ 'syscall'
tst r1, #_TIF_SIGPENDING @ delivering a signal? tst r1, #_TIF_SIGPENDING @ delivering a signal?
movne why, #0 @ prevent further restarts movne why, #0 @ prevent further restarts
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/regset.h> #include <linux/regset.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/tracehook.h> #include <linux/tracehook.h>
#include <linux/unistd.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/traps.h> #include <asm/traps.h>
...@@ -917,6 +918,8 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) ...@@ -917,6 +918,8 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); 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)) if (!test_thread_flag(TIF_SYSCALL_TRACE))
return scno; return scno;
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
*/ */
#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) #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_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. * With EABI, the syscall number has to be loaded into r7.
...@@ -49,18 +48,6 @@ const unsigned long sigreturn_codes[7] = { ...@@ -49,18 +48,6 @@ const unsigned long sigreturn_codes[7] = {
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, 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. * atomically swap in the new signal mask, and wait for a signal.
*/ */
...@@ -91,10 +78,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, ...@@ -91,10 +78,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
old_sigset_t mask; old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) || if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) || __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; 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); siginitset(&new_ka.sa.sa_mask, mask);
} }
...@@ -103,10 +90,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, ...@@ -103,10 +90,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
if (!ret && oact) { if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*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_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; 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; return ret;
...@@ -610,15 +597,6 @@ static void do_signal(struct pt_regs *regs, int syscall) ...@@ -610,15 +597,6 @@ static void do_signal(struct pt_regs *regs, int syscall)
siginfo_t info; siginfo_t info;
int signr; 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... * If we were from a system call, check for system call restarting...
*/ */
...@@ -635,18 +613,13 @@ static void do_signal(struct pt_regs *regs, int syscall) ...@@ -635,18 +613,13 @@ static void do_signal(struct pt_regs *regs, int syscall)
case -ERESTARTNOHAND: case -ERESTARTNOHAND:
case -ERESTARTSYS: case -ERESTARTSYS:
case -ERESTARTNOINTR: case -ERESTARTNOINTR:
case -ERESTART_RESTARTBLOCK:
regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_r0 = regs->ARM_ORIG_r0;
regs->ARM_pc = restart_addr; regs->ARM_pc = restart_addr;
break; break;
case -ERESTART_RESTARTBLOCK:
regs->ARM_r0 = -EINTR;
break;
} }
} }
if (try_to_freeze())
goto no_signal;
/* /*
* Get the signal to deliver. When running under ptrace, at this * Get the signal to deliver. When running under ptrace, at this
* point the debugger may change all our registers ... * point the debugger may change all our registers ...
...@@ -661,12 +634,14 @@ static void do_signal(struct pt_regs *regs, int syscall) ...@@ -661,12 +634,14 @@ static void do_signal(struct pt_regs *regs, int syscall)
* debugger has chosen to restart at a different PC. * debugger has chosen to restart at a different PC.
*/ */
if (regs->ARM_pc == restart_addr) { if (regs->ARM_pc == restart_addr) {
if (retval == -ERESTARTNOHAND if (retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS || (retval == -ERESTARTSYS
&& !(ka.sa.sa_flags & SA_RESTART))) { && !(ka.sa.sa_flags & SA_RESTART))) {
regs->ARM_r0 = -EINTR; regs->ARM_r0 = -EINTR;
regs->ARM_pc = continue_addr; regs->ARM_pc = continue_addr;
} }
clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
} }
if (test_thread_flag(TIF_RESTORE_SIGMASK)) if (test_thread_flag(TIF_RESTORE_SIGMASK))
...@@ -686,7 +661,6 @@ static void do_signal(struct pt_regs *regs, int syscall) ...@@ -686,7 +661,6 @@ static void do_signal(struct pt_regs *regs, int syscall)
return; return;
} }
no_signal:
if (syscall) { if (syscall) {
/* /*
* Handle restarting a different system call. As above, * Handle restarting a different system call. As above,
...@@ -694,38 +668,15 @@ static void do_signal(struct pt_regs *regs, int syscall) ...@@ -694,38 +668,15 @@ static void do_signal(struct pt_regs *regs, int syscall)
* ignore the restart. * ignore the restart.
*/ */
if (retval == -ERESTART_RESTARTBLOCK if (retval == -ERESTART_RESTARTBLOCK
&& regs->ARM_pc == continue_addr) { && regs->ARM_pc == restart_addr)
if (thumb_mode(regs)) { set_thread_flag(TIF_SYSCALL_RESTARTSYS);
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
}
} }
/* If there's no signal to deliver, we just put the saved sigmask /* If there's no signal to deliver, we just put the saved sigmask
* back. * back.
*/ */
if (test_thread_flag(TIF_RESTORE_SIGMASK)) { if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
clear_thread_flag(TIF_RESTORE_SIGMASK); set_current_blocked(&current->saved_sigmask);
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
} }
asmlinkage void asmlinkage void
......
...@@ -8,7 +8,5 @@ ...@@ -8,7 +8,5 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) #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 sigreturn_codes[7];
extern const unsigned long syscall_restart_code[2];
...@@ -820,8 +820,6 @@ void __init early_trap_init(void *vectors_base) ...@@ -820,8 +820,6 @@ void __init early_trap_init(void *vectors_base)
*/ */
memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
sigreturn_codes, sizeof(sigreturn_codes)); 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); flush_icache_range(vectors, vectors + PAGE_SIZE);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT); modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment