Skip to content

Commit 02a6ec6

Browse files
committed
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""
2 parents 9a2533c + c7aa00d commit 02a6ec6

File tree

5 files changed

+58
-85
lines changed

5 files changed

+58
-85
lines changed

arch/arm/kernel/entry-common.S

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,15 @@ ret_fast_syscall:
5151
fast_work_pending:
5252
str r0, [sp, #S_R0+S_OFF]! @ returned r0
5353
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]
6054
mov r0, sp @ 'regs'
61-
tst r2, #15 @ are we returning to user mode?
62-
bne no_work_pending @ no? just leave, then...
6355
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
6862

69-
work_resched:
70-
bl schedule
7163
/*
7264
* "slow" syscall return path. "why" tells us if this was a real syscall.
7365
*/
@@ -409,6 +401,7 @@ ENTRY(vector_swi)
409401
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
410402
#endif
411403

404+
local_restart:
412405
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
413406
stmdb sp!, {r4, r5} @ push fifth and sixth args
414407

@@ -450,7 +443,8 @@ __sys_trace:
450443
mov scno, r0 @ syscall number (possibly new)
451444
add r1, sp, #S_R0 + S_OFF @ pointer to regs
452445
cmp scno, #NR_syscalls @ check upper syscall limit
453-
ldmccia r1, {r0 - r3} @ have to reload r0 - r3
446+
ldmccia r1, {r0 - r6} @ have to reload r0 - r6
447+
stmccia sp, {r4, r5} @ and update the stack args
454448
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
455449
b 2b
456450

arch/arm/kernel/ptrace.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/regset.h>
2626
#include <linux/audit.h>
2727
#include <linux/tracehook.h>
28+
#include <linux/unistd.h>
2829

2930
#include <asm/pgtable.h>
3031
#include <asm/traps.h>

arch/arm/kernel/signal.c

Lines changed: 48 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
*/
2828
#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
2929
#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)
3130

3231
/*
3332
* With EABI, the syscall number has to be loaded into r7.
@@ -47,18 +46,6 @@ const unsigned long sigreturn_codes[7] = {
4746
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
4847
};
4948

50-
/*
51-
* Either we support OABI only, or we have EABI with the OABI
52-
* compat layer enabled. In the later case we don't know if
53-
* user space is EABI or not, and if not we must not clobber r7.
54-
* Always using the OABI syscall solves that issue and works for
55-
* all those cases.
56-
*/
57-
const unsigned long syscall_restart_code[2] = {
58-
SWI_SYS_RESTART, /* swi __NR_restart_syscall */
59-
0xe49df004, /* ldr pc, [sp], #4 */
60-
};
61-
6249
/*
6350
* atomically swap in the new signal mask, and wait for a signal.
6451
*/
@@ -582,12 +569,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
582569
* the kernel can handle, and then we build all the user-level signal handling
583570
* stack-frames in one go after that.
584571
*/
585-
static void do_signal(struct pt_regs *regs, int syscall)
572+
static int do_signal(struct pt_regs *regs, int syscall)
586573
{
587574
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
588575
struct k_sigaction ka;
589576
siginfo_t info;
590577
int signr;
578+
int restart = 0;
591579

592580
/*
593581
* 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)
602590
* debugger will see the already changed PSW.
603591
*/
604592
switch (retval) {
593+
case -ERESTART_RESTARTBLOCK:
594+
restart -= 2;
605595
case -ERESTARTNOHAND:
606596
case -ERESTARTSYS:
607597
case -ERESTARTNOINTR:
598+
restart++;
608599
regs->ARM_r0 = regs->ARM_ORIG_r0;
609600
regs->ARM_pc = restart_addr;
610601
break;
611-
case -ERESTART_RESTARTBLOCK:
612-
regs->ARM_r0 = -EINTR;
613-
break;
614602
}
615603
}
616604

