* [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5
@ 2012-06-22 15:06 Will Deacon
2012-06-22 15:06 ` [RFC PATCH 1/8] Revert "arm: remove unused restart trampoline" Will Deacon
` (8 more replies)
0 siblings, 9 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:06 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
This RFC series attempts to address the syscall restarting problems
introduced during the merge window and described here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2012-June/104733.html
I reckon the first two reverts should go in for 3.5 unless anybody has
a better solution. The rest of the code is an RFC since, as Russell has
said before, the code is `rather yucky'.
In my effort to avoid breaking strace, I ended up merging in my audit
fixes with this series since keeping the patch sets separate was
becoming a bit of a nightmare given the amount of common code they are
modifying.
Given the mysterious ability of this code to wrap my brain around my
face and beat it with a hammer, I would really appreciate some feedback!
Cheers,
Will
Will Deacon (8):
Revert "arm: remove unused restart trampoline"
Revert "arm: new way of handling ERESTART_RESTARTBLOCK"
audit: arm: only allow syscall auditing for pure EABI userspace
ARM: entry: don't bother with syscall tracing on ret_from_fork path
ARM: audit: move syscall auditing until after ptrace SIGTRAP handling
ARM: ptrace: provide separate functions for tracing syscall
{entry,exit}
ARM: signal: perform restart_block system call restarting in the
kernel
Revert "Revert "arm: remove unused restart trampoline""
arch/arm/include/asm/ptrace.h | 3 ++
arch/arm/include/asm/thread_info.h | 11 +++---
arch/arm/kernel/calls.S | 2 +-
arch/arm/kernel/entry-common.S | 25 ++++++--------
arch/arm/kernel/ptrace.c | 37 +++++++++++++-------
arch/arm/kernel/signal.c | 63 ++++++++++++++++++++++++------------
init/Kconfig | 2 +-
7 files changed, 88 insertions(+), 55 deletions(-)
--
1.7.4.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 1/8] Revert "arm: remove unused restart trampoline"
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
@ 2012-06-22 15:06 ` Will Deacon
2012-06-22 15:07 ` [RFC PATCH 2/8] Revert "arm: new way of handling ERESTART_RESTARTBLOCK" Will Deacon
` (7 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:06 UTC (permalink / raw)
To: linux-arm-kernel
This reverts commit fa18484d0947b976a769d15c83c50617493c81c1.
We need the restart trampoline back so that we can revert a related
problematic patch 6b5c8045ecc7e726cdaa2a9d9c8e5008050e1252 ("arm: new
way of handling ERESTART_RESTARTBLOCK").
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/signal.c | 13 +++++++++++++
arch/arm/kernel/signal.h | 2 ++
arch/arm/kernel/traps.c | 2 ++
3 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index fd2392a..6d3bce5 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -27,6 +27,7 @@
*/
#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.
@@ -47,6 +48,18 @@ const unsigned long sigreturn_codes[7] = {
};
/*
+ * 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.
*/
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
index 5ff067b7..6fcfe83 100644
--- a/arch/arm/kernel/signal.h
+++ b/arch/arm/kernel/signal.h
@@ -8,5 +8,7 @@
* 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 4928d89..3647170 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -820,6 +820,8 @@ 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);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 2/8] Revert "arm: new way of handling ERESTART_RESTARTBLOCK"
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
2012-06-22 15:06 ` [RFC PATCH 1/8] Revert "arm: remove unused restart trampoline" Will Deacon
@ 2012-06-22 15:07 ` Will Deacon
2012-06-22 15:07 ` [RFC PATCH 3/8] audit: arm: only allow syscall auditing for pure EABI userspace Will Deacon
` (6 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:07 UTC (permalink / raw)
To: linux-arm-kernel
This reverts commit 6b5c8045ecc7e726cdaa2a9d9c8e5008050e1252.
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 -rc4, let's revert the new
method for now and aim for in-kernel restarting at a later date.
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/include/asm/thread_info.h | 5 +----
arch/arm/kernel/ptrace.c | 3 ---
arch/arm/kernel/signal.c | 33 +++++++++++++++++++++++++++------
3 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index b79f8e9..af7b0bd 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -148,7 +148,6 @@ 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 */
@@ -164,11 +163,9 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
#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 | \
- _TIF_SYSCALL_RESTARTSYS)
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
/*
* 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 5700a7a..14e3826 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -25,7 +25,6 @@
#include <linux/regset.h>
#include <linux/audit.h>
#include <linux/tracehook.h>
-#include <linux/unistd.h>
#include <asm/pgtable.h>
#include <asm/traps.h>
@@ -918,8 +917,6 @@ 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;
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 6d3bce5..536c5d6 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -605,10 +605,12 @@ 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;
}
}
@@ -624,14 +626,12 @@ 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 ||
- retval == -ERESTART_RESTARTBLOCK
+ if (retval == -ERESTARTNOHAND
|| (retval == -ERESTARTSYS
&& !(ka.sa.sa_flags & SA_RESTART))) {
regs->ARM_r0 = -EINTR;
regs->ARM_pc = continue_addr;
}
- clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
}
handle_signal(signr, &ka, &info, regs);
@@ -645,8 +645,29 @@ static void do_signal(struct pt_regs *regs, int syscall)
* ignore the restart.
*/
if (retval == -ERESTART_RESTARTBLOCK
- && regs->ARM_pc == restart_addr)
- set_thread_flag(TIF_SYSCALL_RESTARTSYS);
+ && 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();
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 3/8] audit: arm: only allow syscall auditing for pure EABI userspace
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
2012-06-22 15:06 ` [RFC PATCH 1/8] Revert "arm: remove unused restart trampoline" Will Deacon
2012-06-22 15:07 ` [RFC PATCH 2/8] Revert "arm: new way of handling ERESTART_RESTARTBLOCK" Will Deacon
@ 2012-06-22 15:07 ` Will Deacon
2012-06-22 15:07 ` [RFC PATCH 4/8] ARM: entry: don't bother with syscall tracing on ret_from_fork path Will Deacon
` (5 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:07 UTC (permalink / raw)
To: linux-arm-kernel
The audit tools support only EABI userspace and, since there are no
AUDIT_ARCH_* defines for the ARM OABI, it makes sense to allow syscall
auditing on ARM only for EABI at the moment.
Cc: Eric Paris <eparis@redhat.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
init/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/init/Kconfig b/init/Kconfig
index d07dcf9..b3f55f1 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -357,7 +357,7 @@ config AUDIT
config AUDITSYSCALL
bool "Enable system-call auditing support"
- depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || ARM)
+ depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || (ARM && AEABI && !OABI_COMPAT))
default y if SECURITY_SELINUX
help
Enable low-overhead system-call auditing infrastructure that
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 4/8] ARM: entry: don't bother with syscall tracing on ret_from_fork path
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
` (2 preceding siblings ...)
2012-06-22 15:07 ` [RFC PATCH 3/8] audit: arm: only allow syscall auditing for pure EABI userspace Will Deacon
@ 2012-06-22 15:07 ` Will Deacon
2012-06-22 15:07 ` [RFC PATCH 5/8] ARM: audit: move syscall auditing until after ptrace SIGTRAP handling Will Deacon
` (4 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:07 UTC (permalink / raw)
To: linux-arm-kernel
ret_from_fork is setup for a freshly spawned child task via copy_thread,
called from copy_process. The latter function clears TIF_SYSCALL_TRACE
and also resets the child task's audit_context to NULL, meaning that
there is little point invoking the system call tracing routines.
Furthermore, getting hold of the syscall number is a complete pain and
it looks like the current code doesn't even bother.
This patch removes the syscall tracing checks from ret_from_fork.
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/entry-common.S | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 4afed88..10911c9 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -95,13 +95,7 @@ ENDPROC(ret_to_user)
ENTRY(ret_from_fork)
bl schedule_tail
get_thread_info tsk
- ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing
mov why, #1
- tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
- beq ret_slow_syscall
- mov r1, sp
- mov r0, #1 @ trace exit [IP = 1]
- bl syscall_trace
b ret_slow_syscall
ENDPROC(ret_from_fork)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 5/8] ARM: audit: move syscall auditing until after ptrace SIGTRAP handling
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
` (3 preceding siblings ...)
2012-06-22 15:07 ` [RFC PATCH 4/8] ARM: entry: don't bother with syscall tracing on ret_from_fork path Will Deacon
@ 2012-06-22 15:07 ` Will Deacon
2012-06-22 15:07 ` [RFC PATCH 6/8] ARM: ptrace: provide separate functions for tracing syscall {entry, exit} Will Deacon
` (3 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:07 UTC (permalink / raw)
To: linux-arm-kernel
When auditing system calls on ARM, the audit code is called before
notifying the parent process in the case that the current task is being
ptraced. At this point, the parent (debugger) may choose to change the
system call being issued via the SET_SYSCALL ptrace request, causing
the wrong system call to be reported to the audit tools.
This patch moves the audit calls after the ptrace SIGTRAP handling code
in the syscall tracing implementation.
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/ptrace.c | 17 +++++++++--------
1 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 14e3826..592a39d 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -911,14 +911,8 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
{
unsigned long ip;
- if (why)
- audit_syscall_exit(regs);
- else
- audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
- regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
-
if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return scno;
+ goto out_no_trace;
current_thread_info()->syscall = scno;
@@ -935,6 +929,13 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
current_thread_info()->syscall = -1;
regs->ARM_ip = ip;
+ scno = current_thread_info()->syscall;
- return current_thread_info()->syscall;
+out_no_trace:
+ if (why)
+ audit_syscall_exit(regs);
+ else
+ audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
+ regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
+ return scno;
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 6/8] ARM: ptrace: provide separate functions for tracing syscall {entry, exit}
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
` (4 preceding siblings ...)
2012-06-22 15:07 ` [RFC PATCH 5/8] ARM: audit: move syscall auditing until after ptrace SIGTRAP handling Will Deacon
@ 2012-06-22 15:07 ` Will Deacon
2012-06-22 15:07 ` [RFC PATCH 7/8] ARM: signal: perform restart_block system call restarting in the kernel Will Deacon
` (2 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:07 UTC (permalink / raw)
To: linux-arm-kernel
The syscall_trace on ARM takes a `why' parameter to indicate whether or
not we are entering or exiting a system call. This can be confusing for
people looking at the code since (a) it conflicts with the why register
alias in the entry assembly code and (b) it is not immediately clear
what it represents.
This patch splits up the syscall_trace function into separate wrappers
for syscall entry and exit, allowing the low-level syscall handling
code to branch to the appropriate function.
Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/entry-common.S | 14 ++++++--------
arch/arm/kernel/ptrace.c | 37 +++++++++++++++++++++++++------------
2 files changed, 31 insertions(+), 20 deletions(-)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 10911c9..49d9f93 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -442,10 +442,9 @@ ENDPROC(vector_swi)
* context switches, and waiting for our parent to respond.
*/
__sys_trace:
- mov r2, scno
- add r1, sp, #S_OFF
- mov r0, #0 @ trace entry [IP = 0]
- bl syscall_trace
+ mov r1, scno
+ add r0, sp, #S_OFF
+ bl syscall_trace_enter
adr lr, BSYM(__sys_trace_return) @ return address
mov scno, r0 @ syscall number (possibly new)
@@ -457,10 +456,9 @@ __sys_trace:
__sys_trace_return:
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
- mov r2, scno
- mov r1, sp
- mov r0, #1 @ trace exit [IP = 1]
- bl syscall_trace
+ mov r1, scno
+ mov r0, sp
+ bl syscall_trace_exit
b ret_slow_syscall
.align 5
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 592a39d..dab711e 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -907,12 +907,18 @@ long arch_ptrace(struct task_struct *child, long request,
return ret;
}
-asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
+enum ptrace_syscall_dir {
+ PTRACE_SYSCALL_ENTER = 0,
+ PTRACE_SYSCALL_EXIT,
+};
+
+static int ptrace_syscall_trace(struct pt_regs *regs, int scno,
+ enum ptrace_syscall_dir dir)
{
unsigned long ip;
if (!test_thread_flag(TIF_SYSCALL_TRACE))
- goto out_no_trace;
+ return scno;
current_thread_info()->syscall = scno;
@@ -921,21 +927,28 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
* IP = 0 -> entry, =1 -> exit
*/
ip = regs->ARM_ip;
- regs->ARM_ip = why;
+ regs->ARM_ip = dir;
- if (why)
+ if (dir == PTRACE_SYSCALL_EXIT)
tracehook_report_syscall_exit(regs, 0);
else if (tracehook_report_syscall_entry(regs))
current_thread_info()->syscall = -1;
regs->ARM_ip = ip;
- scno = current_thread_info()->syscall;
+ return current_thread_info()->syscall;
+}
-out_no_trace:
- if (why)
- audit_syscall_exit(regs);
- else
- audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
- regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
- return scno;
+asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
+{
+ int ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER);
+ audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
+ regs->ARM_r2, regs->ARM_r3);
+ return ret;
+}
+
+asmlinkage int syscall_trace_exit(struct pt_regs *regs, int scno)
+{
+ int ret = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_EXIT);
+ audit_syscall_exit(regs);
+ return ret;
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 7/8] ARM: signal: perform restart_block system call restarting in the kernel
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
` (5 preceding siblings ...)
2012-06-22 15:07 ` [RFC PATCH 6/8] ARM: ptrace: provide separate functions for tracing syscall {entry, exit} Will Deacon
@ 2012-06-22 15:07 ` Will Deacon
2012-06-22 15:07 ` [RFC PATCH 8/8] Revert "Revert "arm: remove unused restart trampoline"" Will Deacon
2012-06-22 19:36 ` [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Al Viro
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:07 UTC (permalink / raw)
To: linux-arm-kernel
This patch moves the restart_block system call restarting into the
kernel and avoids a problematic return to userspace when restarting
system calls failing with -ERESTART_RESTARTBLOCK.
Rather than fake up an svc invocation from kernel space, this patch
jumps directly to a wrapper around sys_restart_syscall on the return
to userspace path if a restart is pending. This allows us to enable
interrupts during do_signal (required by the freezer code) and also
correctly abort a pending restart if we process further signals that
invalidate the restart requirements.
Heavily-inspired-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/include/asm/ptrace.h | 3 +
arch/arm/include/asm/thread_info.h | 6 ++-
arch/arm/kernel/calls.S | 2 +-
arch/arm/kernel/entry-common.S | 5 ++
arch/arm/kernel/signal.c | 86 ++++++++++++++++++------------------
5 files changed, 57 insertions(+), 45 deletions(-)
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 355ece5..93908d5 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -254,6 +254,9 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
return regs->ARM_sp;
}
+extern int syscall_trace_enter(struct pt_regs *regs, int scno);
+extern int syscall_trace_exit(struct pt_regs *regs, int scno);
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index af7b0bd..d3d1689 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -65,6 +65,7 @@ struct thread_info {
#ifdef CONFIG_ARM_THUMBEE
unsigned long thumbee_state; /* ThumbEE Handler Base register */
#endif
+ unsigned long restart_addr;
struct restart_block restart_block;
};
@@ -136,7 +137,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
/*
* thread information flags:
* TIF_SYSCALL_TRACE - syscall trace active
- * TIF_SYSCAL_AUDIT - syscall auditing active
+ * TIF_SYSCALL_AUDIT - syscall auditing active
+ * TIF_SYSCALL_RESTART - syscall restart in progress
* TIF_SIGPENDING - signal pending
* TIF_NEED_RESCHED - rescheduling necessary
* TIF_NOTIFY_RESUME - callback before returning to user
@@ -148,6 +150,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_RESTART 10
#define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
@@ -160,6 +163,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
+#define _TIF_SYSCALL_RESTART (1 << TIF_SYSCALL_RESTART)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 463ff4a..252a140 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -9,7 +9,7 @@
*
* This file is included thrice in entry-common.S
*/
-/* 0 */ CALL(sys_restart_syscall)
+/* 0 */ CALL(sys_ni_syscall) /* was sys_restart_syscall */
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 49d9f93..c2085bf 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -51,6 +51,7 @@ ret_fast_syscall:
fast_work_pending:
str r0, [sp, #S_R0+S_OFF]! @ returned r0
work_pending:
+ enable_irq
tst r1, #_TIF_NEED_RESCHED
bne work_resched
/*
@@ -79,6 +80,10 @@ ENTRY(ret_to_user_from_irq)
tst r1, #_TIF_WORK_MASK
bne work_pending
no_work_pending:
+ tst r1, #_TIF_SYSCALL_RESTART
+ adrne lr, ret_slow_syscall
+ movne why, #1
+ bne do_sys_restart_syscall
#if defined(CONFIG_IRQSOFF_TRACER)
asm_trace_hardirqs_on
#endif
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 536c5d6..8250475 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -11,6 +11,7 @@
#include <linux/signal.h>
#include <linux/personality.h>
#include <linux/freezer.h>
+#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/tracehook.h>
@@ -584,17 +585,17 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
*/
static void do_signal(struct pt_regs *regs, int syscall)
{
- unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
+ unsigned int retval = 0;
struct k_sigaction ka;
siginfo_t info;
int signr;
+ struct thread_info *thread = current_thread_info();
/*
* If we were from a system call, check for system call restarting...
*/
if (syscall) {
- continue_addr = regs->ARM_pc;
- restart_addr = continue_addr - (thumb_mode(regs) ? 2 : 4);
+ thread->restart_addr = regs->ARM_pc - (thumb_mode(regs) ? 2 : 4);
retval = regs->ARM_r0;
/*
@@ -605,11 +606,9 @@ static void do_signal(struct pt_regs *regs, int syscall)
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
- regs->ARM_r0 = regs->ARM_ORIG_r0;
- regs->ARM_pc = restart_addr;
- break;
case -ERESTART_RESTARTBLOCK:
- regs->ARM_r0 = -EINTR;
+ regs->ARM_r0 = regs->ARM_ORIG_r0;
+ regs->ARM_pc = thread->restart_addr;
break;
}
}
@@ -625,12 +624,17 @@ static void do_signal(struct pt_regs *regs, int syscall)
* 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) {
- if (retval == -ERESTARTNOHAND
- || (retval == -ERESTARTSYS
- && !(ka.sa.sa_flags & SA_RESTART))) {
+ if (regs->ARM_pc == thread->restart_addr) {
+ switch (retval) {
+ case -ERESTARTSYS:
+ if (ka.sa.sa_flags & SA_RESTART)
+ break;
+ case -ERESTARTNOHAND:
+ case -ERESTART_RESTARTBLOCK:
regs->ARM_r0 = -EINTR;
- regs->ARM_pc = continue_addr;
+ regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
+ thread->restart_addr = 0;
+ clear_thread_flag(TIF_SYSCALL_RESTART);
}
}
@@ -638,37 +642,14 @@ static void do_signal(struct pt_regs *regs, int syscall)
return;
}
- 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
- }
- }
- }
+ /*
+ * Handle restarting a different system call. As above,
+ * if a debugger has chosen to restart at a different PC,
+ * ignore the restart.
+ */
+ if (syscall && retval == -ERESTART_RESTARTBLOCK &&
+ regs->ARM_pc == thread->restart_addr)
+ set_thread_flag(TIF_SYSCALL_RESTART);
restore_saved_sigmask();
}
@@ -684,3 +665,22 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
tracehook_notify_resume(regs);
}
}
+
+asmlinkage void
+do_sys_restart_syscall(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
+
+ syscall_trace_enter(regs, __NR_restart_syscall);
+
+ if (test_and_clear_thread_flag(TIF_SYSCALL_RESTART)) {
+ local_irq_enable();
+ regs->ARM_r0 = sys_restart_syscall();
+ } else {
+ pr_warning("Attempt to restart syscall without thread flag set!\n");
+ regs->ARM_r0 = -EINTR;
+ }
+
+ syscall_trace_exit(regs, __NR_restart_syscall);
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 8/8] Revert "Revert "arm: remove unused restart trampoline""
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
` (6 preceding siblings ...)
2012-06-22 15:07 ` [RFC PATCH 7/8] ARM: signal: perform restart_block system call restarting in the kernel Will Deacon
@ 2012-06-22 15:07 ` Will Deacon
2012-06-22 19:36 ` [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Al Viro
8 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-22 15:07 UTC (permalink / raw)
To: linux-arm-kernel
This reverts commit b7913c74b230d2f4fbdb6928a099933bb15f8e49.
Now that we perform system call restarting in the kernel, we can safely
remove the OABI restart trampoline.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/signal.c | 13 -------------
arch/arm/kernel/signal.h | 2 --
arch/arm/kernel/traps.c | 2 --
3 files changed, 0 insertions(+), 17 deletions(-)
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 8250475..19b899f 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -28,7 +28,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] = {
};
/*
- * 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.
*/
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
index 6fcfe83..5ff067b7 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 3647170..4928d89 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -820,8 +820,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);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
` (7 preceding siblings ...)
2012-06-22 15:07 ` [RFC PATCH 8/8] Revert "Revert "arm: remove unused restart trampoline"" Will Deacon
@ 2012-06-22 19:36 ` Al Viro
2012-06-25 9:18 ` Will Deacon
8 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2012-06-22 19:36 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Jun 22, 2012 at 04:06:58PM +0100, Will Deacon wrote:
> Hello,
>
> This RFC series attempts to address the syscall restarting problems
> introduced during the merge window and described here:
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-June/104733.html
>
> I reckon the first two reverts should go in for 3.5 unless anybody has
> a better solution. The rest of the code is an RFC since, as Russell has
> said before, the code is `rather yucky'.
See commit 76c3f4da3ee47b68304dbe0f64e86562e7945bf3 and a couiple before it in
signal.git:
commit 76c3f4da3ee47b68304dbe0f64e86562e7945bf3
Author: Al Viro <viro@zeniv.linux.org.uk>
Date: Sat Jun 2 02:11:01 2012 -0400
arm: get rid of TIF_SYSCALL_RESTARTSYS
just let do_work_pending() return 1 on normal local restarts and
-1 on those that had been caused by ERESTART_RESTARTBLOCK (and 0
is still "all done, sod off to userland now"). And let the asm
glue flip scno to restart_syscall(2) one if it got negative from
us...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
commit 9c802c169f964830496be6480ab71d2123cf38a7
Author: Al Viro <viro@zeniv.linux.org.uk>
Date: Sat Jun 2 01:52:18 2012 -0400
arm: deal with handlerless restarts without leaving the kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
commit c1eafa6fc84aaf725e02c7b50ee8a8a748f45b63
Author: Al Viro <viro@zeniv.linux.org.uk>
Date: Fri Jun 1 23:58:57 2012 -0400
arm: pull all work_pending logics into C function
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5
2012-06-22 19:36 ` [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Al Viro
@ 2012-06-25 9:18 ` Will Deacon
2012-06-26 14:33 ` Will Deacon
0 siblings, 1 reply; 12+ messages in thread
From: Will Deacon @ 2012-06-25 9:18 UTC (permalink / raw)
To: linux-arm-kernel
Hi Al,
On Fri, Jun 22, 2012 at 08:36:26PM +0100, Al Viro wrote:
> On Fri, Jun 22, 2012 at 04:06:58PM +0100, Will Deacon wrote:
> > I reckon the first two reverts should go in for 3.5 unless anybody has
> > a better solution. The rest of the code is an RFC since, as Russell has
> > said before, the code is `rather yucky'.
>
> See commit 76c3f4da3ee47b68304dbe0f64e86562e7945bf3 and a couiple before it in
> signal.git:
Thanks, I'll take a look (it may keep me occupied for some time...). Are
these destined for 3.5 or shall we press ahead with the two reverts for now
and fix this properly in the merge window?
Cheers,
Will
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5
2012-06-25 9:18 ` Will Deacon
@ 2012-06-26 14:33 ` Will Deacon
0 siblings, 0 replies; 12+ messages in thread
From: Will Deacon @ 2012-06-26 14:33 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jun 25, 2012 at 10:18:18AM +0100, Will Deacon wrote:
> Hi Al,
Hello again,
> On Fri, Jun 22, 2012 at 08:36:26PM +0100, Al Viro wrote:
> > On Fri, Jun 22, 2012 at 04:06:58PM +0100, Will Deacon wrote:
> > > I reckon the first two reverts should go in for 3.5 unless anybody has
> > > a better solution. The rest of the code is an RFC since, as Russell has
> > > said before, the code is `rather yucky'.
> >
> > See commit 76c3f4da3ee47b68304dbe0f64e86562e7945bf3 and a couiple before it in
> > signal.git:
>
> Thanks, I'll take a look (it may keep me occupied for some time...). Are
> these destined for 3.5 or shall we press ahead with the two reverts for now
> and fix this properly in the merge window?
For what it's worth, your patches look correct to me. The main difference
between my approach and yours is that I continue processing signals even
after the restart requirements have been filled, aborting the restart later
if further signal processing indicates that it's necessary to do so. With
your patches we stop iterating through the signals as soon as we hit a
restart and avoid the problem that way.
POSIX helpfully seems to avoid this scenario and given the asychronous
nature of signals, I'm not sure it matters either way. The only thing I
wonder about is whether restarting a syscall using restart_syscall(2) when
there are further signals pending will cause the syscall to return
-ERESTART_RESTARTBLOCK immediately and we'll go through this long-winded
sequence for each pending signal without a handler installed...
... or am I grossly confused?
Cheers,
Will
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2012-06-26 14:33 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-22 15:06 [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Will Deacon
2012-06-22 15:06 ` [RFC PATCH 1/8] Revert "arm: remove unused restart trampoline" Will Deacon
2012-06-22 15:07 ` [RFC PATCH 2/8] Revert "arm: new way of handling ERESTART_RESTARTBLOCK" Will Deacon
2012-06-22 15:07 ` [RFC PATCH 3/8] audit: arm: only allow syscall auditing for pure EABI userspace Will Deacon
2012-06-22 15:07 ` [RFC PATCH 4/8] ARM: entry: don't bother with syscall tracing on ret_from_fork path Will Deacon
2012-06-22 15:07 ` [RFC PATCH 5/8] ARM: audit: move syscall auditing until after ptrace SIGTRAP handling Will Deacon
2012-06-22 15:07 ` [RFC PATCH 6/8] ARM: ptrace: provide separate functions for tracing syscall {entry, exit} Will Deacon
2012-06-22 15:07 ` [RFC PATCH 7/8] ARM: signal: perform restart_block system call restarting in the kernel Will Deacon
2012-06-22 15:07 ` [RFC PATCH 8/8] Revert "Revert "arm: remove unused restart trampoline"" Will Deacon
2012-06-22 19:36 ` [RFC PATCH 0/8] Fix restart_block syscall restarting for 3.5 Al Viro
2012-06-25 9:18 ` Will Deacon
2012-06-26 14:33 ` Will Deacon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).