aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2012-01-03 14:23:06 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2012-01-17 16:16:56 -0500
commitd7e7528bcd456f5c36ad4a202ccfb43c5aa98bc4 (patch)
treeef49503b1dc52c52102e728dbd979c9309d5756b
parent85e7bac33b8d5edafc4e219c7dfdb3d48e0b4e31 (diff)
Audit: push audit success and retcode into arch ptrace.h
The audit system previously expected arches calling to audit_syscall_exit to supply as arguments if the syscall was a success and what the return code was. Audit also provides a helper AUDITSC_RESULT which was supposed to simplify things by converting from negative retcodes to an audit internal magic value stating success or failure. This helper was wrong and could indicate that a valid pointer returned to userspace was a failed syscall. The fix is to fix the layering foolishness. We now pass audit_syscall_exit a struct pt_reg and it in turns calls back into arch code to collect the return value and to determine if the syscall was a success or failure. We also define a generic is_syscall_success() macro which determines success/failure based on if the value is < -MAX_ERRNO. This works for arches like x86 which do not use a separate mechanism to indicate syscall failure. We make both the is_syscall_success() and regs_return_value() static inlines instead of macros. The reason is because the audit function must take a void* for the regs. (uml calls theirs struct uml_pt_regs instead of just struct pt_regs so audit_syscall_exit can't take a struct pt_regs). Since the audit function takes a void* we need to use static inlines to cast it back to the arch correct structure to dereference it. The other major change is that on some arches, like ia64, MIPS and ppc, we change regs_return_value() to give us the negative value on syscall failure. THE only other user of this macro, kretprobe_example.c, won't notice and it makes the value signed consistently for the audit functions across all archs. In arch/sh/kernel/ptrace_64.c I see that we were using regs[9] in the old audit code as the return value. But the ptrace_64.h code defined the macro regs_return_value() as regs[3]. I have no idea which one is correct, but this patch now uses the regs_return_value() function, so it now uses regs[3]. For powerpc we previously used regs->result but now use the regs_return_value() function which uses regs->gprs[3]. regs->gprs[3] is always positive so the regs_return_value(), much like ia64 makes it negative before calling the audit code when appropriate. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: H. Peter Anvin <hpa@zytor.com> [for x86 portion] Acked-by: Tony Luck <tony.luck@intel.com> [for ia64] Acked-by: Richard Weinberger <richard@nod.at> [for uml] Acked-by: David S. Miller <davem@davemloft.net> [for sparc] Acked-by: Ralf Baechle <ralf@linux-mips.org> [for mips] Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> [for ppc]
-rw-r--r--arch/ia64/include/asm/ptrace.h13
-rw-r--r--arch/ia64/kernel/ptrace.c9
-rw-r--r--arch/microblaze/include/asm/ptrace.h5
-rw-r--r--arch/microblaze/kernel/ptrace.c3
-rw-r--r--arch/mips/include/asm/ptrace.h14
-rw-r--r--arch/mips/kernel/ptrace.c4
-rw-r--r--arch/powerpc/include/asm/ptrace.h13
-rw-r--r--arch/powerpc/kernel/ptrace.c4
-rw-r--r--arch/s390/include/asm/ptrace.h6
-rw-r--r--arch/s390/kernel/ptrace.c4
-rw-r--r--arch/sh/include/asm/ptrace_32.h5
-rw-r--r--arch/sh/include/asm/ptrace_64.h5
-rw-r--r--arch/sh/kernel/ptrace_32.c4
-rw-r--r--arch/sh/kernel/ptrace_64.c4
-rw-r--r--arch/sparc/include/asm/ptrace.h10
-rw-r--r--arch/sparc/kernel/ptrace_64.c11
-rw-r--r--arch/um/kernel/ptrace.c4
-rw-r--r--arch/x86/ia32/ia32entry.S10
-rw-r--r--arch/x86/kernel/entry_32.S8
-rw-r--r--arch/x86/kernel/entry_64.S10
-rw-r--r--arch/x86/kernel/ptrace.c3
-rw-r--r--arch/x86/kernel/vm86_32.c4
-rw-r--r--arch/x86/um/shared/sysdep/ptrace.h5
-rw-r--r--include/linux/audit.h22
-rw-r--r--include/linux/ptrace.h10
-rw-r--r--kernel/auditsc.c16
26 files changed, 132 insertions, 74 deletions
diff --git a/arch/ia64/include/asm/ptrace.h b/arch/ia64/include/asm/ptrace.h
index f5cb27614e3..68c98f5b3ca 100644
--- a/arch/ia64/include/asm/ptrace.h
+++ b/arch/ia64/include/asm/ptrace.h
@@ -246,7 +246,18 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
246 return regs->ar_bspstore; 246 return regs->ar_bspstore;
247} 247}
248 248
249#define regs_return_value(regs) ((regs)->r8) 249static inline int is_syscall_success(struct pt_regs *regs)
250{
251 return regs->r10 != -1;
252}
253
254static inline long regs_return_value(struct pt_regs *regs)
255{
256 if (is_syscall_success(regs))
257 return regs->r8;
258 else
259 return -regs->r8;
260}
250 261
251/* Conserve space in histogram by encoding slot bits in address 262/* Conserve space in histogram by encoding slot bits in address
252 * bits 2 and 3 rather than bits 0 and 1. 263 * bits 2 and 3 rather than bits 0 and 1.
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 8848f43d819..2c154088cce 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -1268,14 +1268,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
1268{ 1268{
1269 int step; 1269 int step;
1270 1270
1271 if (unlikely(current->audit_context)) { 1271 audit_syscall_exit(&regs);
1272 int success = AUDITSC_RESULT(regs.r10);
1273 long result = regs.r8;
1274
1275 if (success != AUDITSC_SUCCESS)
1276 result = -result;
1277 audit_syscall_exit(success, result);
1278 }
1279 1272
1280 step = test_thread_flag(TIF_SINGLESTEP); 1273 step = test_thread_flag(TIF_SINGLESTEP);
1281 if (step || test_thread_flag(TIF_SYSCALL_TRACE)) 1274 if (step || test_thread_flag(TIF_SYSCALL_TRACE))
diff --git a/arch/microblaze/include/asm/ptrace.h b/arch/microblaze/include/asm/ptrace.h
index 816bee64b19..94e92c80585 100644
--- a/arch/microblaze/include/asm/ptrace.h
+++ b/arch/microblaze/include/asm/ptrace.h
@@ -61,6 +61,11 @@ struct pt_regs {
61#define instruction_pointer(regs) ((regs)->pc) 61#define instruction_pointer(regs) ((regs)->pc)
62#define profile_pc(regs) instruction_pointer(regs) 62#define profile_pc(regs) instruction_pointer(regs)
63 63
64static inline long regs_return_value(struct pt_regs *regs)
65{
66 return regs->r3;
67}
68
64#else /* __KERNEL__ */ 69#else /* __KERNEL__ */
65 70
66/* pt_regs offsets used by gdbserver etc in ptrace syscalls */ 71/* pt_regs offsets used by gdbserver etc in ptrace syscalls */
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index 043cb58f9c4..f564b1bfd38 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -159,8 +159,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
159{ 159{
160 int step; 160 int step;
161 161
162 if (unlikely(current->audit_context)) 162 audit_syscall_exit(regs);
163 audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3);
164 163
165 step = test_thread_flag(TIF_SINGLESTEP); 164 step = test_thread_flag(TIF_SINGLESTEP);
166 if (step || test_thread_flag(TIF_SYSCALL_TRACE)) 165 if (step || test_thread_flag(TIF_SYSCALL_TRACE))
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index de39b1f343e..7d409505df2 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -137,7 +137,19 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
137 */ 137 */
138#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER) 138#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
139 139
140#define regs_return_value(_regs) ((_regs)->regs[2]) 140static inline int is_syscall_success(struct pt_regs *regs)
141{
142 return !regs->regs[7];
143}
144
145static inline long regs_return_value(struct pt_regs *regs)
146{
147 if (is_syscall_success(regs))
148 return regs->regs[2];
149 else
150 return -regs->regs[2];
151}
152
141#define instruction_pointer(regs) ((regs)->cp0_epc) 153#define instruction_pointer(regs) ((regs)->cp0_epc)
142#define profile_pc(regs) instruction_pointer(regs) 154#define profile_pc(regs) instruction_pointer(regs)
143 155
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 4e6ea1ffad4..ab0f1963a7b 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -572,9 +572,7 @@ out:
572 */ 572 */
573asmlinkage void syscall_trace_leave(struct pt_regs *regs) 573asmlinkage void syscall_trace_leave(struct pt_regs *regs)
574{ 574{
575 if (unlikely(current->audit_context)) 575 audit_syscall_exit(regs);
576 audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]),
577 -regs->regs[2]);
578 576
579 if (!(current->ptrace & PT_PTRACED)) 577 if (!(current->ptrace & PT_PTRACED))
580 return; 578 return;
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 48223f9b872..78a205162fd 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -86,7 +86,18 @@ struct pt_regs {
86#define instruction_pointer(regs) ((regs)->nip) 86#define instruction_pointer(regs) ((regs)->nip)
87#define user_stack_pointer(regs) ((regs)->gpr[1]) 87#define user_stack_pointer(regs) ((regs)->gpr[1])
88#define kernel_stack_pointer(regs) ((regs)->gpr[1]) 88#define kernel_stack_pointer(regs) ((regs)->gpr[1])
89#define regs_return_value(regs) ((regs)->gpr[3]) 89static inline int is_syscall_success(struct pt_regs *regs)
90{
91 return !(regs->ccr & 0x10000000);
92}
93
94static inline long regs_return_value(struct pt_regs *regs)
95{
96 if (is_syscall_success(regs))
97 return regs->gpr[3];
98 else
99 return -regs->gpr[3];
100}
90 101
91#ifdef CONFIG_SMP 102#ifdef CONFIG_SMP
92extern unsigned long profile_pc(struct pt_regs *regs); 103extern unsigned long profile_pc(struct pt_regs *regs);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 5de73dbd15c..09d31c12a5e 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1748,9 +1748,7 @@ void do_syscall_trace_leave(struct pt_regs *regs)
1748{ 1748{
1749 int step; 1749 int step;
1750 1750
1751 if (unlikely(current->audit_context)) 1751 audit_syscall_exit(regs);
1752 audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
1753 regs->result);
1754 1752
1755 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) 1753 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1756 trace_sys_exit(regs, regs->result); 1754 trace_sys_exit(regs, regs->result);
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 56da355678f..aeb77f01798 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -541,9 +541,13 @@ struct user_regs_struct
541#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) 541#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
542#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) 542#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
543#define user_stack_pointer(regs)((regs)->gprs[15]) 543#define user_stack_pointer(regs)((regs)->gprs[15])
544#define regs_return_value(regs)((regs)->gprs[2])
545#define profile_pc(regs) instruction_pointer(regs) 544#define profile_pc(regs) instruction_pointer(regs)
546 545
546static inline long regs_return_value(struct pt_regs *regs)
547{
548 return regs->gprs[2];
549}
550
547int regs_query_register_offset(const char *name); 551int regs_query_register_offset(const char *name);
548const char *regs_query_register_name(unsigned int offset); 552const char *regs_query_register_name(unsigned int offset);
549unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset); 553unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset);
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 573bc29551e..f5275860098 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -751,9 +751,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
751 751
752asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) 752asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
753{ 753{
754 if (unlikely(current->audit_context)) 754 audit_syscall_exit(regs);
755 audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
756 regs->gprs[2]);
757 755
758 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) 756 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
759 trace_sys_exit(regs, regs->gprs[2]); 757 trace_sys_exit(regs, regs->gprs[2]);
diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h
index 6c2239cca1a..2d3e906aa72 100644
--- a/arch/sh/include/asm/ptrace_32.h
+++ b/arch/sh/include/asm/ptrace_32.h
@@ -76,7 +76,10 @@ struct pt_dspregs {
76#ifdef __KERNEL__ 76#ifdef __KERNEL__
77 77
78#define MAX_REG_OFFSET offsetof(struct pt_regs, tra) 78#define MAX_REG_OFFSET offsetof(struct pt_regs, tra)
79#define regs_return_value(_regs) ((_regs)->regs[0]) 79static inline long regs_return_value(struct pt_regs *regs)
80{
81 return regs->regs[0];
82}
80 83
81#endif /* __KERNEL__ */ 84#endif /* __KERNEL__ */
82 85
diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h
index bf9be7764d6..eb3fcceaf64 100644
--- a/arch/sh/include/asm/ptrace_64.h
+++ b/arch/sh/include/asm/ptrace_64.h
@@ -13,7 +13,10 @@ struct pt_regs {
13#ifdef __KERNEL__ 13#ifdef __KERNEL__
14 14
15#define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7]) 15#define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7])
16#define regs_return_value(_regs) ((_regs)->regs[3]) 16static inline long regs_return_value(struct pt_regs *regs)
17{
18 return regs->regs[3];
19}
17 20
18#endif /* __KERNEL__ */ 21#endif /* __KERNEL__ */
19 22
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 92b3c276339..c0b5c179d27 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -530,9 +530,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
530{ 530{
531 int step; 531 int step;
532 532
533 if (unlikely(current->audit_context)) 533 audit_syscall_exit(regs);
534 audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
535 regs->regs[0]);
536 534
537 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) 535 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
538 trace_sys_exit(regs, regs->regs[0]); 536 trace_sys_exit(regs, regs->regs[0]);
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index c8f97649f35..ba720d68643 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -548,9 +548,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
548{ 548{
549 int step; 549 int step;
550 550
551 if (unlikely(current->audit_context)) 551 audit_syscall_exit(regs);
552 audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
553 regs->regs[9]);
554 552
555 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) 553 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
556 trace_sys_exit(regs, regs->regs[9]); 554 trace_sys_exit(regs, regs->regs[9]);
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h
index a0e1bcf843a..c00c3b5c280 100644
--- a/arch/sparc/include/asm/ptrace.h
+++ b/arch/sparc/include/asm/ptrace.h
@@ -207,7 +207,15 @@ do { current_thread_info()->syscall_noerror = 1; \
207#define instruction_pointer(regs) ((regs)->tpc) 207#define instruction_pointer(regs) ((regs)->tpc)
208#define instruction_pointer_set(regs, val) ((regs)->tpc = (val)) 208#define instruction_pointer_set(regs, val) ((regs)->tpc = (val))
209#define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) 209#define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
210#define regs_return_value(regs) ((regs)->u_regs[UREG_I0]) 210static inline int is_syscall_success(struct pt_regs *regs)
211{
212 return !(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY));
213}
214
215static inline long regs_return_value(struct pt_regs *regs)
216{
217 return regs->u_regs[UREG_I0];
218}
211#ifdef CONFIG_SMP 219#ifdef CONFIG_SMP
212extern unsigned long profile_pc(struct pt_regs *); 220extern unsigned long profile_pc(struct pt_regs *);
213#else 221#else
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index 96ee50a8066..c73c8c50f11 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -1086,17 +1086,8 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
1086 1086
1087asmlinkage void syscall_trace_leave(struct pt_regs *regs) 1087asmlinkage void syscall_trace_leave(struct pt_regs *regs)
1088{ 1088{
1089#ifdef CONFIG_AUDITSYSCALL 1089 audit_syscall_exit(regs);
1090 if (unlikely(current->audit_context)) {
1091 unsigned long tstate = regs->tstate;
1092 int result = AUDITSC_SUCCESS;
1093 1090
1094 if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
1095 result = AUDITSC_FAILURE;
1096
1097 audit_syscall_exit(result, regs->u_regs[UREG_I0]);
1098 }
1099#endif
1100 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) 1091 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1101 trace_sys_exit(regs, regs->u_regs[UREG_G1]); 1092 trace_sys_exit(regs, regs->u_regs[UREG_G1]);
1102 1093
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index c9da32b0c70..2ccf25c42fe 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -175,8 +175,8 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit)
175 UPT_SYSCALL_ARG2(regs), 175 UPT_SYSCALL_ARG2(regs),
176 UPT_SYSCALL_ARG3(regs), 176 UPT_SYSCALL_ARG3(regs),
177 UPT_SYSCALL_ARG4(regs)); 177 UPT_SYSCALL_ARG4(regs));
178 else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), 178 else
179 UPT_SYSCALL_RET(regs)); 179 audit_syscall_exit(regs);
180 } 180 }
181 181
182 /* Fake a debug trap */ 182 /* Fake a debug trap */
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 3e274564f6b..64ced0b8f8f 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -14,6 +14,7 @@
14#include <asm/segment.h> 14#include <asm/segment.h>
15#include <asm/irqflags.h> 15#include <asm/irqflags.h>
16#include <linux/linkage.h> 16#include <linux/linkage.h>
17#include <linux/err.h>
17 18
18/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ 19/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
19#include <linux/elf-em.h> 20#include <linux/elf-em.h>
@@ -208,12 +209,11 @@ sysexit_from_sys_call:
208 TRACE_IRQS_ON 209 TRACE_IRQS_ON
209 sti 210 sti
210 movl %eax,%esi /* second arg, syscall return value */ 211 movl %eax,%esi /* second arg, syscall return value */
211 cmpl $0,%eax /* is it < 0? */ 212 cmpl $-MAX_ERRNO,%eax /* is it an error ? */
212 setl %al /* 1 if so, 0 if not */ 213 setbe %al /* 1 if so, 0 if not */
213 movzbl %al,%edi /* zero-extend that into %edi */ 214 movzbl %al,%edi /* zero-extend that into %edi */
214 inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ 215 call __audit_syscall_exit
215 call audit_syscall_exit 216 movq RAX-ARGOFFSET(%rsp),%rax /* reload syscall return value */
216 movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall return value */
217 movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi 217 movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
218 cli 218 cli
219 TRACE_IRQS_OFF 219 TRACE_IRQS_OFF
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 22d0e21b4dd..a22facf06f0 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -42,6 +42,7 @@
42 */ 42 */
43 43
44#include <linux/linkage.h> 44#include <linux/linkage.h>
45#include <linux/err.h>
45#include <asm/thread_info.h> 46#include <asm/thread_info.h>
46#include <asm/irqflags.h> 47#include <asm/irqflags.h>
47#include <asm/errno.h> 48#include <asm/errno.h>
@@ -466,11 +467,10 @@ sysexit_audit:
466 TRACE_IRQS_ON 467 TRACE_IRQS_ON
467 ENABLE_INTERRUPTS(CLBR_ANY) 468 ENABLE_INTERRUPTS(CLBR_ANY)
468 movl %eax,%edx /* second arg, syscall return value */ 469 movl %eax,%edx /* second arg, syscall return value */
469 cmpl $0,%eax /* is it < 0? */ 470 cmpl $-MAX_ERRNO,%eax /* is it an error ? */
470 setl %al /* 1 if so, 0 if not */ 471 setbe %al /* 1 if so, 0 if not */
471 movzbl %al,%eax /* zero-extend that */ 472 movzbl %al,%eax /* zero-extend that */
472 inc %eax /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ 473 call __audit_syscall_exit
473 call audit_syscall_exit
474 DISABLE_INTERRUPTS(CLBR_ANY) 474 DISABLE_INTERRUPTS(CLBR_ANY)
475 TRACE_IRQS_OFF 475 TRACE_IRQS_OFF
476 movl TI_flags(%ebp), %ecx 476 movl TI_flags(%ebp), %ecx
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index a20e1cb9dc8..e51393dd93a 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -55,6 +55,7 @@
55#include <asm/paravirt.h> 55#include <asm/paravirt.h>
56#include <asm/ftrace.h> 56#include <asm/ftrace.h>
57#include <asm/percpu.h> 57#include <asm/percpu.h>
58#include <linux/err.h>
58 59
59/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ 60/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
60#include <linux/elf-em.h> 61#include <linux/elf-em.h>
@@ -563,17 +564,16 @@ auditsys:
563 jmp system_call_fastpath 564 jmp system_call_fastpath
564 565
565 /* 566 /*
566 * Return fast path for syscall audit. Call audit_syscall_exit() 567 * Return fast path for syscall audit. Call __audit_syscall_exit()
567 * directly and then jump back to the fast path with TIF_SYSCALL_AUDIT 568 * directly and then jump back to the fast path with TIF_SYSCALL_AUDIT
568 * masked off. 569 * masked off.
569 */ 570 */
570sysret_audit: 571sysret_audit:
571 movq RAX-ARGOFFSET(%rsp),%rsi /* second arg, syscall return value */ 572 movq RAX-ARGOFFSET(%rsp),%rsi /* second arg, syscall return value */
572 cmpq $0,%rsi /* is it < 0? */ 573 cmpq $-MAX_ERRNO,%rsi /* is it < -MAX_ERRNO? */
573 setl %al /* 1 if so, 0 if not */ 574 setbe %al /* 1 if so, 0 if not */
574 movzbl %al,%edi /* zero-extend that into %edi */ 575 movzbl %al,%edi /* zero-extend that into %edi */
575 inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ 576 call __audit_syscall_exit
576 call audit_syscall_exit
577 movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi 577 movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
578 jmp sysret_check 578 jmp sysret_check
579#endif /* CONFIG_AUDITSYSCALL */ 579#endif /* CONFIG_AUDITSYSCALL */
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 89a04c7b5bb..8b021875877 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1414,8 +1414,7 @@ void syscall_trace_leave(struct pt_regs *regs)
1414{ 1414{
1415 bool step; 1415 bool step;
1416 1416
1417 if (unlikely(current->audit_context)) 1417 audit_syscall_exit(regs);
1418 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
1419 1418
1420 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) 1419 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1421 trace_sys_exit(regs, regs->ax); 1420 trace_sys_exit(regs, regs->ax);
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 863f8753ab0..af17e1c966d 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -335,9 +335,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
335 if (info->flags & VM86_SCREEN_BITMAP) 335 if (info->flags & VM86_SCREEN_BITMAP)
336 mark_screen_rdonly(tsk->mm); 336 mark_screen_rdonly(tsk->mm);
337 337
338 /*call audit_syscall_exit since we do not exit via the normal paths */ 338 /*call __audit_syscall_exit since we do not exit via the normal paths */
339 if (unlikely(current->audit_context)) 339 if (unlikely(current->audit_context))
340 audit_syscall_exit(AUDITSC_RESULT(0), 0); 340 __audit_syscall_exit(1, 0);
341 341
342 __asm__ __volatile__( 342 __asm__ __volatile__(
343 "movl %0,%%esp\n\t" 343 "movl %0,%%esp\n\t"
diff --git a/arch/x86/um/shared/sysdep/ptrace.h b/arch/x86/um/shared/sysdep/ptrace.h
index 711b1621747..5ef9344a8b2 100644
--- a/arch/x86/um/shared/sysdep/ptrace.h
+++ b/arch/x86/um/shared/sysdep/ptrace.h
@@ -3,3 +3,8 @@
3#else 3#else
4#include "ptrace_64.h" 4#include "ptrace_64.h"
5#endif 5#endif
6
7static inline long regs_return_value(struct uml_pt_regs *regs)
8{
9 return UPT_SYSCALL_RET(regs);
10}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 6e1c533f9b4..3d65e4b3ba0 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -26,6 +26,7 @@
26 26
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/elf-em.h> 28#include <linux/elf-em.h>
29#include <linux/ptrace.h>
29 30
30/* The netlink messages for the audit system is divided into blocks: 31/* The netlink messages for the audit system is divided into blocks:
31 * 1000 - 1099 are for commanding the audit system 32 * 1000 - 1099 are for commanding the audit system
@@ -408,10 +409,6 @@ struct audit_field {
408 void *lsm_rule; 409 void *lsm_rule;
409}; 410};
410 411
411#define AUDITSC_INVALID 0
412#define AUDITSC_SUCCESS 1
413#define AUDITSC_FAILURE 2
414#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
415extern int __init audit_register_class(int class, unsigned *list); 412extern int __init audit_register_class(int class, unsigned *list);
416extern int audit_classify_syscall(int abi, unsigned syscall); 413extern int audit_classify_syscall(int abi, unsigned syscall);
417extern int audit_classify_arch(int arch); 414extern int audit_classify_arch(int arch);
@@ -424,7 +421,7 @@ extern void audit_free(struct task_struct *task);
424extern void audit_syscall_entry(int arch, 421extern void audit_syscall_entry(int arch,
425 int major, unsigned long a0, unsigned long a1, 422 int major, unsigned long a0, unsigned long a1,
426 unsigned long a2, unsigned long a3); 423 unsigned long a2, unsigned long a3);
427extern void audit_syscall_exit(int failed, long return_code); 424extern void __audit_syscall_exit(int ret_success, long ret_value);
428extern void __audit_getname(const char *name); 425extern void __audit_getname(const char *name);
429extern void audit_putname(const char *name); 426extern void audit_putname(const char *name);
430extern void __audit_inode(const char *name, const struct dentry *dentry); 427extern void __audit_inode(const char *name, const struct dentry *dentry);
@@ -438,6 +435,15 @@ static inline int audit_dummy_context(void)
438 void *p = current->audit_context; 435 void *p = current->audit_context;
439 return !p || *(int *)p; 436 return !p || *(int *)p;
440} 437}
438static inline void audit_syscall_exit(void *pt_regs)
439{
440 if (unlikely(current->audit_context)) {
441 int success = is_syscall_success(pt_regs);
442 int return_code = regs_return_value(pt_regs);
443
444 __audit_syscall_exit(success, return_code);
445 }
446}
441static inline void audit_getname(const char *name) 447static inline void audit_getname(const char *name)
442{ 448{
443 if (unlikely(!audit_dummy_context())) 449 if (unlikely(!audit_dummy_context()))
@@ -551,12 +557,12 @@ static inline void audit_mmap_fd(int fd, int flags)
551 557
552extern int audit_n_rules; 558extern int audit_n_rules;
553extern int audit_signals; 559extern int audit_signals;
554#else 560#else /* CONFIG_AUDITSYSCALL */
555#define audit_finish_fork(t) 561#define audit_finish_fork(t)
556#define audit_alloc(t) ({ 0; }) 562#define audit_alloc(t) ({ 0; })
557#define audit_free(t) do { ; } while (0) 563#define audit_free(t) do { ; } while (0)
558#define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0) 564#define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0)
559#define audit_syscall_exit(f,r) do { ; } while (0) 565#define audit_syscall_exit(r) do { ; } while (0)
560#define audit_dummy_context() 1 566#define audit_dummy_context() 1
561#define audit_getname(n) do { ; } while (0) 567#define audit_getname(n) do { ; } while (0)
562#define audit_putname(n) do { ; } while (0) 568#define audit_putname(n) do { ; } while (0)
@@ -587,7 +593,7 @@ extern int audit_signals;
587#define audit_ptrace(t) ((void)0) 593#define audit_ptrace(t) ((void)0)
588#define audit_n_rules 0 594#define audit_n_rules 0
589#define audit_signals 0 595#define audit_signals 0
590#endif 596#endif /* CONFIG_AUDITSYSCALL */
591 597
592#ifdef CONFIG_AUDIT 598#ifdef CONFIG_AUDIT
593/* These are defined in audit.c */ 599/* These are defined in audit.c */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 800f113bea6..dd4cefa6519 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -112,6 +112,7 @@
112 112
113#include <linux/compiler.h> /* For unlikely. */ 113#include <linux/compiler.h> /* For unlikely. */
114#include <linux/sched.h> /* For struct task_struct. */ 114#include <linux/sched.h> /* For struct task_struct. */
115#include <linux/err.h> /* for IS_ERR_VALUE */
115 116
116 117
117extern long arch_ptrace(struct task_struct *child, long request, 118extern long arch_ptrace(struct task_struct *child, long request,
@@ -265,6 +266,15 @@ static inline void ptrace_release_task(struct task_struct *task)
265#define force_successful_syscall_return() do { } while (0) 266#define force_successful_syscall_return() do { } while (0)
266#endif 267#endif
267 268
269#ifndef is_syscall_success
270/*
271 * On most systems we can tell if a syscall is a success based on if the retval
272 * is an error value. On some systems like ia64 and powerpc they have different
273 * indicators of success/failure and must define their own.
274 */
275#define is_syscall_success(regs) (!IS_ERR_VALUE((unsigned long)(regs_return_value(regs))))
276#endif
277
268/* 278/*
269 * <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__. 279 * <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__.
270 * 280 *
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e9bcb93800d..3d285380818 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -70,6 +70,11 @@
70 70
71#include "audit.h" 71#include "audit.h"
72 72
73/* flags stating the success for a syscall */
74#define AUDITSC_INVALID 0
75#define AUDITSC_SUCCESS 1
76#define AUDITSC_FAILURE 2
77
73/* AUDIT_NAMES is the number of slots we reserve in the audit_context 78/* AUDIT_NAMES is the number of slots we reserve in the audit_context
74 * for saving names from getname(). If we get more names we will allocate 79 * for saving names from getname(). If we get more names we will allocate
75 * a name dynamically and also add those to the list anchored by names_list. */ 80 * a name dynamically and also add those to the list anchored by names_list. */
@@ -1724,8 +1729,7 @@ void audit_finish_fork(struct task_struct *child)
1724 1729
1725/** 1730/**
1726 * audit_syscall_exit - deallocate audit context after a system call 1731 * audit_syscall_exit - deallocate audit context after a system call
1727 * @valid: success/failure flag 1732 * @pt_regs: syscall registers
1728 * @return_code: syscall return value
1729 * 1733 *
1730 * Tear down after system call. If the audit context has been marked as 1734 * Tear down after system call. If the audit context has been marked as
1731 * auditable (either because of the AUDIT_RECORD_CONTEXT state from 1735 * auditable (either because of the AUDIT_RECORD_CONTEXT state from
@@ -1733,13 +1737,17 @@ void audit_finish_fork(struct task_struct *child)
1733 * message), then write out the syscall information. In call cases, 1737 * message), then write out the syscall information. In call cases,
1734 * free the names stored from getname(). 1738 * free the names stored from getname().
1735 */ 1739 */
1736void audit_syscall_exit(int valid, long return_code) 1740void __audit_syscall_exit(int success, long return_code)
1737{ 1741{
1738 struct task_struct *tsk = current; 1742 struct task_struct *tsk = current;
1739 struct audit_context *context; 1743 struct audit_context *context;
1740 1744
1741 context = audit_get_context(tsk, valid, return_code); 1745 if (success)
1746 success = AUDITSC_SUCCESS;
1747 else
1748 success = AUDITSC_FAILURE;
1742 1749
1750 context = audit_get_context(tsk, success, return_code);
1743 if (likely(!context)) 1751 if (likely(!context))
1744 return; 1752 return;
1745 1753