@@ -619,14 +607,17 @@ static void do_signal(struct pt_regs *regs, int syscall)
619607
* point the debugger may change all our registers ...
620608
*/
621609
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
610+
/*
611+
* Depending on the signal settings we may need to revert the
612+
* decision to restart the system call. But skip this if a
613+
* debugger has chosen to restart at a different PC.
614+
*/
615+
if (regs->ARM_pc != restart_addr)
616+
restart = 0;
622617
if (signr > 0) {
623-
/*
624-
* Depending on the signal settings we may need to revert the
625-
* decision to restart the system call. But skip this if a
626-
* debugger has chosen to restart at a different PC.
627-
*/
628-
if (regs->ARM_pc == restart_addr) {
629-
if (retval == -ERESTARTNOHAND
618+
if (unlikely(restart)) {
619+
if (retval == -ERESTARTNOHAND ||
620+
retval == -ERESTART_RESTARTBLOCK
630621
|| (retval == -ERESTARTSYS
631622
&& !(ka.sa.sa_flags & SA_RESTART))) {
632623
regs->ARM_r0 = -EINTR;
@@ -635,52 +626,43 @@ static void do_signal(struct pt_regs *regs, int syscall)
635626
}
636627

637628
handle_signal(signr, &ka, &info, regs);
638-
return;
639-
}
640-
641-
if (syscall) {
642-
/*
643-
* Handle restarting a different system call. As above,
644-
* if a debugger has chosen to restart at a different PC,
645-
* ignore the restart.
646-
*/
647-
if (retval == -ERESTART_RESTARTBLOCK
648-
&& regs->ARM_pc == continue_addr) {
649-
if (thumb_mode(regs)) {
650-
regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
651-
regs->ARM_pc -= 2;
652-
} else {
653-
#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
654-
regs->ARM_r7 = __NR_restart_syscall;
655-
regs->ARM_pc -= 4;
656-
#else
657-
u32 __user *usp;
658-
659-
regs->ARM_sp -= 4;
660-
usp = (u32 __user *)regs->ARM_sp;
661-
662-
if (put_user(regs->ARM_pc, usp) == 0) {
663-
regs->ARM_pc = KERN_RESTART_CODE;
664-
} else {
665-
regs->ARM_sp += 4;
666-
force_sigsegv(0, current);
667-
}
668-
#endif
669-
}
670-
}
629+
return 0;
671630
}
672631

673632
restore_saved_sigmask();
633+
if (unlikely(restart))
634+
regs->ARM_pc = continue_addr;
635+
return restart;
674636
}
675637

676-
asmlinkage void
677-
do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
638+
asmlinkage int
639+
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
678640
{
679-
if (thread_flags & _TIF_SIGPENDING)
680-
do_signal(regs, syscall);
681-
682-
if (thread_flags & _TIF_NOTIFY_RESUME) {
683-
clear_thread_flag(TIF_NOTIFY_RESUME);
684-
tracehook_notify_resume(regs);
685-
}
641+
do {
642+
if (likely(thread_flags & _TIF_NEED_RESCHED)) {
643+
schedule();
644+
} else {
645+
if (unlikely(!user_mode(regs)))
646+
return 0;
647+
local_irq_enable();
648+
if (thread_flags & _TIF_SIGPENDING) {
649+
int restart = do_signal(regs, syscall);
650+
if (unlikely(restart)) {
651+
/*
652+
* Restart without handlers.
653+
* Deal with it without leaving
654+
* the kernel space.
655+
*/
656+
return restart;
657+
}
658+
syscall = 0;
659+
} else {
660+
clear_thread_flag(TIF_NOTIFY_RESUME);
661+
tracehook_notify_resume(regs);
662+
}
663+
}
664+
local_irq_disable();
665+
thread_flags = current_thread_info()->flags;
666+
} while (thread_flags & _TIF_WORK_MASK);
667+
return 0;
686668
}

arch/arm/kernel/signal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,5 @@
88
* published by the Free Software Foundation.
99
*/
1010
#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500)
11-
#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
1211

1312
extern const unsigned long sigreturn_codes[7];
14-
extern const unsigned long syscall_restart_code[2];

arch/arm/kernel/traps.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,8 +844,6 @@ void __init early_trap_init(void *vectors_base)
844844
*/
845845
memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
846846
sigreturn_codes, sizeof(sigreturn_codes));
847-
memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
848-
syscall_restart_code, sizeof(syscall_restart_code));
849847

850848
flush_icache_range(vectors, vectors + PAGE_SIZE);
851849
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);

0 commit comments

Comments
 (0)