* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-09-09 4:49 ` AKASHI Takahiro
0 siblings, 0 replies; 15+ messages in thread
From: AKASHI Takahiro @ 2014-09-09 4:49 UTC (permalink / raw)
To: linux, will.deacon
Cc: viro, eparis, rgb, dsaxena, linux-arm-kernel, linaro-kernel,
linux-kernel, linux-audit, AKASHI Takahiro
BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
while syscall auditing is enabled (that is, by starting auditd).
------------[ cut here ]------------
kernel BUG at /home/akashi/arm/armv7/linux/kernel/auditsc.c:1534!
Internal error: Oops - BUG: 0 [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
task: ea0c4380 ti: ea48e000 task.ti: ea48e000
PC is at __audit_syscall_entry+0xe4/0x110
LR is at 0xea0c4380
pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
sp : ea48ff68 ip : 00000001 fp : 0000869c
r10: 00000200 r9 : ea48e000 r8 : c020f4e4
r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: 8a4ac059 DAC: 00000015
Process syscall_arm (pid: 61, stack limit = 0xea48e250)
Stack: (0xea48ff68 to 0xea490000)
ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
[<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
[<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
---[ end trace 0c4441660aba5692 ]---
In fact, syscall(-1) just fails (not signaled despite the expectation,
this is another minor bug), but the succeeding syscall hits BUG_ON.
When auditing syscall(-1), audit_syscall_entry() is called anyway, but
audit_syscall_exit() is not called and then 'in_syscall' flag in thread's
audit context is kept on. In this way, audit_syscall_entry() against
the succeeding syscall will see BUG_ON(in_syscall).
This patch fixes this bug by
1) preventing syscall tracing, ftrace tracepoint and audit, from being
executed in case of invalid or pseudo system calls,
2) handling user-issued syscall(-1) with arm_syscall().
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
arch/arm/include/asm/traps.h | 1 +
arch/arm/kernel/entry-common.S | 4 ++--
arch/arm/kernel/ptrace.c | 47 +++++++++++++++++++++++++---------------
3 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index f555bb3..de01145 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
extern void __init early_trap_init(void *);
extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
+extern int arm_syscall(int no, struct pt_regs *regs);
extern void *vectors_page;
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e52fe5a..28d3931 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -426,7 +426,6 @@ ENTRY(vector_swi)
local_restart:
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
stmdb sp!, {r4, r5} @ push fifth and sixth args
-
tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
bne __sys_trace
@@ -476,10 +475,11 @@ __sys_trace:
cmp scno, #-1 @ skip the syscall?
bne 2b
add sp, sp, #S_OFF @ restore stack
- b ret_slow_syscall
+ b __sys_trace_return_skipped
__sys_trace_return:
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
+__sys_trace_return_skipped:
mov r0, sp
bl syscall_trace_exit
b ret_slow_syscall
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 0c27ed6..68b42cd 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
{
- current_thread_info()->syscall = scno;
+ int orig_scno;
+
+ current_thread_info()->syscall = orig_scno = scno;
/* Do the secure computing check first; failures should be fast. */
if (secure_computing(scno) == -1)
@@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
scno = current_thread_info()->syscall;
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_enter(regs, scno);
+ if (scno >= 0 && scno < NR_syscalls) {
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_enter(regs, scno);
+
+ audit_syscall_entry(AUDIT_ARCH_ARM, scno,
+ regs->ARM_r0, regs->ARM_r1,
+ regs->ARM_r2, regs->ARM_r3);
+ }
- audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
- regs->ARM_r2, regs->ARM_r3);
+ /* user-issued syscall of -1 */
+ if (scno == -1 && orig_scno == -1)
+ arm_syscall(scno, regs);
return scno;
}
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
- /*
- * Audit the syscall before anything else, as a debugger may
- * come in and change the current registers.
- */
- audit_syscall_exit(regs);
+ if (current_thread_info()->syscall < NR_syscalls) {
+ /*
+ * Audit the syscall before anything else, as a debugger may
+ * come in and change the current registers.
+ */
+ audit_syscall_exit(regs);
- /*
- * Note that we haven't updated the ->syscall field for the
- * current thread. This isn't a problem because it will have
- * been set on syscall entry and there hasn't been an opportunity
- * for a PTRACE_SET_SYSCALL since then.
- */
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_exit(regs, regs_return_value(regs));
+ /*
+ * Note that we haven't updated the ->syscall field for the
+ * current thread. This isn't a problem because it will have
+ * been set on syscall entry and there hasn't been
+ * an opportunity for a PTRACE_SET_SYSCALL since then.
+ */
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_exit(regs, regs_return_value(regs));
+ }
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-09-09 4:49 ` AKASHI Takahiro
0 siblings, 0 replies; 15+ messages in thread
From: AKASHI Takahiro @ 2014-09-09 4:49 UTC (permalink / raw)
To: linux-arm-kernel
BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
while syscall auditing is enabled (that is, by starting auditd).
------------[ cut here ]------------
kernel BUG at /home/akashi/arm/armv7/linux/kernel/auditsc.c:1534!
Internal error: Oops - BUG: 0 [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
task: ea0c4380 ti: ea48e000 task.ti: ea48e000
PC is at __audit_syscall_entry+0xe4/0x110
LR is at 0xea0c4380
pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
sp : ea48ff68 ip : 00000001 fp : 0000869c
r10: 00000200 r9 : ea48e000 r8 : c020f4e4
r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: 8a4ac059 DAC: 00000015
Process syscall_arm (pid: 61, stack limit = 0xea48e250)
Stack: (0xea48ff68 to 0xea490000)
ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
[<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
[<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
---[ end trace 0c4441660aba5692 ]---
In fact, syscall(-1) just fails (not signaled despite the expectation,
this is another minor bug), but the succeeding syscall hits BUG_ON.
When auditing syscall(-1), audit_syscall_entry() is called anyway, but
audit_syscall_exit() is not called and then 'in_syscall' flag in thread's
audit context is kept on. In this way, audit_syscall_entry() against
the succeeding syscall will see BUG_ON(in_syscall).
This patch fixes this bug by
1) preventing syscall tracing, ftrace tracepoint and audit, from being
executed in case of invalid or pseudo system calls,
2) handling user-issued syscall(-1) with arm_syscall().
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
arch/arm/include/asm/traps.h | 1 +
arch/arm/kernel/entry-common.S | 4 ++--
arch/arm/kernel/ptrace.c | 47 +++++++++++++++++++++++++---------------
3 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index f555bb3..de01145 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
extern void __init early_trap_init(void *);
extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
+extern int arm_syscall(int no, struct pt_regs *regs);
extern void *vectors_page;
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e52fe5a..28d3931 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -426,7 +426,6 @@ ENTRY(vector_swi)
local_restart:
ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
stmdb sp!, {r4, r5} @ push fifth and sixth args
-
tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
bne __sys_trace
@@ -476,10 +475,11 @@ __sys_trace:
cmp scno, #-1 @ skip the syscall?
bne 2b
add sp, sp, #S_OFF @ restore stack
- b ret_slow_syscall
+ b __sys_trace_return_skipped
__sys_trace_return:
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
+__sys_trace_return_skipped:
mov r0, sp
bl syscall_trace_exit
b ret_slow_syscall
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 0c27ed6..68b42cd 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
{
- current_thread_info()->syscall = scno;
+ int orig_scno;
+
+ current_thread_info()->syscall = orig_scno = scno;
/* Do the secure computing check first; failures should be fast. */
if (secure_computing(scno) == -1)
@@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
scno = current_thread_info()->syscall;
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_enter(regs, scno);
+ if (scno >= 0 && scno < NR_syscalls) {
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_enter(regs, scno);
+
+ audit_syscall_entry(AUDIT_ARCH_ARM, scno,
+ regs->ARM_r0, regs->ARM_r1,
+ regs->ARM_r2, regs->ARM_r3);
+ }
- audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
- regs->ARM_r2, regs->ARM_r3);
+ /* user-issued syscall of -1 */
+ if (scno == -1 && orig_scno == -1)
+ arm_syscall(scno, regs);
return scno;
}
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
- /*
- * Audit the syscall before anything else, as a debugger may
- * come in and change the current registers.
- */
- audit_syscall_exit(regs);
+ if (current_thread_info()->syscall < NR_syscalls) {
+ /*
+ * Audit the syscall before anything else, as a debugger may
+ * come in and change the current registers.
+ */
+ audit_syscall_exit(regs);
- /*
- * Note that we haven't updated the ->syscall field for the
- * current thread. This isn't a problem because it will have
- * been set on syscall entry and there hasn't been an opportunity
- * for a PTRACE_SET_SYSCALL since then.
- */
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_exit(regs, regs_return_value(regs));
+ /*
+ * Note that we haven't updated the ->syscall field for the
+ * current thread. This isn't a problem because it will have
+ * been set on syscall entry and there hasn't been
+ * an opportunity for a PTRACE_SET_SYSCALL since then.
+ */
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_exit(regs, regs_return_value(regs));
+ }
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
2014-09-09 4:49 ` AKASHI Takahiro
(?)
@ 2014-09-11 16:37 ` Will Deacon
-1 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2014-09-11 16:37 UTC (permalink / raw)
To: AKASHI Takahiro
Cc: linux, viro, eparis, rgb, dsaxena, linux-arm-kernel,
linaro-kernel, linux-kernel, linux-audit
Hi Akashi,
On Tue, Sep 09, 2014 at 05:49:59AM +0100, AKASHI Takahiro wrote:
> BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
> while syscall auditing is enabled (that is, by starting auditd).
[...]
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..28d3931 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -426,7 +426,6 @@ ENTRY(vector_swi)
> local_restart:
> ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
> stmdb sp!, {r4, r5} @ push fifth and sixth args
> -
You don't need this cosmetic change.
> tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
> bne __sys_trace
>
> @@ -476,10 +475,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
Can't you just remove the add as well, them fall-through here?
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..68b42cd 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
Is this supposed to work for OABI? If so, better use __NR_SYSCALL_BASE.
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
> +
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + }
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + /* user-issued syscall of -1 */
> + if (scno == -1 && orig_scno == -1)
Make this an else if, for clarity?
> + arm_syscall(scno, regs);
Doesn't this always result in bad_syscall being called, which sends a SIGILL
to the task? Shouldn't we simply return -ENOSYS instead? You could do that
in the assembly code.
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
Again, not going to work for OABI.
Will
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-09-11 16:37 ` Will Deacon
0 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2014-09-11 16:37 UTC (permalink / raw)
To: AKASHI Takahiro
Cc: linux, viro, eparis, rgb, dsaxena, linux-arm-kernel,
linaro-kernel, linux-kernel, linux-audit
Hi Akashi,
On Tue, Sep 09, 2014 at 05:49:59AM +0100, AKASHI Takahiro wrote:
> BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
> while syscall auditing is enabled (that is, by starting auditd).
[...]
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..28d3931 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -426,7 +426,6 @@ ENTRY(vector_swi)
> local_restart:
> ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
> stmdb sp!, {r4, r5} @ push fifth and sixth args
> -
You don't need this cosmetic change.
> tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
> bne __sys_trace
>
> @@ -476,10 +475,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
Can't you just remove the add as well, them fall-through here?
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..68b42cd 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
Is this supposed to work for OABI? If so, better use __NR_SYSCALL_BASE.
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
> +
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + }
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + /* user-issued syscall of -1 */
> + if (scno == -1 && orig_scno == -1)
Make this an else if, for clarity?
> + arm_syscall(scno, regs);
Doesn't this always result in bad_syscall being called, which sends a SIGILL
to the task? Shouldn't we simply return -ENOSYS instead? You could do that
in the assembly code.
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
Again, not going to work for OABI.
Will
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-09-11 16:37 ` Will Deacon
0 siblings, 0 replies; 15+ messages in thread
From: Will Deacon @ 2014-09-11 16:37 UTC (permalink / raw)
To: linux-arm-kernel
Hi Akashi,
On Tue, Sep 09, 2014 at 05:49:59AM +0100, AKASHI Takahiro wrote:
> BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
> while syscall auditing is enabled (that is, by starting auditd).
[...]
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..28d3931 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -426,7 +426,6 @@ ENTRY(vector_swi)
> local_restart:
> ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
> stmdb sp!, {r4, r5} @ push fifth and sixth args
> -
You don't need this cosmetic change.
> tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
> bne __sys_trace
>
> @@ -476,10 +475,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
Can't you just remove the add as well, them fall-through here?
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..68b42cd 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
Is this supposed to work for OABI? If so, better use __NR_SYSCALL_BASE.
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
> +
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + }
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + /* user-issued syscall of -1 */
> + if (scno == -1 && orig_scno == -1)
Make this an else if, for clarity?
> + arm_syscall(scno, regs);
Doesn't this always result in bad_syscall being called, which sends a SIGILL
to the task? Shouldn't we simply return -ENOSYS instead? You could do that
in the assembly code.
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
Again, not going to work for OABI.
Will
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
2014-09-11 16:37 ` Will Deacon
(?)
@ 2014-09-16 0:17 ` AKASHI Takahiro
-1 siblings, 0 replies; 15+ messages in thread
From: AKASHI Takahiro @ 2014-09-16 0:17 UTC (permalink / raw)
To: Will Deacon
Cc: linux, viro, eparis, rgb, dsaxena, linux-arm-kernel,
linaro-kernel, linux-kernel, linux-audit
Will,
Sorry for not responding quickly.
On 09/11/2014 09:37 AM, Will Deacon wrote:
> Hi Akashi,
>
> On Tue, Sep 09, 2014 at 05:49:59AM +0100, AKASHI Takahiro wrote:
>> BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
>> while syscall auditing is enabled (that is, by starting auditd).
>
> [...]
>
>> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
>> index f555bb3..de01145 100644
>> --- a/arch/arm/include/asm/traps.h
>> +++ b/arch/arm/include/asm/traps.h
>> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
>> extern void __init early_trap_init(void *);
>> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
>> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
>> +extern int arm_syscall(int no, struct pt_regs *regs);
>>
>> extern void *vectors_page;
>>
>> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
>> index e52fe5a..28d3931 100644
>> --- a/arch/arm/kernel/entry-common.S
>> +++ b/arch/arm/kernel/entry-common.S
>> @@ -426,7 +426,6 @@ ENTRY(vector_swi)
>> local_restart:
>> ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
>> stmdb sp!, {r4, r5} @ push fifth and sixth args
>> -
>
> You don't need this cosmetic change.
Typo. I will fix it.
>> tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
>> bne __sys_trace
>>
>> @@ -476,10 +475,11 @@ __sys_trace:
>> cmp scno, #-1 @ skip the syscall?
>> bne 2b
>> add sp, sp, #S_OFF @ restore stack
>> - b ret_slow_syscall
>> + b __sys_trace_return_skipped
>
> Can't you just remove the add as well, them fall-through here?
I'm afraid that we can't remove this branch because we don't want to override
a value of r0 in regs which a tracer may have already changed while skipping
a syscall.
>>
>> __sys_trace_return:
>> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
>> +__sys_trace_return_skipped:
>> mov r0, sp
>> bl syscall_trace_exit
>> b ret_slow_syscall
>> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
>> index 0c27ed6..68b42cd 100644
>> --- a/arch/arm/kernel/ptrace.c
>> +++ b/arch/arm/kernel/ptrace.c
>> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>>
>> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>> {
>> - current_thread_info()->syscall = scno;
>> + int orig_scno;
>> +
>> + current_thread_info()->syscall = orig_scno = scno;
>>
>> /* Do the secure computing check first; failures should be fast. */
>> if (secure_computing(scno) == -1)
>> @@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>>
>> scno = current_thread_info()->syscall;
>>
>> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> - trace_sys_enter(regs, scno);
>> + if (scno >= 0 && scno < NR_syscalls) {
>
> Is this supposed to work for OABI? If so, better use __NR_SYSCALL_BASE.
Good point. I'm not quite sure how it works for OABI, but looking into entry-comon.S,
there is some code:
> #if defined(CONFIG_OABI_COMPAT)
> bics r10, r10, #0xff000000
> eorne scno, r10, #__NR_OABI_SYSCALL_BASE
> ldrne tbl, =sys_oabi_call_table
> #elif !defined(CONFIG_AEABI)
> bic scno, scno, #0xff000000 @ mask off SWI op-code
> eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
> #endif
>
> local_restart:
It seems to me that scno, actually r7 in regs, is already offset.
>> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> + trace_sys_enter(regs, scno);
>> +
>> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
>> + regs->ARM_r0, regs->ARM_r1,
>> + regs->ARM_r2, regs->ARM_r3);
>> + }
>>
>> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
>> - regs->ARM_r2, regs->ARM_r3);
>> + /* user-issued syscall of -1 */
>> + if (scno == -1 && orig_scno == -1)
>
> Make this an else if, for clarity?
Sure. I will fix it.
>> + arm_syscall(scno, regs);
>
> Doesn't this always result in bad_syscall being called, which sends a SIGILL
> to the task? Shouldn't we simply return -ENOSYS instead? You could do that
> in the assembly code.
I meant so (that is, resulting in bad_syscall).
As I mentioned earlier, a task calling syscall(-1, or whatever native value) is always
signaled on arm. Meanwhile, whether it is intended or not, this behavior is not simulated
in the current arm64 compat syscalls.
>> return scno;
>> }
>>
>> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
>> {
>> - /*
>> - * Audit the syscall before anything else, as a debugger may
>> - * come in and change the current registers.
>> - */
>> - audit_syscall_exit(regs);
>> + if (current_thread_info()->syscall < NR_syscalls) {
>
> Again, not going to work for OABI.
The same comment above.
Thanks,
-Takahiro AKASHI
> Will
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-09-16 0:17 ` AKASHI Takahiro
0 siblings, 0 replies; 15+ messages in thread
From: AKASHI Takahiro @ 2014-09-16 0:17 UTC (permalink / raw)
To: Will Deacon
Cc: linux, viro, eparis, rgb, dsaxena, linux-arm-kernel,
linaro-kernel, linux-kernel, linux-audit
Will,
Sorry for not responding quickly.
On 09/11/2014 09:37 AM, Will Deacon wrote:
> Hi Akashi,
>
> On Tue, Sep 09, 2014 at 05:49:59AM +0100, AKASHI Takahiro wrote:
>> BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
>> while syscall auditing is enabled (that is, by starting auditd).
>
> [...]
>
>> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
>> index f555bb3..de01145 100644
>> --- a/arch/arm/include/asm/traps.h
>> +++ b/arch/arm/include/asm/traps.h
>> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
>> extern void __init early_trap_init(void *);
>> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
>> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
>> +extern int arm_syscall(int no, struct pt_regs *regs);
>>
>> extern void *vectors_page;
>>
>> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
>> index e52fe5a..28d3931 100644
>> --- a/arch/arm/kernel/entry-common.S
>> +++ b/arch/arm/kernel/entry-common.S
>> @@ -426,7 +426,6 @@ ENTRY(vector_swi)
>> local_restart:
>> ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
>> stmdb sp!, {r4, r5} @ push fifth and sixth args
>> -
>
> You don't need this cosmetic change.
Typo. I will fix it.
>> tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
>> bne __sys_trace
>>
>> @@ -476,10 +475,11 @@ __sys_trace:
>> cmp scno, #-1 @ skip the syscall?
>> bne 2b
>> add sp, sp, #S_OFF @ restore stack
>> - b ret_slow_syscall
>> + b __sys_trace_return_skipped
>
> Can't you just remove the add as well, them fall-through here?
I'm afraid that we can't remove this branch because we don't want to override
a value of r0 in regs which a tracer may have already changed while skipping
a syscall.
>>
>> __sys_trace_return:
>> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
>> +__sys_trace_return_skipped:
>> mov r0, sp
>> bl syscall_trace_exit
>> b ret_slow_syscall
>> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
>> index 0c27ed6..68b42cd 100644
>> --- a/arch/arm/kernel/ptrace.c
>> +++ b/arch/arm/kernel/ptrace.c
>> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>>
>> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>> {
>> - current_thread_info()->syscall = scno;
>> + int orig_scno;
>> +
>> + current_thread_info()->syscall = orig_scno = scno;
>>
>> /* Do the secure computing check first; failures should be fast. */
>> if (secure_computing(scno) == -1)
>> @@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>>
>> scno = current_thread_info()->syscall;
>>
>> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> - trace_sys_enter(regs, scno);
>> + if (scno >= 0 && scno < NR_syscalls) {
>
> Is this supposed to work for OABI? If so, better use __NR_SYSCALL_BASE.
Good point. I'm not quite sure how it works for OABI, but looking into entry-comon.S,
there is some code:
> #if defined(CONFIG_OABI_COMPAT)
> bics r10, r10, #0xff000000
> eorne scno, r10, #__NR_OABI_SYSCALL_BASE
> ldrne tbl, =sys_oabi_call_table
> #elif !defined(CONFIG_AEABI)
> bic scno, scno, #0xff000000 @ mask off SWI op-code
> eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
> #endif
>
> local_restart:
It seems to me that scno, actually r7 in regs, is already offset.
>> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> + trace_sys_enter(regs, scno);
>> +
>> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
>> + regs->ARM_r0, regs->ARM_r1,
>> + regs->ARM_r2, regs->ARM_r3);
>> + }
>>
>> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
>> - regs->ARM_r2, regs->ARM_r3);
>> + /* user-issued syscall of -1 */
>> + if (scno == -1 && orig_scno == -1)
>
> Make this an else if, for clarity?
Sure. I will fix it.
>> + arm_syscall(scno, regs);
>
> Doesn't this always result in bad_syscall being called, which sends a SIGILL
> to the task? Shouldn't we simply return -ENOSYS instead? You could do that
> in the assembly code.
I meant so (that is, resulting in bad_syscall).
As I mentioned earlier, a task calling syscall(-1, or whatever native value) is always
signaled on arm. Meanwhile, whether it is intended or not, this behavior is not simulated
in the current arm64 compat syscalls.
>> return scno;
>> }
>>
>> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
>> {
>> - /*
>> - * Audit the syscall before anything else, as a debugger may
>> - * come in and change the current registers.
>> - */
>> - audit_syscall_exit(regs);
>> + if (current_thread_info()->syscall < NR_syscalls) {
>
> Again, not going to work for OABI.
The same comment above.
Thanks,
-Takahiro AKASHI
> Will
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-09-16 0:17 ` AKASHI Takahiro
0 siblings, 0 replies; 15+ messages in thread
From: AKASHI Takahiro @ 2014-09-16 0:17 UTC (permalink / raw)
To: linux-arm-kernel
Will,
Sorry for not responding quickly.
On 09/11/2014 09:37 AM, Will Deacon wrote:
> Hi Akashi,
>
> On Tue, Sep 09, 2014 at 05:49:59AM +0100, AKASHI Takahiro wrote:
>> BUG_ON() in audit_syscall_entry() will be hit if user issues syscall(-1)
>> while syscall auditing is enabled (that is, by starting auditd).
>
> [...]
>
>> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
>> index f555bb3..de01145 100644
>> --- a/arch/arm/include/asm/traps.h
>> +++ b/arch/arm/include/asm/traps.h
>> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
>> extern void __init early_trap_init(void *);
>> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
>> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
>> +extern int arm_syscall(int no, struct pt_regs *regs);
>>
>> extern void *vectors_page;
>>
>> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
>> index e52fe5a..28d3931 100644
>> --- a/arch/arm/kernel/entry-common.S
>> +++ b/arch/arm/kernel/entry-common.S
>> @@ -426,7 +426,6 @@ ENTRY(vector_swi)
>> local_restart:
>> ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing
>> stmdb sp!, {r4, r5} @ push fifth and sixth args
>> -
>
> You don't need this cosmetic change.
Typo. I will fix it.
>> tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls?
>> bne __sys_trace
>>
>> @@ -476,10 +475,11 @@ __sys_trace:
>> cmp scno, #-1 @ skip the syscall?
>> bne 2b
>> add sp, sp, #S_OFF @ restore stack
>> - b ret_slow_syscall
>> + b __sys_trace_return_skipped
>
> Can't you just remove the add as well, them fall-through here?
I'm afraid that we can't remove this branch because we don't want to override
a value of r0 in regs which a tracer may have already changed while skipping
a syscall.
>>
>> __sys_trace_return:
>> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
>> +__sys_trace_return_skipped:
>> mov r0, sp
>> bl syscall_trace_exit
>> b ret_slow_syscall
>> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
>> index 0c27ed6..68b42cd 100644
>> --- a/arch/arm/kernel/ptrace.c
>> +++ b/arch/arm/kernel/ptrace.c
>> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>>
>> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>> {
>> - current_thread_info()->syscall = scno;
>> + int orig_scno;
>> +
>> + current_thread_info()->syscall = orig_scno = scno;
>>
>> /* Do the secure computing check first; failures should be fast. */
>> if (secure_computing(scno) == -1)
>> @@ -941,31 +943,40 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>>
>> scno = current_thread_info()->syscall;
>>
>> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> - trace_sys_enter(regs, scno);
>> + if (scno >= 0 && scno < NR_syscalls) {
>
> Is this supposed to work for OABI? If so, better use __NR_SYSCALL_BASE.
Good point. I'm not quite sure how it works for OABI, but looking into entry-comon.S,
there is some code:
> #if defined(CONFIG_OABI_COMPAT)
> bics r10, r10, #0xff000000
> eorne scno, r10, #__NR_OABI_SYSCALL_BASE
> ldrne tbl, =sys_oabi_call_table
> #elif !defined(CONFIG_AEABI)
> bic scno, scno, #0xff000000 @ mask off SWI op-code
> eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
> #endif
>
> local_restart:
It seems to me that scno, actually r7 in regs, is already offset.
>> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> + trace_sys_enter(regs, scno);
>> +
>> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
>> + regs->ARM_r0, regs->ARM_r1,
>> + regs->ARM_r2, regs->ARM_r3);
>> + }
>>
>> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
>> - regs->ARM_r2, regs->ARM_r3);
>> + /* user-issued syscall of -1 */
>> + if (scno == -1 && orig_scno == -1)
>
> Make this an else if, for clarity?
Sure. I will fix it.
>> + arm_syscall(scno, regs);
>
> Doesn't this always result in bad_syscall being called, which sends a SIGILL
> to the task? Shouldn't we simply return -ENOSYS instead? You could do that
> in the assembly code.
I meant so (that is, resulting in bad_syscall).
As I mentioned earlier, a task calling syscall(-1, or whatever native value) is always
signaled on arm. Meanwhile, whether it is intended or not, this behavior is not simulated
in the current arm64 compat syscalls.
>> return scno;
>> }
>>
>> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
>> {
>> - /*
>> - * Audit the syscall before anything else, as a debugger may
>> - * come in and change the current registers.
>> - */
>> - audit_syscall_exit(regs);
>> + if (current_thread_info()->syscall < NR_syscalls) {
>
> Again, not going to work for OABI.
The same comment above.
Thanks,
-Takahiro AKASHI
> Will
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
2014-10-01 10:45 ` AKASHI Takahiro
@ 2014-10-01 21:42 ` Richard Guy Briggs
-1 siblings, 0 replies; 15+ messages in thread
From: Richard Guy Briggs @ 2014-10-01 21:42 UTC (permalink / raw)
To: AKASHI Takahiro
Cc: linux, will.deacon, broonie, keescook, viro, eparis, dsaxena,
linux-arm-kernel, linaro-kernel, linux-kernel, linux-audit
On 14/10/01, AKASHI Takahiro wrote:
> BUG_ON() in audit_syscall_entry() is hit under the following conditions:
> 1) syscall auditing is enabled (that is, by running auditd).
> 2) user process issues syscall(-1)
> In fact, syscall(-1) just fails (not raising SIGILL, that is an expected
> behavior if not audited), and the succeeding syscall will hit this BUG_ON.
Ok, this looks related to:
https://lkml.org/lkml/2014/6/16/682
Andy has another plan for upstream:
https://lkml.org/lkml/2014/6/16/730
Which finally got posted here:
https://lkml.org/lkml/2014/9/5/736
v5 0/5 x86: two-phase syscall tracing and seccomp fastpath
This is all x86 stuff, but sounds like it may be a problem across other
architectures as well.
Thanks for testing this!
> ------------[ cut here ]------------
> kernel BUG at (...)/kernel/auditsc.c:1534!
> Internal error: Oops - BUG: 0 [#1] SMP ARM
> Modules linked in:
> CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
> task: ea0c4380 ti: ea48e000 task.ti: ea48e000
> PC is at __audit_syscall_entry+0xe4/0x110
> LR is at 0xea0c4380
> pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
> sp : ea48ff68 ip : 00000001 fp : 0000869c
> r10: 00000200 r9 : ea48e000 r8 : c020f4e4
> r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
> r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
> Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> Control: 10c5387d Table: 8a4ac059 DAC: 00000015
> Process syscall_arm (pid: 61, stack limit = 0xea48e250)
> Stack: (0xea48ff68 to 0xea490000)
> ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
> ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
> ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
> ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
> ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
> [<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
> [<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
> Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
> ---[ end trace 0c4441660aba5692 ]---
>
> Under the current implementation, audit_syscall_entry() is called even
> against syscall(-1), but audit_syscall_exit() is not. Because 'in_syscall'
> flag in a current thread's audit context is kept on, next called
> audit_syscall_entry() will see BUG_ON(in_syscall).
>
> This patch fixes this bug by
> 1) preventing syscall enter/exit tracing, ftrace tracepoint and audit,
> from being executed if an invalid (including -1) or pseudo syscall
> number (starting from __NR_ARM_BASE + 1).
> Please note that tracehook_report_syscall(PTRACE_SYSCALL_EXIT) is
> still executed as it should be paired with
> tracehook_report_syscall(PTRACE_SYSCALL_ENTER).
>
> 2) handling user-issued syscall(-1) with arm_syscall() for compatibility
> if tracing is on.
> Since UL(-1) > __NR_ARM_BASE - __NR_SYSCALL_BASE, arm_syscall() is
> called at local_restart in entry-common.S if tracing is off.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
> arch/arm/include/asm/traps.h | 1 +
> arch/arm/kernel/entry-common.S | 3 ++-
> arch/arm/kernel/ptrace.c | 49 +++++++++++++++++++++++++---------------
> 3 files changed, 34 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..4c62324 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -476,10 +476,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..d458367 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,42 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + } else if (scno == -1 && orig_scno == -1) {
> + /*
> + * For compatibility, we handles user-issued syscall(-1)
> + * here with arm_syscall().
> + */
> + arm_syscall(scno, regs);
> + }
>
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
> + /*
> + * Audit the syscall before anything else, as a debugger may
> + * come in and change the current registers.
> + */
> + audit_syscall_exit(regs);
>
> - /*
> - * Note that we haven't updated the ->syscall field for the
> - * current thread. This isn't a problem because it will have
> - * been set on syscall entry and there hasn't been an opportunity
> - * for a PTRACE_SET_SYSCALL since then.
> - */
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_exit(regs, regs_return_value(regs));
> + /*
> + * Note that we haven't updated the ->syscall field for the
> + * current thread. This isn't a problem because it will have
> + * been set on syscall entry and there hasn't been
> + * an opportunity for a PTRACE_SET_SYSCALL since then.
> + */
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_exit(regs, regs_return_value(regs));
> + }
>
> if (test_thread_flag(TIF_SYSCALL_TRACE))
> tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
> --
> 1.7.9.5
>
- RGB
--
Richard Guy Briggs <rbriggs@redhat.com>
Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-10-01 21:42 ` Richard Guy Briggs
0 siblings, 0 replies; 15+ messages in thread
From: Richard Guy Briggs @ 2014-10-01 21:42 UTC (permalink / raw)
To: linux-arm-kernel
On 14/10/01, AKASHI Takahiro wrote:
> BUG_ON() in audit_syscall_entry() is hit under the following conditions:
> 1) syscall auditing is enabled (that is, by running auditd).
> 2) user process issues syscall(-1)
> In fact, syscall(-1) just fails (not raising SIGILL, that is an expected
> behavior if not audited), and the succeeding syscall will hit this BUG_ON.
Ok, this looks related to:
https://lkml.org/lkml/2014/6/16/682
Andy has another plan for upstream:
https://lkml.org/lkml/2014/6/16/730
Which finally got posted here:
https://lkml.org/lkml/2014/9/5/736
v5 0/5 x86: two-phase syscall tracing and seccomp fastpath
This is all x86 stuff, but sounds like it may be a problem across other
architectures as well.
Thanks for testing this!
> ------------[ cut here ]------------
> kernel BUG at (...)/kernel/auditsc.c:1534!
> Internal error: Oops - BUG: 0 [#1] SMP ARM
> Modules linked in:
> CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
> task: ea0c4380 ti: ea48e000 task.ti: ea48e000
> PC is at __audit_syscall_entry+0xe4/0x110
> LR is at 0xea0c4380
> pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
> sp : ea48ff68 ip : 00000001 fp : 0000869c
> r10: 00000200 r9 : ea48e000 r8 : c020f4e4
> r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
> r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
> Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> Control: 10c5387d Table: 8a4ac059 DAC: 00000015
> Process syscall_arm (pid: 61, stack limit = 0xea48e250)
> Stack: (0xea48ff68 to 0xea490000)
> ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
> ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
> ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
> ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
> ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
> [<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
> [<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
> Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
> ---[ end trace 0c4441660aba5692 ]---
>
> Under the current implementation, audit_syscall_entry() is called even
> against syscall(-1), but audit_syscall_exit() is not. Because 'in_syscall'
> flag in a current thread's audit context is kept on, next called
> audit_syscall_entry() will see BUG_ON(in_syscall).
>
> This patch fixes this bug by
> 1) preventing syscall enter/exit tracing, ftrace tracepoint and audit,
> from being executed if an invalid (including -1) or pseudo syscall
> number (starting from __NR_ARM_BASE + 1).
> Please note that tracehook_report_syscall(PTRACE_SYSCALL_EXIT) is
> still executed as it should be paired with
> tracehook_report_syscall(PTRACE_SYSCALL_ENTER).
>
> 2) handling user-issued syscall(-1) with arm_syscall() for compatibility
> if tracing is on.
> Since UL(-1) > __NR_ARM_BASE - __NR_SYSCALL_BASE, arm_syscall() is
> called at local_restart in entry-common.S if tracing is off.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
> arch/arm/include/asm/traps.h | 1 +
> arch/arm/kernel/entry-common.S | 3 ++-
> arch/arm/kernel/ptrace.c | 49 +++++++++++++++++++++++++---------------
> 3 files changed, 34 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..4c62324 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -476,10 +476,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..d458367 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,42 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + } else if (scno == -1 && orig_scno == -1) {
> + /*
> + * For compatibility, we handles user-issued syscall(-1)
> + * here with arm_syscall().
> + */
> + arm_syscall(scno, regs);
> + }
>
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
> + /*
> + * Audit the syscall before anything else, as a debugger may
> + * come in and change the current registers.
> + */
> + audit_syscall_exit(regs);
>
> - /*
> - * Note that we haven't updated the ->syscall field for the
> - * current thread. This isn't a problem because it will have
> - * been set on syscall entry and there hasn't been an opportunity
> - * for a PTRACE_SET_SYSCALL since then.
> - */
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_exit(regs, regs_return_value(regs));
> + /*
> + * Note that we haven't updated the ->syscall field for the
> + * current thread. This isn't a problem because it will have
> + * been set on syscall entry and there hasn't been
> + * an opportunity for a PTRACE_SET_SYSCALL since then.
> + */
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_exit(regs, regs_return_value(regs));
> + }
>
> if (test_thread_flag(TIF_SYSCALL_TRACE))
> tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
> --
> 1.7.9.5
>
- RGB
--
Richard Guy Briggs <rbriggs@redhat.com>
Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
2014-10-01 10:45 ` AKASHI Takahiro
(?)
@ 2014-10-01 19:02 ` Kees Cook
-1 siblings, 0 replies; 15+ messages in thread
From: Kees Cook @ 2014-10-01 19:02 UTC (permalink / raw)
To: AKASHI Takahiro
Cc: Russell King - ARM Linux, Will Deacon, broonie, Al Viro,
Eric Paris, Richard Guy Briggs, Deepak Saxena, linux-arm-kernel,
linaro-kernel, LKML, linux-audit
On Wed, Oct 1, 2014 at 3:45 AM, AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
> BUG_ON() in audit_syscall_entry() is hit under the following conditions:
> 1) syscall auditing is enabled (that is, by running auditd).
> 2) user process issues syscall(-1)
> In fact, syscall(-1) just fails (not raising SIGILL, that is an expected
> behavior if not audited), and the succeeding syscall will hit this BUG_ON.
Thanks for digging in to this!
>
> ------------[ cut here ]------------
> kernel BUG at (...)/kernel/auditsc.c:1534!
> Internal error: Oops - BUG: 0 [#1] SMP ARM
> Modules linked in:
> CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
> task: ea0c4380 ti: ea48e000 task.ti: ea48e000
> PC is at __audit_syscall_entry+0xe4/0x110
> LR is at 0xea0c4380
> pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
> sp : ea48ff68 ip : 00000001 fp : 0000869c
> r10: 00000200 r9 : ea48e000 r8 : c020f4e4
> r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
> r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
> Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> Control: 10c5387d Table: 8a4ac059 DAC: 00000015
> Process syscall_arm (pid: 61, stack limit = 0xea48e250)
> Stack: (0xea48ff68 to 0xea490000)
> ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
> ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
> ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
> ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
> ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
> [<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
> [<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
> Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
> ---[ end trace 0c4441660aba5692 ]---
>
> Under the current implementation, audit_syscall_entry() is called even
> against syscall(-1), but audit_syscall_exit() is not. Because 'in_syscall'
> flag in a current thread's audit context is kept on, next called
> audit_syscall_entry() will see BUG_ON(in_syscall).
>
> This patch fixes this bug by
> 1) preventing syscall enter/exit tracing, ftrace tracepoint and audit,
> from being executed if an invalid (including -1) or pseudo syscall
> number (starting from __NR_ARM_BASE + 1).
> Please note that tracehook_report_syscall(PTRACE_SYSCALL_EXIT) is
> still executed as it should be paired with
> tracehook_report_syscall(PTRACE_SYSCALL_ENTER).
>
> 2) handling user-issued syscall(-1) with arm_syscall() for compatibility
> if tracing is on.
> Since UL(-1) > __NR_ARM_BASE - __NR_SYSCALL_BASE, arm_syscall() is
> called at local_restart in entry-common.S if tracing is off.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
> arch/arm/include/asm/traps.h | 1 +
> arch/arm/kernel/entry-common.S | 3 ++-
> arch/arm/kernel/ptrace.c | 49 +++++++++++++++++++++++++---------------
> 3 files changed, 34 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..4c62324 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -476,10 +476,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..d458367 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,42 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + } else if (scno == -1 && orig_scno == -1) {
> + /*
> + * For compatibility, we handles user-issued syscall(-1)
> + * here with arm_syscall().
> + */
> + arm_syscall(scno, regs);
Won't this always land in bad_syscall(-1, regs) during arm_syscall?
Should syscall_trace-enter just call bad_syscall directly instead, or
are you using arm_syscall since it's the common entry point for this
kind of logic on "non-standard" syscalls?
Either way, this look good! Thanks!
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> + }
>
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
> + /*
> + * Audit the syscall before anything else, as a debugger may
> + * come in and change the current registers.
> + */
> + audit_syscall_exit(regs);
>
> - /*
> - * Note that we haven't updated the ->syscall field for the
> - * current thread. This isn't a problem because it will have
> - * been set on syscall entry and there hasn't been an opportunity
> - * for a PTRACE_SET_SYSCALL since then.
> - */
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_exit(regs, regs_return_value(regs));
> + /*
> + * Note that we haven't updated the ->syscall field for the
> + * current thread. This isn't a problem because it will have
> + * been set on syscall entry and there hasn't been
> + * an opportunity for a PTRACE_SET_SYSCALL since then.
> + */
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_exit(regs, regs_return_value(regs));
> + }
>
> if (test_thread_flag(TIF_SYSCALL_TRACE))
> tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
> --
> 1.7.9.5
>
--
Kees Cook
Chrome OS Security
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-10-01 19:02 ` Kees Cook
0 siblings, 0 replies; 15+ messages in thread
From: Kees Cook @ 2014-10-01 19:02 UTC (permalink / raw)
To: AKASHI Takahiro
Cc: Russell King - ARM Linux, Will Deacon, broonie, Al Viro,
Eric Paris, Richard Guy Briggs, Deepak Saxena, linux-arm-kernel,
linaro-kernel, LKML, linux-audit
On Wed, Oct 1, 2014 at 3:45 AM, AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
> BUG_ON() in audit_syscall_entry() is hit under the following conditions:
> 1) syscall auditing is enabled (that is, by running auditd).
> 2) user process issues syscall(-1)
> In fact, syscall(-1) just fails (not raising SIGILL, that is an expected
> behavior if not audited), and the succeeding syscall will hit this BUG_ON.
Thanks for digging in to this!
>
> ------------[ cut here ]------------
> kernel BUG at (...)/kernel/auditsc.c:1534!
> Internal error: Oops - BUG: 0 [#1] SMP ARM
> Modules linked in:
> CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
> task: ea0c4380 ti: ea48e000 task.ti: ea48e000
> PC is at __audit_syscall_entry+0xe4/0x110
> LR is at 0xea0c4380
> pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
> sp : ea48ff68 ip : 00000001 fp : 0000869c
> r10: 00000200 r9 : ea48e000 r8 : c020f4e4
> r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
> r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
> Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> Control: 10c5387d Table: 8a4ac059 DAC: 00000015
> Process syscall_arm (pid: 61, stack limit = 0xea48e250)
> Stack: (0xea48ff68 to 0xea490000)
> ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
> ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
> ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
> ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
> ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
> [<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
> [<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
> Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
> ---[ end trace 0c4441660aba5692 ]---
>
> Under the current implementation, audit_syscall_entry() is called even
> against syscall(-1), but audit_syscall_exit() is not. Because 'in_syscall'
> flag in a current thread's audit context is kept on, next called
> audit_syscall_entry() will see BUG_ON(in_syscall).
>
> This patch fixes this bug by
> 1) preventing syscall enter/exit tracing, ftrace tracepoint and audit,
> from being executed if an invalid (including -1) or pseudo syscall
> number (starting from __NR_ARM_BASE + 1).
> Please note that tracehook_report_syscall(PTRACE_SYSCALL_EXIT) is
> still executed as it should be paired with
> tracehook_report_syscall(PTRACE_SYSCALL_ENTER).
>
> 2) handling user-issued syscall(-1) with arm_syscall() for compatibility
> if tracing is on.
> Since UL(-1) > __NR_ARM_BASE - __NR_SYSCALL_BASE, arm_syscall() is
> called at local_restart in entry-common.S if tracing is off.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
> arch/arm/include/asm/traps.h | 1 +
> arch/arm/kernel/entry-common.S | 3 ++-
> arch/arm/kernel/ptrace.c | 49 +++++++++++++++++++++++++---------------
> 3 files changed, 34 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..4c62324 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -476,10 +476,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..d458367 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,42 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + } else if (scno == -1 && orig_scno == -1) {
> + /*
> + * For compatibility, we handles user-issued syscall(-1)
> + * here with arm_syscall().
> + */
> + arm_syscall(scno, regs);
Won't this always land in bad_syscall(-1, regs) during arm_syscall?
Should syscall_trace-enter just call bad_syscall directly instead, or
are you using arm_syscall since it's the common entry point for this
kind of logic on "non-standard" syscalls?
Either way, this look good! Thanks!
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> + }
>
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
> + /*
> + * Audit the syscall before anything else, as a debugger may
> + * come in and change the current registers.
> + */
> + audit_syscall_exit(regs);
>
> - /*
> - * Note that we haven't updated the ->syscall field for the
> - * current thread. This isn't a problem because it will have
> - * been set on syscall entry and there hasn't been an opportunity
> - * for a PTRACE_SET_SYSCALL since then.
> - */
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_exit(regs, regs_return_value(regs));
> + /*
> + * Note that we haven't updated the ->syscall field for the
> + * current thread. This isn't a problem because it will have
> + * been set on syscall entry and there hasn't been
> + * an opportunity for a PTRACE_SET_SYSCALL since then.
> + */
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_exit(regs, regs_return_value(regs));
> + }
>
> if (test_thread_flag(TIF_SYSCALL_TRACE))
> tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
> --
> 1.7.9.5
>
--
Kees Cook
Chrome OS Security
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-10-01 19:02 ` Kees Cook
0 siblings, 0 replies; 15+ messages in thread
From: Kees Cook @ 2014-10-01 19:02 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Oct 1, 2014 at 3:45 AM, AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
> BUG_ON() in audit_syscall_entry() is hit under the following conditions:
> 1) syscall auditing is enabled (that is, by running auditd).
> 2) user process issues syscall(-1)
> In fact, syscall(-1) just fails (not raising SIGILL, that is an expected
> behavior if not audited), and the succeeding syscall will hit this BUG_ON.
Thanks for digging in to this!
>
> ------------[ cut here ]------------
> kernel BUG at (...)/kernel/auditsc.c:1534!
> Internal error: Oops - BUG: 0 [#1] SMP ARM
> Modules linked in:
> CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
> task: ea0c4380 ti: ea48e000 task.ti: ea48e000
> PC is at __audit_syscall_entry+0xe4/0x110
> LR is at 0xea0c4380
> pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
> sp : ea48ff68 ip : 00000001 fp : 0000869c
> r10: 00000200 r9 : ea48e000 r8 : c020f4e4
> r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
> r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
> Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> Control: 10c5387d Table: 8a4ac059 DAC: 00000015
> Process syscall_arm (pid: 61, stack limit = 0xea48e250)
> Stack: (0xea48ff68 to 0xea490000)
> ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
> ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
> ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
> ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
> ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
> [<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
> [<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
> Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
> ---[ end trace 0c4441660aba5692 ]---
>
> Under the current implementation, audit_syscall_entry() is called even
> against syscall(-1), but audit_syscall_exit() is not. Because 'in_syscall'
> flag in a current thread's audit context is kept on, next called
> audit_syscall_entry() will see BUG_ON(in_syscall).
>
> This patch fixes this bug by
> 1) preventing syscall enter/exit tracing, ftrace tracepoint and audit,
> from being executed if an invalid (including -1) or pseudo syscall
> number (starting from __NR_ARM_BASE + 1).
> Please note that tracehook_report_syscall(PTRACE_SYSCALL_EXIT) is
> still executed as it should be paired with
> tracehook_report_syscall(PTRACE_SYSCALL_ENTER).
>
> 2) handling user-issued syscall(-1) with arm_syscall() for compatibility
> if tracing is on.
> Since UL(-1) > __NR_ARM_BASE - __NR_SYSCALL_BASE, arm_syscall() is
> called at local_restart in entry-common.S if tracing is off.
>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
> arch/arm/include/asm/traps.h | 1 +
> arch/arm/kernel/entry-common.S | 3 ++-
> arch/arm/kernel/ptrace.c | 49 +++++++++++++++++++++++++---------------
> 3 files changed, 34 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
> index f555bb3..de01145 100644
> --- a/arch/arm/include/asm/traps.h
> +++ b/arch/arm/include/asm/traps.h
> @@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
> extern void __init early_trap_init(void *);
> extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
> extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
> +extern int arm_syscall(int no, struct pt_regs *regs);
>
> extern void *vectors_page;
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index e52fe5a..4c62324 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -476,10 +476,11 @@ __sys_trace:
> cmp scno, #-1 @ skip the syscall?
> bne 2b
> add sp, sp, #S_OFF @ restore stack
> - b ret_slow_syscall
> + b __sys_trace_return_skipped
>
> __sys_trace_return:
> str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
> +__sys_trace_return_skipped:
> mov r0, sp
> bl syscall_trace_exit
> b ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 0c27ed6..d458367 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>
> asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
> {
> - current_thread_info()->syscall = scno;
> + int orig_scno;
> +
> + current_thread_info()->syscall = orig_scno = scno;
>
> /* Do the secure computing check first; failures should be fast. */
> if (secure_computing(scno) == -1)
> @@ -941,31 +943,42 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>
> scno = current_thread_info()->syscall;
>
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_enter(regs, scno);
> + if (scno >= 0 && scno < NR_syscalls) {
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_enter(regs, scno);
>
> - audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
> - regs->ARM_r2, regs->ARM_r3);
> + audit_syscall_entry(AUDIT_ARCH_ARM, scno,
> + regs->ARM_r0, regs->ARM_r1,
> + regs->ARM_r2, regs->ARM_r3);
> + } else if (scno == -1 && orig_scno == -1) {
> + /*
> + * For compatibility, we handles user-issued syscall(-1)
> + * here with arm_syscall().
> + */
> + arm_syscall(scno, regs);
Won't this always land in bad_syscall(-1, regs) during arm_syscall?
Should syscall_trace-enter just call bad_syscall directly instead, or
are you using arm_syscall since it's the common entry point for this
kind of logic on "non-standard" syscalls?
Either way, this look good! Thanks!
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> + }
>
> return scno;
> }
>
> asmlinkage void syscall_trace_exit(struct pt_regs *regs)
> {
> - /*
> - * Audit the syscall before anything else, as a debugger may
> - * come in and change the current registers.
> - */
> - audit_syscall_exit(regs);
> + if (current_thread_info()->syscall < NR_syscalls) {
> + /*
> + * Audit the syscall before anything else, as a debugger may
> + * come in and change the current registers.
> + */
> + audit_syscall_exit(regs);
>
> - /*
> - * Note that we haven't updated the ->syscall field for the
> - * current thread. This isn't a problem because it will have
> - * been set on syscall entry and there hasn't been an opportunity
> - * for a PTRACE_SET_SYSCALL since then.
> - */
> - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> - trace_sys_exit(regs, regs_return_value(regs));
> + /*
> + * Note that we haven't updated the ->syscall field for the
> + * current thread. This isn't a problem because it will have
> + * been set on syscall entry and there hasn't been
> + * an opportunity for a PTRACE_SET_SYSCALL since then.
> + */
> + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
> + trace_sys_exit(regs, regs_return_value(regs));
> + }
>
> if (test_thread_flag(TIF_SYSCALL_TRACE))
> tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
> --
> 1.7.9.5
>
--
Kees Cook
Chrome OS Security
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-10-01 10:45 ` AKASHI Takahiro
0 siblings, 0 replies; 15+ messages in thread
From: AKASHI Takahiro @ 2014-10-01 10:45 UTC (permalink / raw)
To: linux, will.deacon
Cc: broonie, keescook, viro, eparis, rgb, dsaxena, linux-arm-kernel,
linaro-kernel, linux-kernel, linux-audit, AKASHI Takahiro
BUG_ON() in audit_syscall_entry() is hit under the following conditions:
1) syscall auditing is enabled (that is, by running auditd).
2) user process issues syscall(-1)
In fact, syscall(-1) just fails (not raising SIGILL, that is an expected
behavior if not audited), and the succeeding syscall will hit this BUG_ON.
------------[ cut here ]------------
kernel BUG at (...)/kernel/auditsc.c:1534!
Internal error: Oops - BUG: 0 [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
task: ea0c4380 ti: ea48e000 task.ti: ea48e000
PC is at __audit_syscall_entry+0xe4/0x110
LR is at 0xea0c4380
pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
sp : ea48ff68 ip : 00000001 fp : 0000869c
r10: 00000200 r9 : ea48e000 r8 : c020f4e4
r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: 8a4ac059 DAC: 00000015
Process syscall_arm (pid: 61, stack limit = 0xea48e250)
Stack: (0xea48ff68 to 0xea490000)
ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
[<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
[<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
---[ end trace 0c4441660aba5692 ]---
Under the current implementation, audit_syscall_entry() is called even
against syscall(-1), but audit_syscall_exit() is not. Because 'in_syscall'
flag in a current thread's audit context is kept on, next called
audit_syscall_entry() will see BUG_ON(in_syscall).
This patch fixes this bug by
1) preventing syscall enter/exit tracing, ftrace tracepoint and audit,
from being executed if an invalid (including -1) or pseudo syscall
number (starting from __NR_ARM_BASE + 1).
Please note that tracehook_report_syscall(PTRACE_SYSCALL_EXIT) is
still executed as it should be paired with
tracehook_report_syscall(PTRACE_SYSCALL_ENTER).
2) handling user-issued syscall(-1) with arm_syscall() for compatibility
if tracing is on.
Since UL(-1) > __NR_ARM_BASE - __NR_SYSCALL_BASE, arm_syscall() is
called at local_restart in entry-common.S if tracing is off.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
arch/arm/include/asm/traps.h | 1 +
arch/arm/kernel/entry-common.S | 3 ++-
arch/arm/kernel/ptrace.c | 49 +++++++++++++++++++++++++---------------
3 files changed, 34 insertions(+), 19 deletions(-)
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index f555bb3..de01145 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
extern void __init early_trap_init(void *);
extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
+extern int arm_syscall(int no, struct pt_regs *regs);
extern void *vectors_page;
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e52fe5a..4c62324 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -476,10 +476,11 @@ __sys_trace:
cmp scno, #-1 @ skip the syscall?
bne 2b
add sp, sp, #S_OFF @ restore stack
- b ret_slow_syscall
+ b __sys_trace_return_skipped
__sys_trace_return:
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
+__sys_trace_return_skipped:
mov r0, sp
bl syscall_trace_exit
b ret_slow_syscall
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 0c27ed6..d458367 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
{
- current_thread_info()->syscall = scno;
+ int orig_scno;
+
+ current_thread_info()->syscall = orig_scno = scno;
/* Do the secure computing check first; failures should be fast. */
if (secure_computing(scno) == -1)
@@ -941,31 +943,42 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
scno = current_thread_info()->syscall;
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_enter(regs, scno);
+ if (scno >= 0 && scno < NR_syscalls) {
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_enter(regs, scno);
- audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
- regs->ARM_r2, regs->ARM_r3);
+ audit_syscall_entry(AUDIT_ARCH_ARM, scno,
+ regs->ARM_r0, regs->ARM_r1,
+ regs->ARM_r2, regs->ARM_r3);
+ } else if (scno == -1 && orig_scno == -1) {
+ /*
+ * For compatibility, we handles user-issued syscall(-1)
+ * here with arm_syscall().
+ */
+ arm_syscall(scno, regs);
+ }
return scno;
}
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
- /*
- * Audit the syscall before anything else, as a debugger may
- * come in and change the current registers.
- */
- audit_syscall_exit(regs);
+ if (current_thread_info()->syscall < NR_syscalls) {
+ /*
+ * Audit the syscall before anything else, as a debugger may
+ * come in and change the current registers.
+ */
+ audit_syscall_exit(regs);
- /*
- * Note that we haven't updated the ->syscall field for the
- * current thread. This isn't a problem because it will have
- * been set on syscall entry and there hasn't been an opportunity
- * for a PTRACE_SET_SYSCALL since then.
- */
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_exit(regs, regs_return_value(regs));
+ /*
+ * Note that we haven't updated the ->syscall field for the
+ * current thread. This isn't a problem because it will have
+ * been set on syscall entry and there hasn't been
+ * an opportunity for a PTRACE_SET_SYSCALL since then.
+ */
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_exit(regs, regs_return_value(regs));
+ }
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry()
@ 2014-10-01 10:45 ` AKASHI Takahiro
0 siblings, 0 replies; 15+ messages in thread
From: AKASHI Takahiro @ 2014-10-01 10:45 UTC (permalink / raw)
To: linux-arm-kernel
BUG_ON() in audit_syscall_entry() is hit under the following conditions:
1) syscall auditing is enabled (that is, by running auditd).
2) user process issues syscall(-1)
In fact, syscall(-1) just fails (not raising SIGILL, that is an expected
behavior if not audited), and the succeeding syscall will hit this BUG_ON.
------------[ cut here ]------------
kernel BUG at (...)/kernel/auditsc.c:1534!
Internal error: Oops - BUG: 0 [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 61 Comm: syscall_arm Not tainted 3.17.0-rc4 #60
task: ea0c4380 ti: ea48e000 task.ti: ea48e000
PC is at __audit_syscall_entry+0xe4/0x110
LR is at 0xea0c4380
pc : [<c02b2ae8>] lr : [<ea0c4380>] psr: 20000013
sp : ea48ff68 ip : 00000001 fp : 0000869c
r10: 00000200 r9 : ea48e000 r8 : c020f4e4
r7 : 000000c5 r6 : ea48e000 r5 : ea48ffb0 r4 : ea490800
r3 : bef1e718 r2 : 00000001 r1 : 000000c5 r0 : 40000028
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: 8a4ac059 DAC: 00000015
Process syscall_arm (pid: 61, stack limit = 0xea48e250)
Stack: (0xea48ff68 to 0xea490000)
ff60: 540e7a69 3ab5e840 00000200 000000c5 ea48ffb0 ea48e000
ff80: 000000c5 c02114bc bef1e718 00000001 b6efdb58 ffffffff 08400000 000000c5
ffa0: c020f4e4 c020f49c b6efdb58 ffffffff 00000001 bef1e718 bef1e718 00000001
ffc0: b6efdb58 ffffffff 08400000 000000c5 00000000 b6f22850 00000008 0000869c
ffe0: 000000c5 bef1e704 b6ea315f b6e318e6 20000030 00000001 00000000 00000000
[<c02b2ae8>] (__audit_syscall_entry) from [<c02114bc>] (syscall_trace_enter+0xf0/0x120)
[<c02114bc>] (syscall_trace_enter) from [<c020f49c>] (__sys_trace+0xc/0x38)
Code: e584500c e5842004 e28dd00c e8bd80f0 (e7f001f2)
---[ end trace 0c4441660aba5692 ]---
Under the current implementation, audit_syscall_entry() is called even
against syscall(-1), but audit_syscall_exit() is not. Because 'in_syscall'
flag in a current thread's audit context is kept on, next called
audit_syscall_entry() will see BUG_ON(in_syscall).
This patch fixes this bug by
1) preventing syscall enter/exit tracing, ftrace tracepoint and audit,
from being executed if an invalid (including -1) or pseudo syscall
number (starting from __NR_ARM_BASE + 1).
Please note that tracehook_report_syscall(PTRACE_SYSCALL_EXIT) is
still executed as it should be paired with
tracehook_report_syscall(PTRACE_SYSCALL_ENTER).
2) handling user-issued syscall(-1) with arm_syscall() for compatibility
if tracing is on.
Since UL(-1) > __NR_ARM_BASE - __NR_SYSCALL_BASE, arm_syscall() is
called at local_restart in entry-common.S if tracing is off.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
arch/arm/include/asm/traps.h | 1 +
arch/arm/kernel/entry-common.S | 3 ++-
arch/arm/kernel/ptrace.c | 49 +++++++++++++++++++++++++---------------
3 files changed, 34 insertions(+), 19 deletions(-)
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index f555bb3..de01145 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -49,6 +49,7 @@ static inline int in_exception_text(unsigned long ptr)
extern void __init early_trap_init(void *);
extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
+extern int arm_syscall(int no, struct pt_regs *regs);
extern void *vectors_page;
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e52fe5a..4c62324 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -476,10 +476,11 @@ __sys_trace:
cmp scno, #-1 @ skip the syscall?
bne 2b
add sp, sp, #S_OFF @ restore stack
- b ret_slow_syscall
+ b __sys_trace_return_skipped
__sys_trace_return:
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
+__sys_trace_return_skipped:
mov r0, sp
bl syscall_trace_exit
b ret_slow_syscall
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 0c27ed6..d458367 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -930,7 +930,9 @@ static void tracehook_report_syscall(struct pt_regs *regs,
asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
{
- current_thread_info()->syscall = scno;
+ int orig_scno;
+
+ current_thread_info()->syscall = orig_scno = scno;
/* Do the secure computing check first; failures should be fast. */
if (secure_computing(scno) == -1)
@@ -941,31 +943,42 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
scno = current_thread_info()->syscall;
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_enter(regs, scno);
+ if (scno >= 0 && scno < NR_syscalls) {
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_enter(regs, scno);
- audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,
- regs->ARM_r2, regs->ARM_r3);
+ audit_syscall_entry(AUDIT_ARCH_ARM, scno,
+ regs->ARM_r0, regs->ARM_r1,
+ regs->ARM_r2, regs->ARM_r3);
+ } else if (scno == -1 && orig_scno == -1) {
+ /*
+ * For compatibility, we handles user-issued syscall(-1)
+ * here with arm_syscall().
+ */
+ arm_syscall(scno, regs);
+ }
return scno;
}
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
- /*
- * Audit the syscall before anything else, as a debugger may
- * come in and change the current registers.
- */
- audit_syscall_exit(regs);
+ if (current_thread_info()->syscall < NR_syscalls) {
+ /*
+ * Audit the syscall before anything else, as a debugger may
+ * come in and change the current registers.
+ */
+ audit_syscall_exit(regs);
- /*
- * Note that we haven't updated the ->syscall field for the
- * current thread. This isn't a problem because it will have
- * been set on syscall entry and there hasn't been an opportunity
- * for a PTRACE_SET_SYSCALL since then.
- */
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_exit(regs, regs_return_value(regs));
+ /*
+ * Note that we haven't updated the ->syscall field for the
+ * current thread. This isn't a problem because it will have
+ * been set on syscall entry and there hasn't been
+ * an opportunity for a PTRACE_SET_SYSCALL since then.
+ */
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_exit(regs, regs_return_value(regs));
+ }
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 15+ messages in thread
end of thread, other threads:[~2014-10-01 21:43 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-09 4:49 [PATCH v2] arm: prevent BUG_ON in audit_syscall_entry() AKASHI Takahiro
2014-09-09 4:49 ` AKASHI Takahiro
2014-09-11 16:37 ` Will Deacon
2014-09-11 16:37 ` Will Deacon
2014-09-11 16:37 ` Will Deacon
2014-09-16 0:17 ` AKASHI Takahiro
2014-09-16 0:17 ` AKASHI Takahiro
2014-09-16 0:17 ` AKASHI Takahiro
2014-10-01 10:45 AKASHI Takahiro
2014-10-01 10:45 ` AKASHI Takahiro
2014-10-01 19:02 ` Kees Cook
2014-10-01 19:02 ` Kees Cook
2014-10-01 19:02 ` Kees Cook
2014-10-01 21:42 ` Richard Guy Briggs
2014-10-01 21:42 ` Richard Guy Briggs
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.