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""
This commit is contained in:
commit
02a6ec6a24
|
@ -51,23 +51,15 @@ ret_fast_syscall:
|
||||||
fast_work_pending:
|
fast_work_pending:
|
||||||
str r0, [sp, #S_R0+S_OFF]! @ returned r0
|
str r0, [sp, #S_R0+S_OFF]! @ returned r0
|
||||||
work_pending:
|
work_pending:
|
||||||
tst r1, #_TIF_NEED_RESCHED
|
|
||||||
bne work_resched
|
|
||||||
/*
|
|
||||||
* 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?
|
bl do_work_pending
|
||||||
movne why, #0 @ prevent further restarts
|
cmp r0, #0
|
||||||
bl do_notify_resume
|
beq no_work_pending
|
||||||
b ret_slow_syscall @ Check work again
|
movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)
|
||||||
|
ldmia sp, {r0 - r6} @ have to reload r0 - r6
|
||||||
|
b local_restart @ ... and off we go
|
||||||
|
|
||||||
work_resched:
|
|
||||||
bl schedule
|
|
||||||
/*
|
/*
|
||||||
* "slow" syscall return path. "why" tells us if this was a real syscall.
|
* "slow" syscall return path. "why" tells us if this was a real syscall.
|
||||||
*/
|
*/
|
||||||
|
@ -409,6 +401,7 @@ ENTRY(vector_swi)
|
||||||
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
|
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
local_restart:
|
||||||
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
|
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
|
||||||
stmdb sp!, {r4, r5} @ push fifth and sixth args
|
stmdb sp!, {r4, r5} @ push fifth and sixth args
|
||||||
|
|
||||||
|
@ -450,7 +443,8 @@ __sys_trace:
|
||||||
mov scno, r0 @ syscall number (possibly new)
|
mov scno, r0 @ syscall number (possibly new)
|
||||||
add r1, sp, #S_R0 + S_OFF @ pointer to regs
|
add r1, sp, #S_R0 + S_OFF @ pointer to regs
|
||||||
cmp scno, #NR_syscalls @ check upper syscall limit
|
cmp scno, #NR_syscalls @ check upper syscall limit
|
||||||
ldmccia r1, {r0 - r3} @ have to reload r0 - r3
|
ldmccia r1, {r0 - r6} @ have to reload r0 - r6
|
||||||
|
stmccia sp, {r4, r5} @ and update the stack args
|
||||||
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
|
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
|
||||||
b 2b
|
b 2b
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -27,7 +27,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.
|
||||||
|
@ -47,18 +46,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.
|
||||||
*/
|
*/
|
||||||
|
@ -582,12 +569,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
|
||||||
* the kernel can handle, and then we build all the user-level signal handling
|
* the kernel can handle, and then we build all the user-level signal handling
|
||||||
* stack-frames in one go after that.
|
* stack-frames in one go after that.
|
||||||
*/
|
*/
|
||||||
static void do_signal(struct pt_regs *regs, int syscall)
|
static int do_signal(struct pt_regs *regs, int syscall)
|
||||||
{
|
{
|
||||||
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
|
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
|
||||||
struct k_sigaction ka;
|
struct k_sigaction ka;
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
int signr;
|
int signr;
|
||||||
|
int restart = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we were from a system call, check for system call restarting...
|
* If we were from a system call, check for system call restarting...
|
||||||
|
@ -602,15 +590,15 @@ static void do_signal(struct pt_regs *regs, int syscall)
|
||||||
* debugger will see the already changed PSW.
|
* debugger will see the already changed PSW.
|
||||||
*/
|
*/
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
case -ERESTART_RESTARTBLOCK:
|
||||||
|
restart -= 2;
|
||||||
case -ERESTARTNOHAND:
|
case -ERESTARTNOHAND:
|
||||||
case -ERESTARTSYS:
|
case -ERESTARTSYS:
|
||||||
case -ERESTARTNOINTR:
|
case -ERESTARTNOINTR:
|
||||||
|
restart++;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,14 +607,17 @@ static void do_signal(struct pt_regs *regs, int syscall)
|
||||||
* point the debugger may change all our registers ...
|
* point the debugger may change all our registers ...
|
||||||
*/
|
*/
|
||||||
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||||
|
/*
|
||||||
|
* Depending on the signal settings we may need to revert the
|
||||||
|
* decision to restart the system call. But skip this if a
|
||||||
|
* debugger has chosen to restart at a different PC.
|
||||||
|
*/
|
||||||
|
if (regs->ARM_pc != restart_addr)
|
||||||
|
restart = 0;
|
||||||
if (signr > 0) {
|
if (signr > 0) {
|
||||||
/*
|
if (unlikely(restart)) {
|
||||||
* Depending on the signal settings we may need to revert the
|
if (retval == -ERESTARTNOHAND ||
|
||||||
* decision to restart the system call. But skip this if a
|
retval == -ERESTART_RESTARTBLOCK
|
||||||
* debugger has chosen to restart at a different PC.
|
|
||||||
*/
|
|
||||||
if (regs->ARM_pc == restart_addr) {
|
|
||||||
if (retval == -ERESTARTNOHAND
|
|
||||||
|| (retval == -ERESTARTSYS
|
|| (retval == -ERESTARTSYS
|
||||||
&& !(ka.sa.sa_flags & SA_RESTART))) {
|
&& !(ka.sa.sa_flags & SA_RESTART))) {
|
||||||
regs->ARM_r0 = -EINTR;
|
regs->ARM_r0 = -EINTR;
|
||||||
|
@ -635,52 +626,43 @@ static void do_signal(struct pt_regs *regs, int syscall)
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_signal(signr, &ka, &info, regs);
|
handle_signal(signr, &ka, &info, regs);
|
||||||
return;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (syscall) {
|
|
||||||
/*
|
|
||||||
* Handle restarting a different system call. As above,
|
|
||||||
* if a debugger has chosen to restart at a different PC,
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
restore_saved_sigmask();
|
restore_saved_sigmask();
|
||||||
|
if (unlikely(restart))
|
||||||
|
regs->ARM_pc = continue_addr;
|
||||||
|
return restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void
|
asmlinkage int
|
||||||
do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
|
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
|
||||||
{
|
{
|
||||||
if (thread_flags & _TIF_SIGPENDING)
|
do {
|
||||||
do_signal(regs, syscall);
|
if (likely(thread_flags & _TIF_NEED_RESCHED)) {
|
||||||
|
schedule();
|
||||||
if (thread_flags & _TIF_NOTIFY_RESUME) {
|
} else {
|
||||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
if (unlikely(!user_mode(regs)))
|
||||||
tracehook_notify_resume(regs);
|
return 0;
|
||||||
}
|
local_irq_enable();
|
||||||
|
if (thread_flags & _TIF_SIGPENDING) {
|
||||||
|
int restart = do_signal(regs, syscall);
|
||||||
|
if (unlikely(restart)) {
|
||||||
|
/*
|
||||||
|
* Restart without handlers.
|
||||||
|
* Deal with it without leaving
|
||||||
|
* the kernel space.
|
||||||
|
*/
|
||||||
|
return restart;
|
||||||
|
}
|
||||||
|
syscall = 0;
|
||||||
|
} else {
|
||||||
|
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||||
|
tracehook_notify_resume(regs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local_irq_disable();
|
||||||
|
thread_flags = current_thread_info()->flags;
|
||||||
|
} while (thread_flags & _TIF_WORK_MASK);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
|
||||||
|
|
|
@ -844,8 +844,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);
|
||||||
|
|
Loading…
Reference in New Issue