Skip to content

Commit 433e2f3

Browse files
wildea01Russell King
authored andcommitted
ARM: 7443/1: Revert "new way of handling ERESTART_RESTARTBLOCK"
This reverts commit 6b5c804. Conflicts: arch/arm/kernel/ptrace.c The new syscall restarting code can lead to problems if we take an interrupt in userspace just before restarting the svc instruction. If a signal is delivered when returning from the interrupt, the TIF_SYSCALL_RESTARTSYS will remain set and cause any syscalls executed from the signal handler to be treated as a restart of the previously interrupted system call. This includes the final sigreturn call, meaning that we may fail to exit from the signal context. Furthermore, if a system call made from the signal handler requires a restart via the restart_block, it is possible to clear the thread flag and fail to restart the originally interrupted system call. The right solution to this problem is to perform the restarting in the kernel, avoiding the possibility of handling a further signal before the restart is complete. Since we're almost at -rc6, let's revert the new method for now and aim for in-kernel restarting at a later date. Acked-by: Catalin Marinas <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent 3b0c062 commit 433e2f3

File tree

3 files changed

+28
-13
lines changed

3 files changed

+28
-13
lines changed

arch/arm/include/asm/thread_info.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
148148
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
149149
#define TIF_SYSCALL_TRACE 8
150150
#define TIF_SYSCALL_AUDIT 9
151-
#define TIF_SYSCALL_RESTARTSYS 10
152151
#define TIF_POLLING_NRFLAG 16
153152
#define TIF_USING_IWMMXT 17
154153
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
@@ -164,11 +163,9 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
164163
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
165164
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
166165
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
167-
#define _TIF_SYSCALL_RESTARTSYS (1 << TIF_SYSCALL_RESTARTSYS)
168166

169167
/* Checks for any syscall work in entry-common.S */
170-
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
171-
_TIF_SYSCALL_RESTARTSYS)
168+
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
172169

173170
/*
174171
* Change these and you break ASM code in entry-common.S

arch/arm/kernel/ptrace.c

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

3029
#include <asm/pgtable.h>
3130
#include <asm/traps.h>
@@ -918,8 +917,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
918917
audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
919918
regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
920919

921-
if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS))
922-
scno = __NR_restart_syscall - __NR_SYSCALL_BASE;
923920
if (!test_thread_flag(TIF_SYSCALL_TRACE))
924921
return scno;
925922

arch/arm/kernel/signal.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -605,10 +605,12 @@ static void do_signal(struct pt_regs *regs, int syscall)
605605
case -ERESTARTNOHAND:
606606
case -ERESTARTSYS:
607607
case -ERESTARTNOINTR:
608-
case -ERESTART_RESTARTBLOCK:
609608
regs->ARM_r0 = regs->ARM_ORIG_r0;
610609
regs->ARM_pc = restart_addr;
611610
break;
611+
case -ERESTART_RESTARTBLOCK:
612+
regs->ARM_r0 = -EINTR;
613+
break;
612614
}
613615
}
614616

@@ -624,14 +626,12 @@ static void do_signal(struct pt_regs *regs, int syscall)
624626
* debugger has chosen to restart at a different PC.
625627
*/
626628
if (regs->ARM_pc == restart_addr) {
627-
if (retval == -ERESTARTNOHAND ||
628-
retval == -ERESTART_RESTARTBLOCK
629+
if (retval == -ERESTARTNOHAND
629630
|| (retval == -ERESTARTSYS
630631
&& !(ka.sa.sa_flags & SA_RESTART))) {
631632
regs->ARM_r0 = -EINTR;
632633
regs->ARM_pc = continue_addr;
633634
}
634-
clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
635635
}
636636

637637
handle_signal(signr, &ka, &info, regs);
@@ -645,8 +645,29 @@ static void do_signal(struct pt_regs *regs, int syscall)
645645
* ignore the restart.
646646
*/
647647
if (retval == -ERESTART_RESTARTBLOCK
648-
&& regs->ARM_pc == restart_addr)
649-
set_thread_flag(TIF_SYSCALL_RESTARTSYS);
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+
}
650671
}
651672

652673
restore_saved_sigmask();

0 commit comments

Comments
 (0)