diff options
43 files changed, 810 insertions, 500 deletions
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index feec86768f9c..f82ec22eeb11 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h | |||
@@ -24,7 +24,6 @@ | |||
24 | #define MAX_INSN_SIZE 2 | 24 | #define MAX_INSN_SIZE 2 |
25 | #define MAX_STACK_SIZE 64 /* 32 would probably be OK */ | 25 | #define MAX_STACK_SIZE 64 /* 32 would probably be OK */ |
26 | 26 | ||
27 | #define regs_return_value(regs) ((regs)->ARM_r0) | ||
28 | #define flush_insn_slot(p) do { } while (0) | 27 | #define flush_insn_slot(p) do { } while (0) |
29 | #define kretprobe_blacklist_size 0 | 28 | #define kretprobe_blacklist_size 0 |
30 | 29 | ||
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 96187ff58c24..451808ba1211 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h | |||
@@ -189,6 +189,11 @@ static inline int valid_user_regs(struct pt_regs *regs) | |||
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | static inline long regs_return_value(struct pt_regs *regs) | ||
193 | { | ||
194 | return regs->ARM_r0; | ||
195 | } | ||
196 | |||
192 | #define instruction_pointer(regs) (regs)->ARM_pc | 197 | #define instruction_pointer(regs) (regs)->ARM_pc |
193 | 198 | ||
194 | #ifdef CONFIG_SMP | 199 | #ifdef CONFIG_SMP |
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 0f30c3a78fc1..d4c24d412a8d 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
@@ -129,6 +129,7 @@ extern void vfp_flush_hwstate(struct thread_info *); | |||
129 | /* | 129 | /* |
130 | * thread information flags: | 130 | * thread information flags: |
131 | * TIF_SYSCALL_TRACE - syscall trace active | 131 | * TIF_SYSCALL_TRACE - syscall trace active |
132 | * TIF_SYSCAL_AUDIT - syscall auditing active | ||
132 | * TIF_SIGPENDING - signal pending | 133 | * TIF_SIGPENDING - signal pending |
133 | * TIF_NEED_RESCHED - rescheduling necessary | 134 | * TIF_NEED_RESCHED - rescheduling necessary |
134 | * TIF_NOTIFY_RESUME - callback before returning to user | 135 | * TIF_NOTIFY_RESUME - callback before returning to user |
@@ -139,6 +140,7 @@ extern void vfp_flush_hwstate(struct thread_info *); | |||
139 | #define TIF_NEED_RESCHED 1 | 140 | #define TIF_NEED_RESCHED 1 |
140 | #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ | 141 | #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ |
141 | #define TIF_SYSCALL_TRACE 8 | 142 | #define TIF_SYSCALL_TRACE 8 |
143 | #define TIF_SYSCALL_AUDIT 9 | ||
142 | #define TIF_POLLING_NRFLAG 16 | 144 | #define TIF_POLLING_NRFLAG 16 |
143 | #define TIF_USING_IWMMXT 17 | 145 | #define TIF_USING_IWMMXT 17 |
144 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ | 146 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ |
@@ -149,11 +151,15 @@ extern void vfp_flush_hwstate(struct thread_info *); | |||
149 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 151 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
150 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | 152 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) |
151 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | 153 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
154 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) | ||
152 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | 155 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) |
153 | #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) | 156 | #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) |
154 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | 157 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) |
155 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) | 158 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) |
156 | 159 | ||
160 | /* Checks for any syscall work in entry-common.S */ | ||
161 | #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT) | ||
162 | |||
157 | /* | 163 | /* |
158 | * Change these and you break ASM code in entry-common.S | 164 | * Change these and you break ASM code in entry-common.S |
159 | */ | 165 | */ |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index b2a27b6b0046..520889cf1b5b 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -87,7 +87,7 @@ ENTRY(ret_from_fork) | |||
87 | get_thread_info tsk | 87 | get_thread_info tsk |
88 | ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing | 88 | ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing |
89 | mov why, #1 | 89 | mov why, #1 |
90 | tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? | 90 | tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? |
91 | beq ret_slow_syscall | 91 | beq ret_slow_syscall |
92 | mov r1, sp | 92 | mov r1, sp |
93 | mov r0, #1 @ trace exit [IP = 1] | 93 | mov r0, #1 @ trace exit [IP = 1] |
@@ -443,7 +443,7 @@ ENTRY(vector_swi) | |||
443 | 1: | 443 | 1: |
444 | #endif | 444 | #endif |
445 | 445 | ||
446 | tst r10, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? | 446 | tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls? |
447 | bne __sys_trace | 447 | bne __sys_trace |
448 | 448 | ||
449 | cmp scno, #NR_syscalls @ check upper syscall limit | 449 | cmp scno, #NR_syscalls @ check upper syscall limit |
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 483727ad6892..e1d5e1929fbd 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -906,11 +906,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) | |||
906 | { | 906 | { |
907 | unsigned long ip; | 907 | unsigned long ip; |
908 | 908 | ||
909 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
910 | return scno; | ||
911 | if (!(current->ptrace & PT_PTRACED)) | ||
912 | return scno; | ||
913 | |||
914 | /* | 909 | /* |
915 | * Save IP. IP is used to denote syscall entry/exit: | 910 | * Save IP. IP is used to denote syscall entry/exit: |
916 | * IP = 0 -> entry, = 1 -> exit | 911 | * IP = 0 -> entry, = 1 -> exit |
@@ -918,6 +913,17 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) | |||
918 | ip = regs->ARM_ip; | 913 | ip = regs->ARM_ip; |
919 | regs->ARM_ip = why; | 914 | regs->ARM_ip = why; |
920 | 915 | ||
916 | if (!ip) | ||
917 | audit_syscall_exit(regs); | ||
918 | else | ||
919 | audit_syscall_entry(AUDIT_ARCH_ARMEB, scno, regs->ARM_r0, | ||
920 | regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); | ||
921 | |||
922 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
923 | return scno; | ||
924 | if (!(current->ptrace & PT_PTRACED)) | ||
925 | return scno; | ||
926 | |||
921 | current_thread_info()->syscall = scno; | 927 | current_thread_info()->syscall = scno; |
922 | 928 | ||
923 | /* the 0x80 provides a way for the tracing parent to distinguish | 929 | /* the 0x80 provides a way for the tracing parent to distinguish |
diff --git a/arch/ia64/include/asm/ptrace.h b/arch/ia64/include/asm/ptrace.h index f5cb27614e35..68c98f5b3ca6 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) | 249 | static inline int is_syscall_success(struct pt_regs *regs) |
250 | { | ||
251 | return regs->r10 != -1; | ||
252 | } | ||
253 | |||
254 | static 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 8848f43d819e..dad91661ddf9 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -1246,15 +1246,8 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, | |||
1246 | if (test_thread_flag(TIF_RESTORE_RSE)) | 1246 | if (test_thread_flag(TIF_RESTORE_RSE)) |
1247 | ia64_sync_krbs(); | 1247 | ia64_sync_krbs(); |
1248 | 1248 | ||
1249 | if (unlikely(current->audit_context)) { | ||
1250 | long syscall; | ||
1251 | int arch; | ||
1252 | 1249 | ||
1253 | syscall = regs.r15; | 1250 | audit_syscall_entry(AUDIT_ARCH_IA64, regs.r15, arg0, arg1, arg2, arg3); |
1254 | arch = AUDIT_ARCH_IA64; | ||
1255 | |||
1256 | audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3); | ||
1257 | } | ||
1258 | 1251 | ||
1259 | return 0; | 1252 | return 0; |
1260 | } | 1253 | } |
@@ -1268,14 +1261,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, | |||
1268 | { | 1261 | { |
1269 | int step; | 1262 | int step; |
1270 | 1263 | ||
1271 | if (unlikely(current->audit_context)) { | 1264 | audit_syscall_exit(®s); |
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 | 1265 | ||
1280 | step = test_thread_flag(TIF_SINGLESTEP); | 1266 | step = test_thread_flag(TIF_SINGLESTEP); |
1281 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) | 1267 | 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 816bee64b196..94e92c805859 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 | ||
64 | static 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 043cb58f9c44..6eb2aa927d89 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c | |||
@@ -147,10 +147,8 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
147 | */ | 147 | */ |
148 | ret = -1L; | 148 | ret = -1L; |
149 | 149 | ||
150 | if (unlikely(current->audit_context)) | 150 | audit_syscall_entry(EM_MICROBLAZE, regs->r12, regs->r5, regs->r6, |
151 | audit_syscall_entry(EM_MICROBLAZE, regs->r12, | 151 | regs->r7, regs->r8); |
152 | regs->r5, regs->r6, | ||
153 | regs->r7, regs->r8); | ||
154 | 152 | ||
155 | return ret ?: regs->r12; | 153 | return ret ?: regs->r12; |
156 | } | 154 | } |
@@ -159,8 +157,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) | |||
159 | { | 157 | { |
160 | int step; | 158 | int step; |
161 | 159 | ||
162 | if (unlikely(current->audit_context)) | 160 | audit_syscall_exit(regs); |
163 | audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3); | ||
164 | 161 | ||
165 | step = test_thread_flag(TIF_SINGLESTEP); | 162 | step = test_thread_flag(TIF_SINGLESTEP); |
166 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) | 163 | 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 7b99c670e478..4b7f5252d2fd 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]) | 140 | static inline int is_syscall_success(struct pt_regs *regs) |
141 | { | ||
142 | return !regs->regs[7]; | ||
143 | } | ||
144 | |||
145 | static 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 4e6ea1ffad46..7786b608d932 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c | |||
@@ -560,10 +560,9 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs) | |||
560 | } | 560 | } |
561 | 561 | ||
562 | out: | 562 | out: |
563 | if (unlikely(current->audit_context)) | 563 | audit_syscall_entry(audit_arch(), regs->regs[2], |
564 | audit_syscall_entry(audit_arch(), regs->regs[2], | 564 | regs->regs[4], regs->regs[5], |
565 | regs->regs[4], regs->regs[5], | 565 | regs->regs[6], regs->regs[7]); |
566 | regs->regs[6], regs->regs[7]); | ||
567 | } | 566 | } |
568 | 567 | ||
569 | /* | 568 | /* |
@@ -572,9 +571,7 @@ out: | |||
572 | */ | 571 | */ |
573 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) | 572 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) |
574 | { | 573 | { |
575 | if (unlikely(current->audit_context)) | 574 | audit_syscall_exit(regs); |
576 | audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]), | ||
577 | -regs->regs[2]); | ||
578 | 575 | ||
579 | if (!(current->ptrace & PT_PTRACED)) | 576 | if (!(current->ptrace & PT_PTRACED)) |
580 | return; | 577 | return; |
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 48223f9b8728..78a205162fd7 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]) | 89 | static inline int is_syscall_success(struct pt_regs *regs) |
90 | { | ||
91 | return !(regs->ccr & 0x10000000); | ||
92 | } | ||
93 | |||
94 | static 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 |
92 | extern unsigned long profile_pc(struct pt_regs *regs); | 103 | extern unsigned long profile_pc(struct pt_regs *regs); |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 5de73dbd15c7..5b43325402bc 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -1724,22 +1724,20 @@ long do_syscall_trace_enter(struct pt_regs *regs) | |||
1724 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 1724 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1725 | trace_sys_enter(regs, regs->gpr[0]); | 1725 | trace_sys_enter(regs, regs->gpr[0]); |
1726 | 1726 | ||
1727 | if (unlikely(current->audit_context)) { | ||
1728 | #ifdef CONFIG_PPC64 | 1727 | #ifdef CONFIG_PPC64 |
1729 | if (!is_32bit_task()) | 1728 | if (!is_32bit_task()) |
1730 | audit_syscall_entry(AUDIT_ARCH_PPC64, | 1729 | audit_syscall_entry(AUDIT_ARCH_PPC64, |
1731 | regs->gpr[0], | 1730 | regs->gpr[0], |
1732 | regs->gpr[3], regs->gpr[4], | 1731 | regs->gpr[3], regs->gpr[4], |
1733 | regs->gpr[5], regs->gpr[6]); | 1732 | regs->gpr[5], regs->gpr[6]); |
1734 | else | 1733 | else |
1735 | #endif | 1734 | #endif |
1736 | audit_syscall_entry(AUDIT_ARCH_PPC, | 1735 | audit_syscall_entry(AUDIT_ARCH_PPC, |
1737 | regs->gpr[0], | 1736 | regs->gpr[0], |
1738 | regs->gpr[3] & 0xffffffff, | 1737 | regs->gpr[3] & 0xffffffff, |
1739 | regs->gpr[4] & 0xffffffff, | 1738 | regs->gpr[4] & 0xffffffff, |
1740 | regs->gpr[5] & 0xffffffff, | 1739 | regs->gpr[5] & 0xffffffff, |
1741 | regs->gpr[6] & 0xffffffff); | 1740 | regs->gpr[6] & 0xffffffff); |
1742 | } | ||
1743 | 1741 | ||
1744 | return ret ?: regs->gpr[0]; | 1742 | return ret ?: regs->gpr[0]; |
1745 | } | 1743 | } |
@@ -1748,9 +1746,7 @@ void do_syscall_trace_leave(struct pt_regs *regs) | |||
1748 | { | 1746 | { |
1749 | int step; | 1747 | int step; |
1750 | 1748 | ||
1751 | if (unlikely(current->audit_context)) | 1749 | audit_syscall_exit(regs); |
1752 | audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, | ||
1753 | regs->result); | ||
1754 | 1750 | ||
1755 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 1751 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1756 | trace_sys_exit(regs, regs->result); | 1752 | trace_sys_exit(regs, regs->result); |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 56da355678f4..aeb77f017985 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 | ||
546 | static inline long regs_return_value(struct pt_regs *regs) | ||
547 | { | ||
548 | return regs->gprs[2]; | ||
549 | } | ||
550 | |||
547 | int regs_query_register_offset(const char *name); | 551 | int regs_query_register_offset(const char *name); |
548 | const char *regs_query_register_name(unsigned int offset); | 552 | const char *regs_query_register_name(unsigned int offset); |
549 | unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset); | 553 | unsigned 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 573bc29551ef..9d82ed4bcb27 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -740,20 +740,17 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
740 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 740 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
741 | trace_sys_enter(regs, regs->gprs[2]); | 741 | trace_sys_enter(regs, regs->gprs[2]); |
742 | 742 | ||
743 | if (unlikely(current->audit_context)) | 743 | audit_syscall_entry(is_compat_task() ? |
744 | audit_syscall_entry(is_compat_task() ? | 744 | AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, |
745 | AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, | 745 | regs->gprs[2], regs->orig_gpr2, |
746 | regs->gprs[2], regs->orig_gpr2, | 746 | regs->gprs[3], regs->gprs[4], |
747 | regs->gprs[3], regs->gprs[4], | 747 | regs->gprs[5]); |
748 | regs->gprs[5]); | ||
749 | return ret ?: regs->gprs[2]; | 748 | return ret ?: regs->gprs[2]; |
750 | } | 749 | } |
751 | 750 | ||
752 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) | 751 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) |
753 | { | 752 | { |
754 | if (unlikely(current->audit_context)) | 753 | audit_syscall_exit(regs); |
755 | audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), | ||
756 | regs->gprs[2]); | ||
757 | 754 | ||
758 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 755 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
759 | trace_sys_exit(regs, regs->gprs[2]); | 756 | 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 6c2239cca1a2..2d3e906aa722 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]) | 79 | static 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 bf9be7764d69..eb3fcceaf64b 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]) | 16 | static 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 92b3c276339a..a3e651563763 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
@@ -518,10 +518,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
518 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 518 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
519 | trace_sys_enter(regs, regs->regs[0]); | 519 | trace_sys_enter(regs, regs->regs[0]); |
520 | 520 | ||
521 | if (unlikely(current->audit_context)) | 521 | audit_syscall_entry(audit_arch(), regs->regs[3], |
522 | audit_syscall_entry(audit_arch(), regs->regs[3], | 522 | regs->regs[4], regs->regs[5], |
523 | regs->regs[4], regs->regs[5], | 523 | regs->regs[6], regs->regs[7]); |
524 | regs->regs[6], regs->regs[7]); | ||
525 | 524 | ||
526 | return ret ?: regs->regs[0]; | 525 | return ret ?: regs->regs[0]; |
527 | } | 526 | } |
@@ -530,9 +529,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) | |||
530 | { | 529 | { |
531 | int step; | 530 | int step; |
532 | 531 | ||
533 | if (unlikely(current->audit_context)) | 532 | audit_syscall_exit(regs); |
534 | audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), | ||
535 | regs->regs[0]); | ||
536 | 533 | ||
537 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 534 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
538 | trace_sys_exit(regs, regs->regs[0]); | 535 | trace_sys_exit(regs, regs->regs[0]); |
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index c8f97649f354..3d0080b5c976 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c | |||
@@ -536,10 +536,9 @@ asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs) | |||
536 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 536 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
537 | trace_sys_enter(regs, regs->regs[9]); | 537 | trace_sys_enter(regs, regs->regs[9]); |
538 | 538 | ||
539 | if (unlikely(current->audit_context)) | 539 | audit_syscall_entry(audit_arch(), regs->regs[1], |
540 | audit_syscall_entry(audit_arch(), regs->regs[1], | 540 | regs->regs[2], regs->regs[3], |
541 | regs->regs[2], regs->regs[3], | 541 | regs->regs[4], regs->regs[5]); |
542 | regs->regs[4], regs->regs[5]); | ||
543 | 542 | ||
544 | return ret ?: regs->regs[9]; | 543 | return ret ?: regs->regs[9]; |
545 | } | 544 | } |
@@ -548,9 +547,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) | |||
548 | { | 547 | { |
549 | int step; | 548 | int step; |
550 | 549 | ||
551 | if (unlikely(current->audit_context)) | 550 | audit_syscall_exit(regs); |
552 | audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]), | ||
553 | regs->regs[9]); | ||
554 | 551 | ||
555 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 552 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
556 | trace_sys_exit(regs, regs->regs[9]); | 553 | trace_sys_exit(regs, regs->regs[9]); |
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index a0e1bcf843a1..c00c3b5c2806 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]) | 210 | static inline int is_syscall_success(struct pt_regs *regs) |
211 | { | ||
212 | return !(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)); | ||
213 | } | ||
214 | |||
215 | static 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 |
212 | extern unsigned long profile_pc(struct pt_regs *); | 220 | extern 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 96ee50a80661..9388844cd88c 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c | |||
@@ -1071,32 +1071,22 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) | |||
1071 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 1071 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1072 | trace_sys_enter(regs, regs->u_regs[UREG_G1]); | 1072 | trace_sys_enter(regs, regs->u_regs[UREG_G1]); |
1073 | 1073 | ||
1074 | if (unlikely(current->audit_context) && !ret) | 1074 | audit_syscall_entry((test_thread_flag(TIF_32BIT) ? |
1075 | audit_syscall_entry((test_thread_flag(TIF_32BIT) ? | 1075 | AUDIT_ARCH_SPARC : |
1076 | AUDIT_ARCH_SPARC : | 1076 | AUDIT_ARCH_SPARC64), |
1077 | AUDIT_ARCH_SPARC64), | 1077 | regs->u_regs[UREG_G1], |
1078 | regs->u_regs[UREG_G1], | 1078 | regs->u_regs[UREG_I0], |
1079 | regs->u_regs[UREG_I0], | 1079 | regs->u_regs[UREG_I1], |
1080 | regs->u_regs[UREG_I1], | 1080 | regs->u_regs[UREG_I2], |
1081 | regs->u_regs[UREG_I2], | 1081 | regs->u_regs[UREG_I3]); |
1082 | regs->u_regs[UREG_I3]); | ||
1083 | 1082 | ||
1084 | return ret; | 1083 | return ret; |
1085 | } | 1084 | } |
1086 | 1085 | ||
1087 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) | 1086 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) |
1088 | { | 1087 | { |
1089 | #ifdef CONFIG_AUDITSYSCALL | 1088 | audit_syscall_exit(regs); |
1090 | if (unlikely(current->audit_context)) { | ||
1091 | unsigned long tstate = regs->tstate; | ||
1092 | int result = AUDITSC_SUCCESS; | ||
1093 | 1089 | ||
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))) | 1090 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1101 | trace_sys_exit(regs, regs->u_regs[UREG_G1]); | 1091 | trace_sys_exit(regs, regs->u_regs[UREG_G1]); |
1102 | 1092 | ||
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index c9da32b0c707..06b190390505 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -167,17 +167,15 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit) | |||
167 | int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; | 167 | int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; |
168 | int tracesysgood; | 168 | int tracesysgood; |
169 | 169 | ||
170 | if (unlikely(current->audit_context)) { | 170 | if (!entryexit) |
171 | if (!entryexit) | 171 | audit_syscall_entry(HOST_AUDIT_ARCH, |
172 | audit_syscall_entry(HOST_AUDIT_ARCH, | 172 | UPT_SYSCALL_NR(regs), |
173 | UPT_SYSCALL_NR(regs), | 173 | UPT_SYSCALL_ARG1(regs), |
174 | UPT_SYSCALL_ARG1(regs), | 174 | UPT_SYSCALL_ARG2(regs), |
175 | UPT_SYSCALL_ARG2(regs), | 175 | UPT_SYSCALL_ARG3(regs), |
176 | UPT_SYSCALL_ARG3(regs), | 176 | UPT_SYSCALL_ARG4(regs)); |
177 | UPT_SYSCALL_ARG4(regs)); | 177 | else |
178 | else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), | 178 | audit_syscall_exit(regs); |
179 | UPT_SYSCALL_RET(regs)); | ||
180 | } | ||
181 | 179 | ||
182 | /* Fake a debug trap */ | 180 | /* Fake a debug trap */ |
183 | if (is_singlestep) | 181 | if (is_singlestep) |
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 1106261856c8..e3e734005e19 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> |
@@ -189,7 +190,7 @@ sysexit_from_sys_call: | |||
189 | movl %ebx,%edx /* 3rd arg: 1st syscall arg */ | 190 | movl %ebx,%edx /* 3rd arg: 1st syscall arg */ |
190 | movl %eax,%esi /* 2nd arg: syscall number */ | 191 | movl %eax,%esi /* 2nd arg: syscall number */ |
191 | movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ | 192 | movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ |
192 | call audit_syscall_entry | 193 | call __audit_syscall_entry |
193 | movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ | 194 | movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ |
194 | cmpq $(IA32_NR_syscalls-1),%rax | 195 | cmpq $(IA32_NR_syscalls-1),%rax |
195 | ja ia32_badsys | 196 | ja ia32_badsys |
@@ -206,12 +207,13 @@ sysexit_from_sys_call: | |||
206 | TRACE_IRQS_ON | 207 | TRACE_IRQS_ON |
207 | sti | 208 | sti |
208 | movl %eax,%esi /* second arg, syscall return value */ | 209 | movl %eax,%esi /* second arg, syscall return value */ |
209 | cmpl $0,%eax /* is it < 0? */ | 210 | cmpl $-MAX_ERRNO,%eax /* is it an error ? */ |
210 | setl %al /* 1 if so, 0 if not */ | 211 | jbe 1f |
212 | movslq %eax, %rsi /* if error sign extend to 64 bits */ | ||
213 | 1: setbe %al /* 1 if error, 0 if not */ | ||
211 | movzbl %al,%edi /* zero-extend that into %edi */ | 214 | movzbl %al,%edi /* zero-extend that into %edi */ |
212 | inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ | 215 | call __audit_syscall_exit |
213 | call audit_syscall_exit | 216 | movq RAX-ARGOFFSET(%rsp),%rax /* reload syscall return value */ |
214 | movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall return value */ | ||
215 | movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi | 217 | movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi |
216 | cli | 218 | cli |
217 | TRACE_IRQS_OFF | 219 | TRACE_IRQS_OFF |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 4af9fd2450a5..79d97e68f042 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> |
@@ -453,7 +454,7 @@ sysenter_audit: | |||
453 | movl %ebx,%ecx /* 3rd arg: 1st syscall arg */ | 454 | movl %ebx,%ecx /* 3rd arg: 1st syscall arg */ |
454 | movl %eax,%edx /* 2nd arg: syscall number */ | 455 | movl %eax,%edx /* 2nd arg: syscall number */ |
455 | movl $AUDIT_ARCH_I386,%eax /* 1st arg: audit arch */ | 456 | movl $AUDIT_ARCH_I386,%eax /* 1st arg: audit arch */ |
456 | call audit_syscall_entry | 457 | call __audit_syscall_entry |
457 | pushl_cfi %ebx | 458 | pushl_cfi %ebx |
458 | movl PT_EAX(%esp),%eax /* reload syscall number */ | 459 | movl PT_EAX(%esp),%eax /* reload syscall number */ |
459 | jmp sysenter_do_call | 460 | jmp sysenter_do_call |
@@ -464,11 +465,10 @@ sysexit_audit: | |||
464 | TRACE_IRQS_ON | 465 | TRACE_IRQS_ON |
465 | ENABLE_INTERRUPTS(CLBR_ANY) | 466 | ENABLE_INTERRUPTS(CLBR_ANY) |
466 | movl %eax,%edx /* second arg, syscall return value */ | 467 | movl %eax,%edx /* second arg, syscall return value */ |
467 | cmpl $0,%eax /* is it < 0? */ | 468 | cmpl $-MAX_ERRNO,%eax /* is it an error ? */ |
468 | setl %al /* 1 if so, 0 if not */ | 469 | setbe %al /* 1 if so, 0 if not */ |
469 | movzbl %al,%eax /* zero-extend that */ | 470 | movzbl %al,%eax /* zero-extend that */ |
470 | inc %eax /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ | 471 | call __audit_syscall_exit |
471 | call audit_syscall_exit | ||
472 | DISABLE_INTERRUPTS(CLBR_ANY) | 472 | DISABLE_INTERRUPTS(CLBR_ANY) |
473 | TRACE_IRQS_OFF | 473 | TRACE_IRQS_OFF |
474 | movl TI_flags(%ebp), %ecx | 474 | movl TI_flags(%ebp), %ecx |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 940ba711fc28..3fe8239fd8fb 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> |
@@ -548,7 +549,7 @@ badsys: | |||
548 | #ifdef CONFIG_AUDITSYSCALL | 549 | #ifdef CONFIG_AUDITSYSCALL |
549 | /* | 550 | /* |
550 | * Fast path for syscall audit without full syscall trace. | 551 | * Fast path for syscall audit without full syscall trace. |
551 | * We just call audit_syscall_entry() directly, and then | 552 | * We just call __audit_syscall_entry() directly, and then |
552 | * jump back to the normal fast path. | 553 | * jump back to the normal fast path. |
553 | */ | 554 | */ |
554 | auditsys: | 555 | auditsys: |
@@ -558,22 +559,21 @@ auditsys: | |||
558 | movq %rdi,%rdx /* 3rd arg: 1st syscall arg */ | 559 | movq %rdi,%rdx /* 3rd arg: 1st syscall arg */ |
559 | movq %rax,%rsi /* 2nd arg: syscall number */ | 560 | movq %rax,%rsi /* 2nd arg: syscall number */ |
560 | movl $AUDIT_ARCH_X86_64,%edi /* 1st arg: audit arch */ | 561 | movl $AUDIT_ARCH_X86_64,%edi /* 1st arg: audit arch */ |
561 | call audit_syscall_entry | 562 | call __audit_syscall_entry |
562 | LOAD_ARGS 0 /* reload call-clobbered registers */ | 563 | LOAD_ARGS 0 /* reload call-clobbered registers */ |
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 | */ |
570 | sysret_audit: | 571 | sysret_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 89a04c7b5bb6..50267386b766 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -1392,20 +1392,18 @@ long syscall_trace_enter(struct pt_regs *regs) | |||
1392 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 1392 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1393 | trace_sys_enter(regs, regs->orig_ax); | 1393 | trace_sys_enter(regs, regs->orig_ax); |
1394 | 1394 | ||
1395 | if (unlikely(current->audit_context)) { | 1395 | if (IS_IA32) |
1396 | if (IS_IA32) | 1396 | audit_syscall_entry(AUDIT_ARCH_I386, |
1397 | audit_syscall_entry(AUDIT_ARCH_I386, | 1397 | regs->orig_ax, |
1398 | regs->orig_ax, | 1398 | regs->bx, regs->cx, |
1399 | regs->bx, regs->cx, | 1399 | regs->dx, regs->si); |
1400 | regs->dx, regs->si); | ||
1401 | #ifdef CONFIG_X86_64 | 1400 | #ifdef CONFIG_X86_64 |
1402 | else | 1401 | else |
1403 | audit_syscall_entry(AUDIT_ARCH_X86_64, | 1402 | audit_syscall_entry(AUDIT_ARCH_X86_64, |
1404 | regs->orig_ax, | 1403 | regs->orig_ax, |
1405 | regs->di, regs->si, | 1404 | regs->di, regs->si, |
1406 | regs->dx, regs->r10); | 1405 | regs->dx, regs->r10); |
1407 | #endif | 1406 | #endif |
1408 | } | ||
1409 | 1407 | ||
1410 | return ret ?: regs->orig_ax; | 1408 | return ret ?: regs->orig_ax; |
1411 | } | 1409 | } |
@@ -1414,8 +1412,7 @@ void syscall_trace_leave(struct pt_regs *regs) | |||
1414 | { | 1412 | { |
1415 | bool step; | 1413 | bool step; |
1416 | 1414 | ||
1417 | if (unlikely(current->audit_context)) | 1415 | audit_syscall_exit(regs); |
1418 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); | ||
1419 | 1416 | ||
1420 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 1417 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1421 | trace_sys_exit(regs, regs->ax); | 1418 | trace_sys_exit(regs, regs->ax); |
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 863f8753ab0a..af17e1c966dc 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 711b1621747f..5ef9344a8b24 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 | |||
7 | static inline long regs_return_value(struct uml_pt_regs *regs) | ||
8 | { | ||
9 | return UPT_SYSCALL_RET(regs); | ||
10 | } | ||
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index a0d042aa2967..2dff698ab02e 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c | |||
@@ -334,8 +334,7 @@ void do_syscall_trace_enter(struct pt_regs *regs) | |||
334 | do_syscall_trace(); | 334 | do_syscall_trace(); |
335 | 335 | ||
336 | #if 0 | 336 | #if 0 |
337 | if (unlikely(current->audit_context)) | 337 | audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); |
338 | audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); | ||
339 | #endif | 338 | #endif |
340 | } | 339 | } |
341 | 340 | ||
diff --git a/fs/namei.c b/fs/namei.c index c283a1ec008e..208c6aa4a989 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -140,21 +140,19 @@ static int do_getname(const char __user *filename, char *page) | |||
140 | 140 | ||
141 | static char *getname_flags(const char __user *filename, int flags, int *empty) | 141 | static char *getname_flags(const char __user *filename, int flags, int *empty) |
142 | { | 142 | { |
143 | char *tmp, *result; | 143 | char *result = __getname(); |
144 | 144 | int retval; | |
145 | result = ERR_PTR(-ENOMEM); | 145 | |
146 | tmp = __getname(); | 146 | if (!result) |
147 | if (tmp) { | 147 | return ERR_PTR(-ENOMEM); |
148 | int retval = do_getname(filename, tmp); | 148 | |
149 | 149 | retval = do_getname(filename, result); | |
150 | result = tmp; | 150 | if (retval < 0) { |
151 | if (retval < 0) { | 151 | if (retval == -ENOENT && empty) |
152 | if (retval == -ENOENT && empty) | 152 | *empty = 1; |
153 | *empty = 1; | 153 | if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { |
154 | if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { | 154 | __putname(result); |
155 | __putname(tmp); | 155 | return ERR_PTR(retval); |
156 | result = ERR_PTR(retval); | ||
157 | } | ||
158 | } | 156 | } |
159 | } | 157 | } |
160 | audit_getname(result); | 158 | audit_getname(result); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 662ddf2ec4f1..9cde9edf9c4d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1132,9 +1132,6 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, | |||
1132 | ssize_t length; | 1132 | ssize_t length; |
1133 | uid_t loginuid; | 1133 | uid_t loginuid; |
1134 | 1134 | ||
1135 | if (!capable(CAP_AUDIT_CONTROL)) | ||
1136 | return -EPERM; | ||
1137 | |||
1138 | rcu_read_lock(); | 1135 | rcu_read_lock(); |
1139 | if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { | 1136 | if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { |
1140 | rcu_read_unlock(); | 1137 | rcu_read_unlock(); |
@@ -1163,7 +1160,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, | |||
1163 | goto out_free_page; | 1160 | goto out_free_page; |
1164 | 1161 | ||
1165 | } | 1162 | } |
1166 | length = audit_set_loginuid(current, loginuid); | 1163 | length = audit_set_loginuid(loginuid); |
1167 | if (likely(length == 0)) | 1164 | if (likely(length == 0)) |
1168 | length = count; | 1165 | length = count; |
1169 | 1166 | ||
diff --git a/include/linux/audit.h b/include/linux/audit.h index 426ab9f4dd85..9ff7a2c48b50 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 |
@@ -181,6 +182,40 @@ | |||
181 | * AUDIT_UNUSED_BITS is updated if need be. */ | 182 | * AUDIT_UNUSED_BITS is updated if need be. */ |
182 | #define AUDIT_UNUSED_BITS 0x07FFFC00 | 183 | #define AUDIT_UNUSED_BITS 0x07FFFC00 |
183 | 184 | ||
185 | /* AUDIT_FIELD_COMPARE rule list */ | ||
186 | #define AUDIT_COMPARE_UID_TO_OBJ_UID 1 | ||
187 | #define AUDIT_COMPARE_GID_TO_OBJ_GID 2 | ||
188 | #define AUDIT_COMPARE_EUID_TO_OBJ_UID 3 | ||
189 | #define AUDIT_COMPARE_EGID_TO_OBJ_GID 4 | ||
190 | #define AUDIT_COMPARE_AUID_TO_OBJ_UID 5 | ||
191 | #define AUDIT_COMPARE_SUID_TO_OBJ_UID 6 | ||
192 | #define AUDIT_COMPARE_SGID_TO_OBJ_GID 7 | ||
193 | #define AUDIT_COMPARE_FSUID_TO_OBJ_UID 8 | ||
194 | #define AUDIT_COMPARE_FSGID_TO_OBJ_GID 9 | ||
195 | |||
196 | #define AUDIT_COMPARE_UID_TO_AUID 10 | ||
197 | #define AUDIT_COMPARE_UID_TO_EUID 11 | ||
198 | #define AUDIT_COMPARE_UID_TO_FSUID 12 | ||
199 | #define AUDIT_COMPARE_UID_TO_SUID 13 | ||
200 | |||
201 | #define AUDIT_COMPARE_AUID_TO_FSUID 14 | ||
202 | #define AUDIT_COMPARE_AUID_TO_SUID 15 | ||
203 | #define AUDIT_COMPARE_AUID_TO_EUID 16 | ||
204 | |||
205 | #define AUDIT_COMPARE_EUID_TO_SUID 17 | ||
206 | #define AUDIT_COMPARE_EUID_TO_FSUID 18 | ||
207 | |||
208 | #define AUDIT_COMPARE_SUID_TO_FSUID 19 | ||
209 | |||
210 | #define AUDIT_COMPARE_GID_TO_EGID 20 | ||
211 | #define AUDIT_COMPARE_GID_TO_FSGID 21 | ||
212 | #define AUDIT_COMPARE_GID_TO_SGID 22 | ||
213 | |||
214 | #define AUDIT_COMPARE_EGID_TO_FSGID 23 | ||
215 | #define AUDIT_COMPARE_EGID_TO_SGID 24 | ||
216 | #define AUDIT_COMPARE_SGID_TO_FSGID 25 | ||
217 | |||
218 | #define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_SGID_TO_FSGID | ||
184 | 219 | ||
185 | /* Rule fields */ | 220 | /* Rule fields */ |
186 | /* These are useful when checking the | 221 | /* These are useful when checking the |
@@ -222,6 +257,9 @@ | |||
222 | #define AUDIT_PERM 106 | 257 | #define AUDIT_PERM 106 |
223 | #define AUDIT_DIR 107 | 258 | #define AUDIT_DIR 107 |
224 | #define AUDIT_FILETYPE 108 | 259 | #define AUDIT_FILETYPE 108 |
260 | #define AUDIT_OBJ_UID 109 | ||
261 | #define AUDIT_OBJ_GID 110 | ||
262 | #define AUDIT_FIELD_COMPARE 111 | ||
225 | 263 | ||
226 | #define AUDIT_ARG0 200 | 264 | #define AUDIT_ARG0 200 |
227 | #define AUDIT_ARG1 (AUDIT_ARG0+1) | 265 | #define AUDIT_ARG1 (AUDIT_ARG0+1) |
@@ -408,28 +446,24 @@ struct audit_field { | |||
408 | void *lsm_rule; | 446 | void *lsm_rule; |
409 | }; | 447 | }; |
410 | 448 | ||
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 ) | ||
415 | extern int __init audit_register_class(int class, unsigned *list); | 449 | extern int __init audit_register_class(int class, unsigned *list); |
416 | extern int audit_classify_syscall(int abi, unsigned syscall); | 450 | extern int audit_classify_syscall(int abi, unsigned syscall); |
417 | extern int audit_classify_arch(int arch); | 451 | extern int audit_classify_arch(int arch); |
418 | #ifdef CONFIG_AUDITSYSCALL | 452 | #ifdef CONFIG_AUDITSYSCALL |
419 | /* These are defined in auditsc.c */ | 453 | /* These are defined in auditsc.c */ |
420 | /* Public API */ | 454 | /* Public API */ |
421 | extern void audit_finish_fork(struct task_struct *child); | ||
422 | extern int audit_alloc(struct task_struct *task); | 455 | extern int audit_alloc(struct task_struct *task); |
423 | extern void audit_free(struct task_struct *task); | 456 | extern void __audit_free(struct task_struct *task); |
424 | extern void audit_syscall_entry(int arch, | 457 | extern void __audit_syscall_entry(int arch, |
425 | int major, unsigned long a0, unsigned long a1, | 458 | int major, unsigned long a0, unsigned long a1, |
426 | unsigned long a2, unsigned long a3); | 459 | unsigned long a2, unsigned long a3); |
427 | extern void audit_syscall_exit(int failed, long return_code); | 460 | extern void __audit_syscall_exit(int ret_success, long ret_value); |
428 | extern void __audit_getname(const char *name); | 461 | extern void __audit_getname(const char *name); |
429 | extern void audit_putname(const char *name); | 462 | extern void audit_putname(const char *name); |
430 | extern void __audit_inode(const char *name, const struct dentry *dentry); | 463 | extern void __audit_inode(const char *name, const struct dentry *dentry); |
431 | extern void __audit_inode_child(const struct dentry *dentry, | 464 | extern void __audit_inode_child(const struct dentry *dentry, |
432 | const struct inode *parent); | 465 | const struct inode *parent); |
466 | extern void __audit_seccomp(unsigned long syscall); | ||
433 | extern void __audit_ptrace(struct task_struct *t); | 467 | extern void __audit_ptrace(struct task_struct *t); |
434 | 468 | ||
435 | static inline int audit_dummy_context(void) | 469 | static inline int audit_dummy_context(void) |
@@ -437,6 +471,27 @@ static inline int audit_dummy_context(void) | |||
437 | void *p = current->audit_context; | 471 | void *p = current->audit_context; |
438 | return !p || *(int *)p; | 472 | return !p || *(int *)p; |
439 | } | 473 | } |
474 | static inline void audit_free(struct task_struct *task) | ||
475 | { | ||
476 | if (unlikely(task->audit_context)) | ||
477 | __audit_free(task); | ||
478 | } | ||
479 | static inline void audit_syscall_entry(int arch, int major, unsigned long a0, | ||
480 | unsigned long a1, unsigned long a2, | ||
481 | unsigned long a3) | ||
482 | { | ||
483 | if (unlikely(!audit_dummy_context())) | ||
484 | __audit_syscall_entry(arch, major, a0, a1, a2, a3); | ||
485 | } | ||
486 | static inline void audit_syscall_exit(void *pt_regs) | ||
487 | { | ||
488 | if (unlikely(current->audit_context)) { | ||
489 | int success = is_syscall_success(pt_regs); | ||
490 | int return_code = regs_return_value(pt_regs); | ||
491 | |||
492 | __audit_syscall_exit(success, return_code); | ||
493 | } | ||
494 | } | ||
440 | static inline void audit_getname(const char *name) | 495 | static inline void audit_getname(const char *name) |
441 | { | 496 | { |
442 | if (unlikely(!audit_dummy_context())) | 497 | if (unlikely(!audit_dummy_context())) |
@@ -453,6 +508,12 @@ static inline void audit_inode_child(const struct dentry *dentry, | |||
453 | } | 508 | } |
454 | void audit_core_dumps(long signr); | 509 | void audit_core_dumps(long signr); |
455 | 510 | ||
511 | static inline void audit_seccomp(unsigned long syscall) | ||
512 | { | ||
513 | if (unlikely(!audit_dummy_context())) | ||
514 | __audit_seccomp(syscall); | ||
515 | } | ||
516 | |||
456 | static inline void audit_ptrace(struct task_struct *t) | 517 | static inline void audit_ptrace(struct task_struct *t) |
457 | { | 518 | { |
458 | if (unlikely(!audit_dummy_context())) | 519 | if (unlikely(!audit_dummy_context())) |
@@ -463,17 +524,16 @@ static inline void audit_ptrace(struct task_struct *t) | |||
463 | extern unsigned int audit_serial(void); | 524 | extern unsigned int audit_serial(void); |
464 | extern int auditsc_get_stamp(struct audit_context *ctx, | 525 | extern int auditsc_get_stamp(struct audit_context *ctx, |
465 | struct timespec *t, unsigned int *serial); | 526 | struct timespec *t, unsigned int *serial); |
466 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); | 527 | extern int audit_set_loginuid(uid_t loginuid); |
467 | #define audit_get_loginuid(t) ((t)->loginuid) | 528 | #define audit_get_loginuid(t) ((t)->loginuid) |
468 | #define audit_get_sessionid(t) ((t)->sessionid) | 529 | #define audit_get_sessionid(t) ((t)->sessionid) |
469 | extern void audit_log_task_context(struct audit_buffer *ab); | 530 | extern void audit_log_task_context(struct audit_buffer *ab); |
470 | extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); | 531 | extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); |
471 | extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode); | 532 | extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode); |
472 | extern int audit_bprm(struct linux_binprm *bprm); | 533 | extern int __audit_bprm(struct linux_binprm *bprm); |
473 | extern void audit_socketcall(int nargs, unsigned long *args); | 534 | extern void __audit_socketcall(int nargs, unsigned long *args); |
474 | extern int audit_sockaddr(int len, void *addr); | 535 | extern int __audit_sockaddr(int len, void *addr); |
475 | extern void __audit_fd_pair(int fd1, int fd2); | 536 | extern void __audit_fd_pair(int fd1, int fd2); |
476 | extern int audit_set_macxattr(const char *name); | ||
477 | extern void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr); | 537 | extern void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr); |
478 | extern void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout); | 538 | extern void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout); |
479 | extern void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification); | 539 | extern void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification); |
@@ -499,6 +559,23 @@ static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid | |||
499 | if (unlikely(!audit_dummy_context())) | 559 | if (unlikely(!audit_dummy_context())) |
500 | __audit_ipc_set_perm(qbytes, uid, gid, mode); | 560 | __audit_ipc_set_perm(qbytes, uid, gid, mode); |
501 | } | 561 | } |
562 | static inline int audit_bprm(struct linux_binprm *bprm) | ||
563 | { | ||
564 | if (unlikely(!audit_dummy_context())) | ||
565 | return __audit_bprm(bprm); | ||
566 | return 0; | ||
567 | } | ||
568 | static inline void audit_socketcall(int nargs, unsigned long *args) | ||
569 | { | ||
570 | if (unlikely(!audit_dummy_context())) | ||
571 | __audit_socketcall(nargs, args); | ||
572 | } | ||
573 | static inline int audit_sockaddr(int len, void *addr) | ||
574 | { | ||
575 | if (unlikely(!audit_dummy_context())) | ||
576 | return __audit_sockaddr(len, addr); | ||
577 | return 0; | ||
578 | } | ||
502 | static inline void audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr) | 579 | static inline void audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr) |
503 | { | 580 | { |
504 | if (unlikely(!audit_dummy_context())) | 581 | if (unlikely(!audit_dummy_context())) |
@@ -544,12 +621,11 @@ static inline void audit_mmap_fd(int fd, int flags) | |||
544 | 621 | ||
545 | extern int audit_n_rules; | 622 | extern int audit_n_rules; |
546 | extern int audit_signals; | 623 | extern int audit_signals; |
547 | #else | 624 | #else /* CONFIG_AUDITSYSCALL */ |
548 | #define audit_finish_fork(t) | ||
549 | #define audit_alloc(t) ({ 0; }) | 625 | #define audit_alloc(t) ({ 0; }) |
550 | #define audit_free(t) do { ; } while (0) | 626 | #define audit_free(t) do { ; } while (0) |
551 | #define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0) | 627 | #define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0) |
552 | #define audit_syscall_exit(f,r) do { ; } while (0) | 628 | #define audit_syscall_exit(r) do { ; } while (0) |
553 | #define audit_dummy_context() 1 | 629 | #define audit_dummy_context() 1 |
554 | #define audit_getname(n) do { ; } while (0) | 630 | #define audit_getname(n) do { ; } while (0) |
555 | #define audit_putname(n) do { ; } while (0) | 631 | #define audit_putname(n) do { ; } while (0) |
@@ -558,6 +634,7 @@ extern int audit_signals; | |||
558 | #define audit_inode(n,d) do { (void)(d); } while (0) | 634 | #define audit_inode(n,d) do { (void)(d); } while (0) |
559 | #define audit_inode_child(i,p) do { ; } while (0) | 635 | #define audit_inode_child(i,p) do { ; } while (0) |
560 | #define audit_core_dumps(i) do { ; } while (0) | 636 | #define audit_core_dumps(i) do { ; } while (0) |
637 | #define audit_seccomp(i) do { ; } while (0) | ||
561 | #define auditsc_get_stamp(c,t,s) (0) | 638 | #define auditsc_get_stamp(c,t,s) (0) |
562 | #define audit_get_loginuid(t) (-1) | 639 | #define audit_get_loginuid(t) (-1) |
563 | #define audit_get_sessionid(t) (-1) | 640 | #define audit_get_sessionid(t) (-1) |
@@ -568,7 +645,6 @@ extern int audit_signals; | |||
568 | #define audit_socketcall(n,a) ((void)0) | 645 | #define audit_socketcall(n,a) ((void)0) |
569 | #define audit_fd_pair(n,a) ((void)0) | 646 | #define audit_fd_pair(n,a) ((void)0) |
570 | #define audit_sockaddr(len, addr) ({ 0; }) | 647 | #define audit_sockaddr(len, addr) ({ 0; }) |
571 | #define audit_set_macxattr(n) do { ; } while (0) | ||
572 | #define audit_mq_open(o,m,a) ((void)0) | 648 | #define audit_mq_open(o,m,a) ((void)0) |
573 | #define audit_mq_sendrecv(d,l,p,t) ((void)0) | 649 | #define audit_mq_sendrecv(d,l,p,t) ((void)0) |
574 | #define audit_mq_notify(d,n) ((void)0) | 650 | #define audit_mq_notify(d,n) ((void)0) |
@@ -579,7 +655,7 @@ extern int audit_signals; | |||
579 | #define audit_ptrace(t) ((void)0) | 655 | #define audit_ptrace(t) ((void)0) |
580 | #define audit_n_rules 0 | 656 | #define audit_n_rules 0 |
581 | #define audit_signals 0 | 657 | #define audit_signals 0 |
582 | #endif | 658 | #endif /* CONFIG_AUDITSYSCALL */ |
583 | 659 | ||
584 | #ifdef CONFIG_AUDIT | 660 | #ifdef CONFIG_AUDIT |
585 | /* These are defined in audit.c */ | 661 | /* These are defined in audit.c */ |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index a27e56ca41a4..c2f1f6a5fcb8 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 | ||
117 | extern long arch_ptrace(struct task_struct *child, long request, | 118 | extern long arch_ptrace(struct task_struct *child, long request, |
@@ -266,6 +267,15 @@ static inline void ptrace_release_task(struct task_struct *task) | |||
266 | #define force_successful_syscall_return() do { } while (0) | 267 | #define force_successful_syscall_return() do { } while (0) |
267 | #endif | 268 | #endif |
268 | 269 | ||
270 | #ifndef is_syscall_success | ||
271 | /* | ||
272 | * On most systems we can tell if a syscall is a success based on if the retval | ||
273 | * is an error value. On some systems like ia64 and powerpc they have different | ||
274 | * indicators of success/failure and must define their own. | ||
275 | */ | ||
276 | #define is_syscall_success(regs) (!IS_ERR_VALUE((unsigned long)(regs_return_value(regs)))) | ||
277 | #endif | ||
278 | |||
269 | /* | 279 | /* |
270 | * <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__. | 280 | * <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__. |
271 | * | 281 | * |
diff --git a/init/Kconfig b/init/Kconfig index 6ac2236244c3..3f42cd66f0f8 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -355,7 +355,7 @@ config AUDIT | |||
355 | 355 | ||
356 | config AUDITSYSCALL | 356 | config AUDITSYSCALL |
357 | bool "Enable system-call auditing support" | 357 | bool "Enable system-call auditing support" |
358 | depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH) | 358 | depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || ARM) |
359 | default y if SECURITY_SELINUX | 359 | default y if SECURITY_SELINUX |
360 | help | 360 | help |
361 | Enable low-overhead system-call auditing infrastructure that | 361 | Enable low-overhead system-call auditing infrastructure that |
@@ -372,6 +372,20 @@ config AUDIT_TREE | |||
372 | depends on AUDITSYSCALL | 372 | depends on AUDITSYSCALL |
373 | select FSNOTIFY | 373 | select FSNOTIFY |
374 | 374 | ||
375 | config AUDIT_LOGINUID_IMMUTABLE | ||
376 | bool "Make audit loginuid immutable" | ||
377 | depends on AUDIT | ||
378 | help | ||
379 | The config option toggles if a task setting its loginuid requires | ||
380 | CAP_SYS_AUDITCONTROL or if that task should require no special permissions | ||
381 | but should instead only allow setting its loginuid if it was never | ||
382 | previously set. On systems which use systemd or a similar central | ||
383 | process to restart login services this should be set to true. On older | ||
384 | systems in which an admin would typically have to directly stop and | ||
385 | start processes this should be set to false. Setting this to true allows | ||
386 | one to drop potentially dangerous capabilites from the login tasks, | ||
387 | but may not be backwards compatible with older init systems. | ||
388 | |||
375 | source "kernel/irq/Kconfig" | 389 | source "kernel/irq/Kconfig" |
376 | 390 | ||
377 | menu "RCU Subsystem" | 391 | menu "RCU Subsystem" |
diff --git a/kernel/audit.c b/kernel/audit.c index 57e3f5107937..bb0eb5bb9a0a 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -631,7 +631,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, | |||
631 | } | 631 | } |
632 | 632 | ||
633 | *ab = audit_log_start(NULL, GFP_KERNEL, msg_type); | 633 | *ab = audit_log_start(NULL, GFP_KERNEL, msg_type); |
634 | audit_log_format(*ab, "user pid=%d uid=%u auid=%u ses=%u", | 634 | audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u", |
635 | pid, uid, auid, ses); | 635 | pid, uid, auid, ses); |
636 | if (sid) { | 636 | if (sid) { |
637 | rc = security_secid_to_secctx(sid, &ctx, &len); | 637 | rc = security_secid_to_secctx(sid, &ctx, &len); |
@@ -1423,7 +1423,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, | |||
1423 | char *p, *pathname; | 1423 | char *p, *pathname; |
1424 | 1424 | ||
1425 | if (prefix) | 1425 | if (prefix) |
1426 | audit_log_format(ab, " %s", prefix); | 1426 | audit_log_format(ab, "%s", prefix); |
1427 | 1427 | ||
1428 | /* We will allow 11 spaces for ' (deleted)' to be appended */ | 1428 | /* We will allow 11 spaces for ' (deleted)' to be appended */ |
1429 | pathname = kmalloc(PATH_MAX+11, ab->gfp_mask); | 1429 | pathname = kmalloc(PATH_MAX+11, ab->gfp_mask); |
diff --git a/kernel/audit.h b/kernel/audit.h index 91e7071c4d2c..816766803371 100644 --- a/kernel/audit.h +++ b/kernel/audit.h | |||
@@ -36,12 +36,8 @@ enum audit_state { | |||
36 | AUDIT_DISABLED, /* Do not create per-task audit_context. | 36 | AUDIT_DISABLED, /* Do not create per-task audit_context. |
37 | * No syscall-specific audit records can | 37 | * No syscall-specific audit records can |
38 | * be generated. */ | 38 | * be generated. */ |
39 | AUDIT_SETUP_CONTEXT, /* Create the per-task audit_context, | ||
40 | * but don't necessarily fill it in at | ||
41 | * syscall entry time (i.e., filter | ||
42 | * instead). */ | ||
43 | AUDIT_BUILD_CONTEXT, /* Create the per-task audit_context, | 39 | AUDIT_BUILD_CONTEXT, /* Create the per-task audit_context, |
44 | * and always fill it in at syscall | 40 | * and fill it in at syscall |
45 | * entry time. This makes a full | 41 | * entry time. This makes a full |
46 | * syscall record available if some | 42 | * syscall record available if some |
47 | * other part of the kernel decides it | 43 | * other part of the kernel decides it |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index f8277c80d678..a6c3f1abd206 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -235,13 +235,15 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) | |||
235 | switch(listnr) { | 235 | switch(listnr) { |
236 | default: | 236 | default: |
237 | goto exit_err; | 237 | goto exit_err; |
238 | case AUDIT_FILTER_USER: | ||
239 | case AUDIT_FILTER_TYPE: | ||
240 | #ifdef CONFIG_AUDITSYSCALL | 238 | #ifdef CONFIG_AUDITSYSCALL |
241 | case AUDIT_FILTER_ENTRY: | 239 | case AUDIT_FILTER_ENTRY: |
240 | if (rule->action == AUDIT_ALWAYS) | ||
241 | goto exit_err; | ||
242 | case AUDIT_FILTER_EXIT: | 242 | case AUDIT_FILTER_EXIT: |
243 | case AUDIT_FILTER_TASK: | 243 | case AUDIT_FILTER_TASK: |
244 | #endif | 244 | #endif |
245 | case AUDIT_FILTER_USER: | ||
246 | case AUDIT_FILTER_TYPE: | ||
245 | ; | 247 | ; |
246 | } | 248 | } |
247 | if (unlikely(rule->action == AUDIT_POSSIBLE)) { | 249 | if (unlikely(rule->action == AUDIT_POSSIBLE)) { |
@@ -385,7 +387,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) | |||
385 | goto exit_free; | 387 | goto exit_free; |
386 | break; | 388 | break; |
387 | case AUDIT_FILETYPE: | 389 | case AUDIT_FILETYPE: |
388 | if ((f->val & ~S_IFMT) > S_IFMT) | 390 | if (f->val & ~S_IFMT) |
389 | goto exit_free; | 391 | goto exit_free; |
390 | break; | 392 | break; |
391 | case AUDIT_INODE: | 393 | case AUDIT_INODE: |
@@ -459,6 +461,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, | |||
459 | case AUDIT_ARG1: | 461 | case AUDIT_ARG1: |
460 | case AUDIT_ARG2: | 462 | case AUDIT_ARG2: |
461 | case AUDIT_ARG3: | 463 | case AUDIT_ARG3: |
464 | case AUDIT_OBJ_UID: | ||
465 | case AUDIT_OBJ_GID: | ||
462 | break; | 466 | break; |
463 | case AUDIT_ARCH: | 467 | case AUDIT_ARCH: |
464 | entry->rule.arch_f = f; | 468 | entry->rule.arch_f = f; |
@@ -522,7 +526,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, | |||
522 | goto exit_free; | 526 | goto exit_free; |
523 | break; | 527 | break; |
524 | case AUDIT_FILTERKEY: | 528 | case AUDIT_FILTERKEY: |
525 | err = -EINVAL; | ||
526 | if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN) | 529 | if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN) |
527 | goto exit_free; | 530 | goto exit_free; |
528 | str = audit_unpack_string(&bufp, &remain, f->val); | 531 | str = audit_unpack_string(&bufp, &remain, f->val); |
@@ -536,7 +539,11 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, | |||
536 | goto exit_free; | 539 | goto exit_free; |
537 | break; | 540 | break; |
538 | case AUDIT_FILETYPE: | 541 | case AUDIT_FILETYPE: |
539 | if ((f->val & ~S_IFMT) > S_IFMT) | 542 | if (f->val & ~S_IFMT) |
543 | goto exit_free; | ||
544 | break; | ||
545 | case AUDIT_FIELD_COMPARE: | ||
546 | if (f->val > AUDIT_MAX_FIELD_COMPARE) | ||
540 | goto exit_free; | 547 | goto exit_free; |
541 | break; | 548 | break; |
542 | default: | 549 | default: |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index e7fe2b0d29b3..caaea6e944f8 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -70,9 +70,15 @@ | |||
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(). */ | 79 | * for saving names from getname(). If we get more names we will allocate |
75 | #define AUDIT_NAMES 20 | 80 | * a name dynamically and also add those to the list anchored by names_list. */ |
81 | #define AUDIT_NAMES 5 | ||
76 | 82 | ||
77 | /* Indicates that audit should log the full pathname. */ | 83 | /* Indicates that audit should log the full pathname. */ |
78 | #define AUDIT_NAME_FULL -1 | 84 | #define AUDIT_NAME_FULL -1 |
@@ -101,9 +107,8 @@ struct audit_cap_data { | |||
101 | * | 107 | * |
102 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ | 108 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ |
103 | struct audit_names { | 109 | struct audit_names { |
110 | struct list_head list; /* audit_context->names_list */ | ||
104 | const char *name; | 111 | const char *name; |
105 | int name_len; /* number of name's characters to log */ | ||
106 | unsigned name_put; /* call __putname() for this name */ | ||
107 | unsigned long ino; | 112 | unsigned long ino; |
108 | dev_t dev; | 113 | dev_t dev; |
109 | umode_t mode; | 114 | umode_t mode; |
@@ -113,6 +118,14 @@ struct audit_names { | |||
113 | u32 osid; | 118 | u32 osid; |
114 | struct audit_cap_data fcap; | 119 | struct audit_cap_data fcap; |
115 | unsigned int fcap_ver; | 120 | unsigned int fcap_ver; |
121 | int name_len; /* number of name's characters to log */ | ||
122 | bool name_put; /* call __putname() for this name */ | ||
123 | /* | ||
124 | * This was an allocated audit_names and not from the array of | ||
125 | * names allocated in the task audit context. Thus this name | ||
126 | * should be freed on syscall exit | ||
127 | */ | ||
128 | bool should_free; | ||
116 | }; | 129 | }; |
117 | 130 | ||
118 | struct audit_aux_data { | 131 | struct audit_aux_data { |
@@ -174,8 +187,17 @@ struct audit_context { | |||
174 | long return_code;/* syscall return code */ | 187 | long return_code;/* syscall return code */ |
175 | u64 prio; | 188 | u64 prio; |
176 | int return_valid; /* return code is valid */ | 189 | int return_valid; /* return code is valid */ |
177 | int name_count; | 190 | /* |
178 | struct audit_names names[AUDIT_NAMES]; | 191 | * The names_list is the list of all audit_names collected during this |
192 | * syscall. The first AUDIT_NAMES entries in the names_list will | ||
193 | * actually be from the preallocated_names array for performance | ||
194 | * reasons. Except during allocation they should never be referenced | ||
195 | * through the preallocated_names array and should only be found/used | ||
196 | * by running the names_list. | ||
197 | */ | ||
198 | struct audit_names preallocated_names[AUDIT_NAMES]; | ||
199 | int name_count; /* total records in names_list */ | ||
200 | struct list_head names_list; /* anchor for struct audit_names->list */ | ||
179 | char * filterkey; /* key for rule that triggered record */ | 201 | char * filterkey; /* key for rule that triggered record */ |
180 | struct path pwd; | 202 | struct path pwd; |
181 | struct audit_context *previous; /* For nested syscalls */ | 203 | struct audit_context *previous; /* For nested syscalls */ |
@@ -305,21 +327,21 @@ static int audit_match_perm(struct audit_context *ctx, int mask) | |||
305 | } | 327 | } |
306 | } | 328 | } |
307 | 329 | ||
308 | static int audit_match_filetype(struct audit_context *ctx, int which) | 330 | static int audit_match_filetype(struct audit_context *ctx, int val) |
309 | { | 331 | { |
310 | unsigned index = which & ~S_IFMT; | 332 | struct audit_names *n; |
311 | umode_t mode = which & S_IFMT; | 333 | umode_t mode = (umode_t)val; |
312 | 334 | ||
313 | if (unlikely(!ctx)) | 335 | if (unlikely(!ctx)) |
314 | return 0; | 336 | return 0; |
315 | 337 | ||
316 | if (index >= ctx->name_count) | 338 | list_for_each_entry(n, &ctx->names_list, list) { |
317 | return 0; | 339 | if ((n->ino != -1) && |
318 | if (ctx->names[index].ino == -1) | 340 | ((n->mode & S_IFMT) == mode)) |
319 | return 0; | 341 | return 1; |
320 | if ((ctx->names[index].mode ^ mode) & S_IFMT) | 342 | } |
321 | return 0; | 343 | |
322 | return 1; | 344 | return 0; |
323 | } | 345 | } |
324 | 346 | ||
325 | /* | 347 | /* |
@@ -441,6 +463,134 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree) | |||
441 | return 0; | 463 | return 0; |
442 | } | 464 | } |
443 | 465 | ||
466 | static int audit_compare_id(uid_t uid1, | ||
467 | struct audit_names *name, | ||
468 | unsigned long name_offset, | ||
469 | struct audit_field *f, | ||
470 | struct audit_context *ctx) | ||
471 | { | ||
472 | struct audit_names *n; | ||
473 | unsigned long addr; | ||
474 | uid_t uid2; | ||
475 | int rc; | ||
476 | |||
477 | BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t)); | ||
478 | |||
479 | if (name) { | ||
480 | addr = (unsigned long)name; | ||
481 | addr += name_offset; | ||
482 | |||
483 | uid2 = *(uid_t *)addr; | ||
484 | rc = audit_comparator(uid1, f->op, uid2); | ||
485 | if (rc) | ||
486 | return rc; | ||
487 | } | ||
488 | |||
489 | if (ctx) { | ||
490 | list_for_each_entry(n, &ctx->names_list, list) { | ||
491 | addr = (unsigned long)n; | ||
492 | addr += name_offset; | ||
493 | |||
494 | uid2 = *(uid_t *)addr; | ||
495 | |||
496 | rc = audit_comparator(uid1, f->op, uid2); | ||
497 | if (rc) | ||
498 | return rc; | ||
499 | } | ||
500 | } | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | static int audit_field_compare(struct task_struct *tsk, | ||
505 | const struct cred *cred, | ||
506 | struct audit_field *f, | ||
507 | struct audit_context *ctx, | ||
508 | struct audit_names *name) | ||
509 | { | ||
510 | switch (f->val) { | ||
511 | /* process to file object comparisons */ | ||
512 | case AUDIT_COMPARE_UID_TO_OBJ_UID: | ||
513 | return audit_compare_id(cred->uid, | ||
514 | name, offsetof(struct audit_names, uid), | ||
515 | f, ctx); | ||
516 | case AUDIT_COMPARE_GID_TO_OBJ_GID: | ||
517 | return audit_compare_id(cred->gid, | ||
518 | name, offsetof(struct audit_names, gid), | ||
519 | f, ctx); | ||
520 | case AUDIT_COMPARE_EUID_TO_OBJ_UID: | ||
521 | return audit_compare_id(cred->euid, | ||
522 | name, offsetof(struct audit_names, uid), | ||
523 | f, ctx); | ||
524 | case AUDIT_COMPARE_EGID_TO_OBJ_GID: | ||
525 | return audit_compare_id(cred->egid, | ||
526 | name, offsetof(struct audit_names, gid), | ||
527 | f, ctx); | ||
528 | case AUDIT_COMPARE_AUID_TO_OBJ_UID: | ||
529 | return audit_compare_id(tsk->loginuid, | ||
530 | name, offsetof(struct audit_names, uid), | ||
531 | f, ctx); | ||
532 | case AUDIT_COMPARE_SUID_TO_OBJ_UID: | ||
533 | return audit_compare_id(cred->suid, | ||
534 | name, offsetof(struct audit_names, uid), | ||
535 | f, ctx); | ||
536 | case AUDIT_COMPARE_SGID_TO_OBJ_GID: | ||
537 | return audit_compare_id(cred->sgid, | ||
538 | name, offsetof(struct audit_names, gid), | ||
539 | f, ctx); | ||
540 | case AUDIT_COMPARE_FSUID_TO_OBJ_UID: | ||
541 | return audit_compare_id(cred->fsuid, | ||
542 | name, offsetof(struct audit_names, uid), | ||
543 | f, ctx); | ||
544 | case AUDIT_COMPARE_FSGID_TO_OBJ_GID: | ||
545 | return audit_compare_id(cred->fsgid, | ||
546 | name, offsetof(struct audit_names, gid), | ||
547 | f, ctx); | ||
548 | /* uid comparisons */ | ||
549 | case AUDIT_COMPARE_UID_TO_AUID: | ||
550 | return audit_comparator(cred->uid, f->op, tsk->loginuid); | ||
551 | case AUDIT_COMPARE_UID_TO_EUID: | ||
552 | return audit_comparator(cred->uid, f->op, cred->euid); | ||
553 | case AUDIT_COMPARE_UID_TO_SUID: | ||
554 | return audit_comparator(cred->uid, f->op, cred->suid); | ||
555 | case AUDIT_COMPARE_UID_TO_FSUID: | ||
556 | return audit_comparator(cred->uid, f->op, cred->fsuid); | ||
557 | /* auid comparisons */ | ||
558 | case AUDIT_COMPARE_AUID_TO_EUID: | ||
559 | return audit_comparator(tsk->loginuid, f->op, cred->euid); | ||
560 | case AUDIT_COMPARE_AUID_TO_SUID: | ||
561 | return audit_comparator(tsk->loginuid, f->op, cred->suid); | ||
562 | case AUDIT_COMPARE_AUID_TO_FSUID: | ||
563 | return audit_comparator(tsk->loginuid, f->op, cred->fsuid); | ||
564 | /* euid comparisons */ | ||
565 | case AUDIT_COMPARE_EUID_TO_SUID: | ||
566 | return audit_comparator(cred->euid, f->op, cred->suid); | ||
567 | case AUDIT_COMPARE_EUID_TO_FSUID: | ||
568 | return audit_comparator(cred->euid, f->op, cred->fsuid); | ||
569 | /* suid comparisons */ | ||
570 | case AUDIT_COMPARE_SUID_TO_FSUID: | ||
571 | return audit_comparator(cred->suid, f->op, cred->fsuid); | ||
572 | /* gid comparisons */ | ||
573 | case AUDIT_COMPARE_GID_TO_EGID: | ||
574 | return audit_comparator(cred->gid, f->op, cred->egid); | ||
575 | case AUDIT_COMPARE_GID_TO_SGID: | ||
576 | return audit_comparator(cred->gid, f->op, cred->sgid); | ||
577 | case AUDIT_COMPARE_GID_TO_FSGID: | ||
578 | return audit_comparator(cred->gid, f->op, cred->fsgid); | ||
579 | /* egid comparisons */ | ||
580 | case AUDIT_COMPARE_EGID_TO_SGID: | ||
581 | return audit_comparator(cred->egid, f->op, cred->sgid); | ||
582 | case AUDIT_COMPARE_EGID_TO_FSGID: | ||
583 | return audit_comparator(cred->egid, f->op, cred->fsgid); | ||
584 | /* sgid comparison */ | ||
585 | case AUDIT_COMPARE_SGID_TO_FSGID: | ||
586 | return audit_comparator(cred->sgid, f->op, cred->fsgid); | ||
587 | default: | ||
588 | WARN(1, "Missing AUDIT_COMPARE define. Report as a bug\n"); | ||
589 | return 0; | ||
590 | } | ||
591 | return 0; | ||
592 | } | ||
593 | |||
444 | /* Determine if any context name data matches a rule's watch data */ | 594 | /* Determine if any context name data matches a rule's watch data */ |
445 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 | 595 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 |
446 | * otherwise. | 596 | * otherwise. |
@@ -457,13 +607,14 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
457 | bool task_creation) | 607 | bool task_creation) |
458 | { | 608 | { |
459 | const struct cred *cred; | 609 | const struct cred *cred; |
460 | int i, j, need_sid = 1; | 610 | int i, need_sid = 1; |
461 | u32 sid; | 611 | u32 sid; |
462 | 612 | ||
463 | cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); | 613 | cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); |
464 | 614 | ||
465 | for (i = 0; i < rule->field_count; i++) { | 615 | for (i = 0; i < rule->field_count; i++) { |
466 | struct audit_field *f = &rule->fields[i]; | 616 | struct audit_field *f = &rule->fields[i]; |
617 | struct audit_names *n; | ||
467 | int result = 0; | 618 | int result = 0; |
468 | 619 | ||
469 | switch (f->type) { | 620 | switch (f->type) { |
@@ -522,12 +673,14 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
522 | } | 673 | } |
523 | break; | 674 | break; |
524 | case AUDIT_DEVMAJOR: | 675 | case AUDIT_DEVMAJOR: |
525 | if (name) | 676 | if (name) { |
526 | result = audit_comparator(MAJOR(name->dev), | 677 | if (audit_comparator(MAJOR(name->dev), f->op, f->val) || |
527 | f->op, f->val); | 678 | audit_comparator(MAJOR(name->rdev), f->op, f->val)) |
528 | else if (ctx) { | 679 | ++result; |
529 | for (j = 0; j < ctx->name_count; j++) { | 680 | } else if (ctx) { |
530 | if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { | 681 | list_for_each_entry(n, &ctx->names_list, list) { |
682 | if (audit_comparator(MAJOR(n->dev), f->op, f->val) || | ||
683 | audit_comparator(MAJOR(n->rdev), f->op, f->val)) { | ||
531 | ++result; | 684 | ++result; |
532 | break; | 685 | break; |
533 | } | 686 | } |
@@ -535,12 +688,14 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
535 | } | 688 | } |
536 | break; | 689 | break; |
537 | case AUDIT_DEVMINOR: | 690 | case AUDIT_DEVMINOR: |
538 | if (name) | 691 | if (name) { |
539 | result = audit_comparator(MINOR(name->dev), | 692 | if (audit_comparator(MINOR(name->dev), f->op, f->val) || |
540 | f->op, f->val); | 693 | audit_comparator(MINOR(name->rdev), f->op, f->val)) |
541 | else if (ctx) { | 694 | ++result; |
542 | for (j = 0; j < ctx->name_count; j++) { | 695 | } else if (ctx) { |
543 | if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { | 696 | list_for_each_entry(n, &ctx->names_list, list) { |
697 | if (audit_comparator(MINOR(n->dev), f->op, f->val) || | ||
698 | audit_comparator(MINOR(n->rdev), f->op, f->val)) { | ||
544 | ++result; | 699 | ++result; |
545 | break; | 700 | break; |
546 | } | 701 | } |
@@ -551,8 +706,32 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
551 | if (name) | 706 | if (name) |
552 | result = (name->ino == f->val); | 707 | result = (name->ino == f->val); |
553 | else if (ctx) { | 708 | else if (ctx) { |
554 | for (j = 0; j < ctx->name_count; j++) { | 709 | list_for_each_entry(n, &ctx->names_list, list) { |
555 | if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { | 710 | if (audit_comparator(n->ino, f->op, f->val)) { |
711 | ++result; | ||
712 | break; | ||
713 | } | ||
714 | } | ||
715 | } | ||
716 | break; | ||
717 | case AUDIT_OBJ_UID: | ||
718 | if (name) { | ||
719 | result = audit_comparator(name->uid, f->op, f->val); | ||
720 | } else if (ctx) { | ||
721 | list_for_each_entry(n, &ctx->names_list, list) { | ||
722 | if (audit_comparator(n->uid, f->op, f->val)) { | ||
723 | ++result; | ||
724 | break; | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | break; | ||
729 | case AUDIT_OBJ_GID: | ||
730 | if (name) { | ||
731 | result = audit_comparator(name->gid, f->op, f->val); | ||
732 | } else if (ctx) { | ||
733 | list_for_each_entry(n, &ctx->names_list, list) { | ||
734 | if (audit_comparator(n->gid, f->op, f->val)) { | ||
556 | ++result; | 735 | ++result; |
557 | break; | 736 | break; |
558 | } | 737 | } |
@@ -607,11 +786,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
607 | name->osid, f->type, f->op, | 786 | name->osid, f->type, f->op, |
608 | f->lsm_rule, ctx); | 787 | f->lsm_rule, ctx); |
609 | } else if (ctx) { | 788 | } else if (ctx) { |
610 | for (j = 0; j < ctx->name_count; j++) { | 789 | list_for_each_entry(n, &ctx->names_list, list) { |
611 | if (security_audit_rule_match( | 790 | if (security_audit_rule_match(n->osid, f->type, |
612 | ctx->names[j].osid, | 791 | f->op, f->lsm_rule, |
613 | f->type, f->op, | 792 | ctx)) { |
614 | f->lsm_rule, ctx)) { | ||
615 | ++result; | 793 | ++result; |
616 | break; | 794 | break; |
617 | } | 795 | } |
@@ -643,8 +821,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
643 | case AUDIT_FILETYPE: | 821 | case AUDIT_FILETYPE: |
644 | result = audit_match_filetype(ctx, f->val); | 822 | result = audit_match_filetype(ctx, f->val); |
645 | break; | 823 | break; |
824 | case AUDIT_FIELD_COMPARE: | ||
825 | result = audit_field_compare(tsk, cred, f, ctx, name); | ||
826 | break; | ||
646 | } | 827 | } |
647 | |||
648 | if (!result) | 828 | if (!result) |
649 | return 0; | 829 | return 0; |
650 | } | 830 | } |
@@ -722,40 +902,53 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, | |||
722 | return AUDIT_BUILD_CONTEXT; | 902 | return AUDIT_BUILD_CONTEXT; |
723 | } | 903 | } |
724 | 904 | ||
725 | /* At syscall exit time, this filter is called if any audit_names[] have been | 905 | /* |
906 | * Given an audit_name check the inode hash table to see if they match. | ||
907 | * Called holding the rcu read lock to protect the use of audit_inode_hash | ||
908 | */ | ||
909 | static int audit_filter_inode_name(struct task_struct *tsk, | ||
910 | struct audit_names *n, | ||
911 | struct audit_context *ctx) { | ||
912 | int word, bit; | ||
913 | int h = audit_hash_ino((u32)n->ino); | ||
914 | struct list_head *list = &audit_inode_hash[h]; | ||
915 | struct audit_entry *e; | ||
916 | enum audit_state state; | ||
917 | |||
918 | word = AUDIT_WORD(ctx->major); | ||
919 | bit = AUDIT_BIT(ctx->major); | ||
920 | |||
921 | if (list_empty(list)) | ||
922 | return 0; | ||
923 | |||
924 | list_for_each_entry_rcu(e, list, list) { | ||
925 | if ((e->rule.mask[word] & bit) == bit && | ||
926 | audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) { | ||
927 | ctx->current_state = state; | ||
928 | return 1; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | /* At syscall exit time, this filter is called if any audit_names have been | ||
726 | * collected during syscall processing. We only check rules in sublists at hash | 936 | * collected during syscall processing. We only check rules in sublists at hash |
727 | * buckets applicable to the inode numbers in audit_names[]. | 937 | * buckets applicable to the inode numbers in audit_names. |
728 | * Regarding audit_state, same rules apply as for audit_filter_syscall(). | 938 | * Regarding audit_state, same rules apply as for audit_filter_syscall(). |
729 | */ | 939 | */ |
730 | void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx) | 940 | void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx) |
731 | { | 941 | { |
732 | int i; | 942 | struct audit_names *n; |
733 | struct audit_entry *e; | ||
734 | enum audit_state state; | ||
735 | 943 | ||
736 | if (audit_pid && tsk->tgid == audit_pid) | 944 | if (audit_pid && tsk->tgid == audit_pid) |
737 | return; | 945 | return; |
738 | 946 | ||
739 | rcu_read_lock(); | 947 | rcu_read_lock(); |
740 | for (i = 0; i < ctx->name_count; i++) { | ||
741 | int word = AUDIT_WORD(ctx->major); | ||
742 | int bit = AUDIT_BIT(ctx->major); | ||
743 | struct audit_names *n = &ctx->names[i]; | ||
744 | int h = audit_hash_ino((u32)n->ino); | ||
745 | struct list_head *list = &audit_inode_hash[h]; | ||
746 | |||
747 | if (list_empty(list)) | ||
748 | continue; | ||
749 | 948 | ||
750 | list_for_each_entry_rcu(e, list, list) { | 949 | list_for_each_entry(n, &ctx->names_list, list) { |
751 | if ((e->rule.mask[word] & bit) == bit && | 950 | if (audit_filter_inode_name(tsk, n, ctx)) |
752 | audit_filter_rules(tsk, &e->rule, ctx, n, | 951 | break; |
753 | &state, false)) { | ||
754 | rcu_read_unlock(); | ||
755 | ctx->current_state = state; | ||
756 | return; | ||
757 | } | ||
758 | } | ||
759 | } | 952 | } |
760 | rcu_read_unlock(); | 953 | rcu_read_unlock(); |
761 | } | 954 | } |
@@ -766,7 +959,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, | |||
766 | { | 959 | { |
767 | struct audit_context *context = tsk->audit_context; | 960 | struct audit_context *context = tsk->audit_context; |
768 | 961 | ||
769 | if (likely(!context)) | 962 | if (!context) |
770 | return NULL; | 963 | return NULL; |
771 | context->return_valid = return_valid; | 964 | context->return_valid = return_valid; |
772 | 965 | ||
@@ -799,7 +992,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, | |||
799 | 992 | ||
800 | static inline void audit_free_names(struct audit_context *context) | 993 | static inline void audit_free_names(struct audit_context *context) |
801 | { | 994 | { |
802 | int i; | 995 | struct audit_names *n, *next; |
803 | 996 | ||
804 | #if AUDIT_DEBUG == 2 | 997 | #if AUDIT_DEBUG == 2 |
805 | if (context->put_count + context->ino_count != context->name_count) { | 998 | if (context->put_count + context->ino_count != context->name_count) { |
@@ -810,10 +1003,9 @@ static inline void audit_free_names(struct audit_context *context) | |||
810 | context->serial, context->major, context->in_syscall, | 1003 | context->serial, context->major, context->in_syscall, |
811 | context->name_count, context->put_count, | 1004 | context->name_count, context->put_count, |
812 | context->ino_count); | 1005 | context->ino_count); |
813 | for (i = 0; i < context->name_count; i++) { | 1006 | list_for_each_entry(n, &context->names_list, list) { |
814 | printk(KERN_ERR "names[%d] = %p = %s\n", i, | 1007 | printk(KERN_ERR "names[%d] = %p = %s\n", i, |
815 | context->names[i].name, | 1008 | n->name, n->name ?: "(null)"); |
816 | context->names[i].name ?: "(null)"); | ||
817 | } | 1009 | } |
818 | dump_stack(); | 1010 | dump_stack(); |
819 | return; | 1011 | return; |
@@ -824,9 +1016,12 @@ static inline void audit_free_names(struct audit_context *context) | |||
824 | context->ino_count = 0; | 1016 | context->ino_count = 0; |
825 | #endif | 1017 | #endif |
826 | 1018 | ||
827 | for (i = 0; i < context->name_count; i++) { | 1019 | list_for_each_entry_safe(n, next, &context->names_list, list) { |
828 | if (context->names[i].name && context->names[i].name_put) | 1020 | list_del(&n->list); |
829 | __putname(context->names[i].name); | 1021 | if (n->name && n->name_put) |
1022 | __putname(n->name); | ||
1023 | if (n->should_free) | ||
1024 | kfree(n); | ||
830 | } | 1025 | } |
831 | context->name_count = 0; | 1026 | context->name_count = 0; |
832 | path_put(&context->pwd); | 1027 | path_put(&context->pwd); |
@@ -864,6 +1059,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) | |||
864 | return NULL; | 1059 | return NULL; |
865 | audit_zero_context(context, state); | 1060 | audit_zero_context(context, state); |
866 | INIT_LIST_HEAD(&context->killed_trees); | 1061 | INIT_LIST_HEAD(&context->killed_trees); |
1062 | INIT_LIST_HEAD(&context->names_list); | ||
867 | return context; | 1063 | return context; |
868 | } | 1064 | } |
869 | 1065 | ||
@@ -886,7 +1082,7 @@ int audit_alloc(struct task_struct *tsk) | |||
886 | return 0; /* Return if not auditing. */ | 1082 | return 0; /* Return if not auditing. */ |
887 | 1083 | ||
888 | state = audit_filter_task(tsk, &key); | 1084 | state = audit_filter_task(tsk, &key); |
889 | if (likely(state == AUDIT_DISABLED)) | 1085 | if (state == AUDIT_DISABLED) |
890 | return 0; | 1086 | return 0; |
891 | 1087 | ||
892 | if (!(context = audit_alloc_context(state))) { | 1088 | if (!(context = audit_alloc_context(state))) { |
@@ -975,7 +1171,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk | |||
975 | while (vma) { | 1171 | while (vma) { |
976 | if ((vma->vm_flags & VM_EXECUTABLE) && | 1172 | if ((vma->vm_flags & VM_EXECUTABLE) && |
977 | vma->vm_file) { | 1173 | vma->vm_file) { |
978 | audit_log_d_path(ab, "exe=", | 1174 | audit_log_d_path(ab, " exe=", |
979 | &vma->vm_file->f_path); | 1175 | &vma->vm_file->f_path); |
980 | break; | 1176 | break; |
981 | } | 1177 | } |
@@ -1166,8 +1362,8 @@ static void audit_log_execve_info(struct audit_context *context, | |||
1166 | struct audit_buffer **ab, | 1362 | struct audit_buffer **ab, |
1167 | struct audit_aux_data_execve *axi) | 1363 | struct audit_aux_data_execve *axi) |
1168 | { | 1364 | { |
1169 | int i; | 1365 | int i, len; |
1170 | size_t len, len_sent = 0; | 1366 | size_t len_sent = 0; |
1171 | const char __user *p; | 1367 | const char __user *p; |
1172 | char *buf; | 1368 | char *buf; |
1173 | 1369 | ||
@@ -1324,6 +1520,68 @@ static void show_special(struct audit_context *context, int *call_panic) | |||
1324 | audit_log_end(ab); | 1520 | audit_log_end(ab); |
1325 | } | 1521 | } |
1326 | 1522 | ||
1523 | static void audit_log_name(struct audit_context *context, struct audit_names *n, | ||
1524 | int record_num, int *call_panic) | ||
1525 | { | ||
1526 | struct audit_buffer *ab; | ||
1527 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | ||
1528 | if (!ab) | ||
1529 | return; /* audit_panic has been called */ | ||
1530 | |||
1531 | audit_log_format(ab, "item=%d", record_num); | ||
1532 | |||
1533 | if (n->name) { | ||
1534 | switch (n->name_len) { | ||
1535 | case AUDIT_NAME_FULL: | ||
1536 | /* log the full path */ | ||
1537 | audit_log_format(ab, " name="); | ||
1538 | audit_log_untrustedstring(ab, n->name); | ||
1539 | break; | ||
1540 | case 0: | ||
1541 | /* name was specified as a relative path and the | ||
1542 | * directory component is the cwd */ | ||
1543 | audit_log_d_path(ab, " name=", &context->pwd); | ||
1544 | break; | ||
1545 | default: | ||
1546 | /* log the name's directory component */ | ||
1547 | audit_log_format(ab, " name="); | ||
1548 | audit_log_n_untrustedstring(ab, n->name, | ||
1549 | n->name_len); | ||
1550 | } | ||
1551 | } else | ||
1552 | audit_log_format(ab, " name=(null)"); | ||
1553 | |||
1554 | if (n->ino != (unsigned long)-1) { | ||
1555 | audit_log_format(ab, " inode=%lu" | ||
1556 | " dev=%02x:%02x mode=%#ho" | ||
1557 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
1558 | n->ino, | ||
1559 | MAJOR(n->dev), | ||
1560 | MINOR(n->dev), | ||
1561 | n->mode, | ||
1562 | n->uid, | ||
1563 | n->gid, | ||
1564 | MAJOR(n->rdev), | ||
1565 | MINOR(n->rdev)); | ||
1566 | } | ||
1567 | if (n->osid != 0) { | ||
1568 | char *ctx = NULL; | ||
1569 | u32 len; | ||
1570 | if (security_secid_to_secctx( | ||
1571 | n->osid, &ctx, &len)) { | ||
1572 | audit_log_format(ab, " osid=%u", n->osid); | ||
1573 | *call_panic = 2; | ||
1574 | } else { | ||
1575 | audit_log_format(ab, " obj=%s", ctx); | ||
1576 | security_release_secctx(ctx, len); | ||
1577 | } | ||
1578 | } | ||
1579 | |||
1580 | audit_log_fcaps(ab, n); | ||
1581 | |||
1582 | audit_log_end(ab); | ||
1583 | } | ||
1584 | |||
1327 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) | 1585 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) |
1328 | { | 1586 | { |
1329 | const struct cred *cred; | 1587 | const struct cred *cred; |
@@ -1331,6 +1589,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1331 | struct audit_buffer *ab; | 1589 | struct audit_buffer *ab; |
1332 | struct audit_aux_data *aux; | 1590 | struct audit_aux_data *aux; |
1333 | const char *tty; | 1591 | const char *tty; |
1592 | struct audit_names *n; | ||
1334 | 1593 | ||
1335 | /* tsk == current */ | 1594 | /* tsk == current */ |
1336 | context->pid = tsk->pid; | 1595 | context->pid = tsk->pid; |
@@ -1466,70 +1725,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1466 | if (context->pwd.dentry && context->pwd.mnt) { | 1725 | if (context->pwd.dentry && context->pwd.mnt) { |
1467 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); | 1726 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); |
1468 | if (ab) { | 1727 | if (ab) { |
1469 | audit_log_d_path(ab, "cwd=", &context->pwd); | 1728 | audit_log_d_path(ab, " cwd=", &context->pwd); |
1470 | audit_log_end(ab); | 1729 | audit_log_end(ab); |
1471 | } | 1730 | } |
1472 | } | 1731 | } |
1473 | for (i = 0; i < context->name_count; i++) { | ||
1474 | struct audit_names *n = &context->names[i]; | ||
1475 | 1732 | ||
1476 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | 1733 | i = 0; |
1477 | if (!ab) | 1734 | list_for_each_entry(n, &context->names_list, list) |
1478 | continue; /* audit_panic has been called */ | 1735 | audit_log_name(context, n, i++, &call_panic); |
1479 | |||
1480 | audit_log_format(ab, "item=%d", i); | ||
1481 | |||
1482 | if (n->name) { | ||
1483 | switch(n->name_len) { | ||
1484 | case AUDIT_NAME_FULL: | ||
1485 | /* log the full path */ | ||
1486 | audit_log_format(ab, " name="); | ||
1487 | audit_log_untrustedstring(ab, n->name); | ||
1488 | break; | ||
1489 | case 0: | ||
1490 | /* name was specified as a relative path and the | ||
1491 | * directory component is the cwd */ | ||
1492 | audit_log_d_path(ab, "name=", &context->pwd); | ||
1493 | break; | ||
1494 | default: | ||
1495 | /* log the name's directory component */ | ||
1496 | audit_log_format(ab, " name="); | ||
1497 | audit_log_n_untrustedstring(ab, n->name, | ||
1498 | n->name_len); | ||
1499 | } | ||
1500 | } else | ||
1501 | audit_log_format(ab, " name=(null)"); | ||
1502 | |||
1503 | if (n->ino != (unsigned long)-1) { | ||
1504 | audit_log_format(ab, " inode=%lu" | ||
1505 | " dev=%02x:%02x mode=%#ho" | ||
1506 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
1507 | n->ino, | ||
1508 | MAJOR(n->dev), | ||
1509 | MINOR(n->dev), | ||
1510 | n->mode, | ||
1511 | n->uid, | ||
1512 | n->gid, | ||
1513 | MAJOR(n->rdev), | ||
1514 | MINOR(n->rdev)); | ||
1515 | } | ||
1516 | if (n->osid != 0) { | ||
1517 | char *ctx = NULL; | ||
1518 | u32 len; | ||
1519 | if (security_secid_to_secctx( | ||
1520 | n->osid, &ctx, &len)) { | ||
1521 | audit_log_format(ab, " osid=%u", n->osid); | ||
1522 | call_panic = 2; | ||
1523 | } else { | ||
1524 | audit_log_format(ab, " obj=%s", ctx); | ||
1525 | security_release_secctx(ctx, len); | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | audit_log_fcaps(ab, n); | ||
1530 | |||
1531 | audit_log_end(ab); | ||
1532 | } | ||
1533 | 1736 | ||
1534 | /* Send end of event record to help user space know we are finished */ | 1737 | /* Send end of event record to help user space know we are finished */ |
1535 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); | 1738 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); |
@@ -1545,12 +1748,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1545 | * | 1748 | * |
1546 | * Called from copy_process and do_exit | 1749 | * Called from copy_process and do_exit |
1547 | */ | 1750 | */ |
1548 | void audit_free(struct task_struct *tsk) | 1751 | void __audit_free(struct task_struct *tsk) |
1549 | { | 1752 | { |
1550 | struct audit_context *context; | 1753 | struct audit_context *context; |
1551 | 1754 | ||
1552 | context = audit_get_context(tsk, 0, 0); | 1755 | context = audit_get_context(tsk, 0, 0); |
1553 | if (likely(!context)) | 1756 | if (!context) |
1554 | return; | 1757 | return; |
1555 | 1758 | ||
1556 | /* Check for system calls that do not go through the exit | 1759 | /* Check for system calls that do not go through the exit |
@@ -1583,7 +1786,7 @@ void audit_free(struct task_struct *tsk) | |||
1583 | * will only be written if another part of the kernel requests that it | 1786 | * will only be written if another part of the kernel requests that it |
1584 | * be written). | 1787 | * be written). |
1585 | */ | 1788 | */ |
1586 | void audit_syscall_entry(int arch, int major, | 1789 | void __audit_syscall_entry(int arch, int major, |
1587 | unsigned long a1, unsigned long a2, | 1790 | unsigned long a1, unsigned long a2, |
1588 | unsigned long a3, unsigned long a4) | 1791 | unsigned long a3, unsigned long a4) |
1589 | { | 1792 | { |
@@ -1591,7 +1794,7 @@ void audit_syscall_entry(int arch, int major, | |||
1591 | struct audit_context *context = tsk->audit_context; | 1794 | struct audit_context *context = tsk->audit_context; |
1592 | enum audit_state state; | 1795 | enum audit_state state; |
1593 | 1796 | ||
1594 | if (unlikely(!context)) | 1797 | if (!context) |
1595 | return; | 1798 | return; |
1596 | 1799 | ||
1597 | /* | 1800 | /* |
@@ -1648,7 +1851,7 @@ void audit_syscall_entry(int arch, int major, | |||
1648 | context->prio = 0; | 1851 | context->prio = 0; |
1649 | state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); | 1852 | state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); |
1650 | } | 1853 | } |
1651 | if (likely(state == AUDIT_DISABLED)) | 1854 | if (state == AUDIT_DISABLED) |
1652 | return; | 1855 | return; |
1653 | 1856 | ||
1654 | context->serial = 0; | 1857 | context->serial = 0; |
@@ -1658,30 +1861,9 @@ void audit_syscall_entry(int arch, int major, | |||
1658 | context->ppid = 0; | 1861 | context->ppid = 0; |
1659 | } | 1862 | } |
1660 | 1863 | ||
1661 | void audit_finish_fork(struct task_struct *child) | ||
1662 | { | ||
1663 | struct audit_context *ctx = current->audit_context; | ||
1664 | struct audit_context *p = child->audit_context; | ||
1665 | if (!p || !ctx) | ||
1666 | return; | ||
1667 | if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT) | ||
1668 | return; | ||
1669 | p->arch = ctx->arch; | ||
1670 | p->major = ctx->major; | ||
1671 | memcpy(p->argv, ctx->argv, sizeof(ctx->argv)); | ||
1672 | p->ctime = ctx->ctime; | ||
1673 | p->dummy = ctx->dummy; | ||
1674 | p->in_syscall = ctx->in_syscall; | ||
1675 | p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL); | ||
1676 | p->ppid = current->pid; | ||
1677 | p->prio = ctx->prio; | ||
1678 | p->current_state = ctx->current_state; | ||
1679 | } | ||
1680 | |||
1681 | /** | 1864 | /** |
1682 | * audit_syscall_exit - deallocate audit context after a system call | 1865 | * audit_syscall_exit - deallocate audit context after a system call |
1683 | * @valid: success/failure flag | 1866 | * @pt_regs: syscall registers |
1684 | * @return_code: syscall return value | ||
1685 | * | 1867 | * |
1686 | * Tear down after system call. If the audit context has been marked as | 1868 | * Tear down after system call. If the audit context has been marked as |
1687 | * auditable (either because of the AUDIT_RECORD_CONTEXT state from | 1869 | * auditable (either because of the AUDIT_RECORD_CONTEXT state from |
@@ -1689,14 +1871,18 @@ void audit_finish_fork(struct task_struct *child) | |||
1689 | * message), then write out the syscall information. In call cases, | 1871 | * message), then write out the syscall information. In call cases, |
1690 | * free the names stored from getname(). | 1872 | * free the names stored from getname(). |
1691 | */ | 1873 | */ |
1692 | void audit_syscall_exit(int valid, long return_code) | 1874 | void __audit_syscall_exit(int success, long return_code) |
1693 | { | 1875 | { |
1694 | struct task_struct *tsk = current; | 1876 | struct task_struct *tsk = current; |
1695 | struct audit_context *context; | 1877 | struct audit_context *context; |
1696 | 1878 | ||
1697 | context = audit_get_context(tsk, valid, return_code); | 1879 | if (success) |
1880 | success = AUDITSC_SUCCESS; | ||
1881 | else | ||
1882 | success = AUDITSC_FAILURE; | ||
1698 | 1883 | ||
1699 | if (likely(!context)) | 1884 | context = audit_get_context(tsk, success, return_code); |
1885 | if (!context) | ||
1700 | return; | 1886 | return; |
1701 | 1887 | ||
1702 | if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT) | 1888 | if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT) |
@@ -1821,6 +2007,30 @@ retry: | |||
1821 | #endif | 2007 | #endif |
1822 | } | 2008 | } |
1823 | 2009 | ||
2010 | static struct audit_names *audit_alloc_name(struct audit_context *context) | ||
2011 | { | ||
2012 | struct audit_names *aname; | ||
2013 | |||
2014 | if (context->name_count < AUDIT_NAMES) { | ||
2015 | aname = &context->preallocated_names[context->name_count]; | ||
2016 | memset(aname, 0, sizeof(*aname)); | ||
2017 | } else { | ||
2018 | aname = kzalloc(sizeof(*aname), GFP_NOFS); | ||
2019 | if (!aname) | ||
2020 | return NULL; | ||
2021 | aname->should_free = true; | ||
2022 | } | ||
2023 | |||
2024 | aname->ino = (unsigned long)-1; | ||
2025 | list_add_tail(&aname->list, &context->names_list); | ||
2026 | |||
2027 | context->name_count++; | ||
2028 | #if AUDIT_DEBUG | ||
2029 | context->ino_count++; | ||
2030 | #endif | ||
2031 | return aname; | ||
2032 | } | ||
2033 | |||
1824 | /** | 2034 | /** |
1825 | * audit_getname - add a name to the list | 2035 | * audit_getname - add a name to the list |
1826 | * @name: name to add | 2036 | * @name: name to add |
@@ -1831,9 +2041,7 @@ retry: | |||
1831 | void __audit_getname(const char *name) | 2041 | void __audit_getname(const char *name) |
1832 | { | 2042 | { |
1833 | struct audit_context *context = current->audit_context; | 2043 | struct audit_context *context = current->audit_context; |
1834 | 2044 | struct audit_names *n; | |
1835 | if (IS_ERR(name) || !name) | ||
1836 | return; | ||
1837 | 2045 | ||
1838 | if (!context->in_syscall) { | 2046 | if (!context->in_syscall) { |
1839 | #if AUDIT_DEBUG == 2 | 2047 | #if AUDIT_DEBUG == 2 |
@@ -1843,13 +2051,15 @@ void __audit_getname(const char *name) | |||
1843 | #endif | 2051 | #endif |
1844 | return; | 2052 | return; |
1845 | } | 2053 | } |
1846 | BUG_ON(context->name_count >= AUDIT_NAMES); | 2054 | |
1847 | context->names[context->name_count].name = name; | 2055 | n = audit_alloc_name(context); |
1848 | context->names[context->name_count].name_len = AUDIT_NAME_FULL; | 2056 | if (!n) |
1849 | context->names[context->name_count].name_put = 1; | 2057 | return; |
1850 | context->names[context->name_count].ino = (unsigned long)-1; | 2058 | |
1851 | context->names[context->name_count].osid = 0; | 2059 | n->name = name; |
1852 | ++context->name_count; | 2060 | n->name_len = AUDIT_NAME_FULL; |
2061 | n->name_put = true; | ||
2062 | |||
1853 | if (!context->pwd.dentry) | 2063 | if (!context->pwd.dentry) |
1854 | get_fs_pwd(current->fs, &context->pwd); | 2064 | get_fs_pwd(current->fs, &context->pwd); |
1855 | } | 2065 | } |
@@ -1871,12 +2081,13 @@ void audit_putname(const char *name) | |||
1871 | printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", | 2081 | printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", |
1872 | __FILE__, __LINE__, context->serial, name); | 2082 | __FILE__, __LINE__, context->serial, name); |
1873 | if (context->name_count) { | 2083 | if (context->name_count) { |
2084 | struct audit_names *n; | ||
1874 | int i; | 2085 | int i; |
1875 | for (i = 0; i < context->name_count; i++) | 2086 | |
2087 | list_for_each_entry(n, &context->names_list, list) | ||
1876 | printk(KERN_ERR "name[%d] = %p = %s\n", i, | 2088 | printk(KERN_ERR "name[%d] = %p = %s\n", i, |
1877 | context->names[i].name, | 2089 | n->name, n->name ?: "(null)"); |
1878 | context->names[i].name ?: "(null)"); | 2090 | } |
1879 | } | ||
1880 | #endif | 2091 | #endif |
1881 | __putname(name); | 2092 | __putname(name); |
1882 | } | 2093 | } |
@@ -1897,39 +2108,11 @@ void audit_putname(const char *name) | |||
1897 | #endif | 2108 | #endif |
1898 | } | 2109 | } |
1899 | 2110 | ||
1900 | static int audit_inc_name_count(struct audit_context *context, | ||
1901 | const struct inode *inode) | ||
1902 | { | ||
1903 | if (context->name_count >= AUDIT_NAMES) { | ||
1904 | if (inode) | ||
1905 | printk(KERN_DEBUG "audit: name_count maxed, losing inode data: " | ||
1906 | "dev=%02x:%02x, inode=%lu\n", | ||
1907 | MAJOR(inode->i_sb->s_dev), | ||
1908 | MINOR(inode->i_sb->s_dev), | ||
1909 | inode->i_ino); | ||
1910 | |||
1911 | else | ||
1912 | printk(KERN_DEBUG "name_count maxed, losing inode data\n"); | ||
1913 | return 1; | ||
1914 | } | ||
1915 | context->name_count++; | ||
1916 | #if AUDIT_DEBUG | ||
1917 | context->ino_count++; | ||
1918 | #endif | ||
1919 | return 0; | ||
1920 | } | ||
1921 | |||
1922 | |||
1923 | static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) | 2111 | static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) |
1924 | { | 2112 | { |
1925 | struct cpu_vfs_cap_data caps; | 2113 | struct cpu_vfs_cap_data caps; |
1926 | int rc; | 2114 | int rc; |
1927 | 2115 | ||
1928 | memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t)); | ||
1929 | memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t)); | ||
1930 | name->fcap.fE = 0; | ||
1931 | name->fcap_ver = 0; | ||
1932 | |||
1933 | if (!dentry) | 2116 | if (!dentry) |
1934 | return 0; | 2117 | return 0; |
1935 | 2118 | ||
@@ -1969,30 +2152,25 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent | |||
1969 | */ | 2152 | */ |
1970 | void __audit_inode(const char *name, const struct dentry *dentry) | 2153 | void __audit_inode(const char *name, const struct dentry *dentry) |
1971 | { | 2154 | { |
1972 | int idx; | ||
1973 | struct audit_context *context = current->audit_context; | 2155 | struct audit_context *context = current->audit_context; |
1974 | const struct inode *inode = dentry->d_inode; | 2156 | const struct inode *inode = dentry->d_inode; |
2157 | struct audit_names *n; | ||
1975 | 2158 | ||
1976 | if (!context->in_syscall) | 2159 | if (!context->in_syscall) |
1977 | return; | 2160 | return; |
1978 | if (context->name_count | 2161 | |
1979 | && context->names[context->name_count-1].name | 2162 | list_for_each_entry_reverse(n, &context->names_list, list) { |
1980 | && context->names[context->name_count-1].name == name) | 2163 | if (n->name && (n->name == name)) |
1981 | idx = context->name_count - 1; | 2164 | goto out; |
1982 | else if (context->name_count > 1 | ||
1983 | && context->names[context->name_count-2].name | ||
1984 | && context->names[context->name_count-2].name == name) | ||
1985 | idx = context->name_count - 2; | ||
1986 | else { | ||
1987 | /* FIXME: how much do we care about inodes that have no | ||
1988 | * associated name? */ | ||
1989 | if (audit_inc_name_count(context, inode)) | ||
1990 | return; | ||
1991 | idx = context->name_count - 1; | ||
1992 | context->names[idx].name = NULL; | ||
1993 | } | 2165 | } |
2166 | |||
2167 | /* unable to find the name from a previous getname() */ | ||
2168 | n = audit_alloc_name(context); | ||
2169 | if (!n) | ||
2170 | return; | ||
2171 | out: | ||
1994 | handle_path(dentry); | 2172 | handle_path(dentry); |
1995 | audit_copy_inode(&context->names[idx], dentry, inode); | 2173 | audit_copy_inode(n, dentry, inode); |
1996 | } | 2174 | } |
1997 | 2175 | ||
1998 | /** | 2176 | /** |
@@ -2011,11 +2189,11 @@ void __audit_inode(const char *name, const struct dentry *dentry) | |||
2011 | void __audit_inode_child(const struct dentry *dentry, | 2189 | void __audit_inode_child(const struct dentry *dentry, |
2012 | const struct inode *parent) | 2190 | const struct inode *parent) |
2013 | { | 2191 | { |
2014 | int idx; | ||
2015 | struct audit_context *context = current->audit_context; | 2192 | struct audit_context *context = current->audit_context; |
2016 | const char *found_parent = NULL, *found_child = NULL; | 2193 | const char *found_parent = NULL, *found_child = NULL; |
2017 | const struct inode *inode = dentry->d_inode; | 2194 | const struct inode *inode = dentry->d_inode; |
2018 | const char *dname = dentry->d_name.name; | 2195 | const char *dname = dentry->d_name.name; |
2196 | struct audit_names *n; | ||
2019 | int dirlen = 0; | 2197 | int dirlen = 0; |
2020 | 2198 | ||
2021 | if (!context->in_syscall) | 2199 | if (!context->in_syscall) |
@@ -2025,9 +2203,7 @@ void __audit_inode_child(const struct dentry *dentry, | |||
2025 | handle_one(inode); | 2203 | handle_one(inode); |
2026 | 2204 | ||
2027 | /* parent is more likely, look for it first */ | 2205 | /* parent is more likely, look for it first */ |
2028 | for (idx = 0; idx < context->name_count; idx++) { | 2206 | list_for_each_entry(n, &context->names_list, list) { |
2029 | struct audit_names *n = &context->names[idx]; | ||
2030 | |||
2031 | if (!n->name) | 2207 | if (!n->name) |
2032 | continue; | 2208 | continue; |
2033 | 2209 | ||
@@ -2040,9 +2216,7 @@ void __audit_inode_child(const struct dentry *dentry, | |||
2040 | } | 2216 | } |
2041 | 2217 | ||
2042 | /* no matching parent, look for matching child */ | 2218 | /* no matching parent, look for matching child */ |
2043 | for (idx = 0; idx < context->name_count; idx++) { | 2219 | list_for_each_entry(n, &context->names_list, list) { |
2044 | struct audit_names *n = &context->names[idx]; | ||
2045 | |||
2046 | if (!n->name) | 2220 | if (!n->name) |
2047 | continue; | 2221 | continue; |
2048 | 2222 | ||
@@ -2060,34 +2234,29 @@ void __audit_inode_child(const struct dentry *dentry, | |||
2060 | 2234 | ||
2061 | add_names: | 2235 | add_names: |
2062 | if (!found_parent) { | 2236 | if (!found_parent) { |
2063 | if (audit_inc_name_count(context, parent)) | 2237 | n = audit_alloc_name(context); |
2238 | if (!n) | ||
2064 | return; | 2239 | return; |
2065 | idx = context->name_count - 1; | 2240 | audit_copy_inode(n, NULL, parent); |
2066 | context->names[idx].name = NULL; | ||
2067 | audit_copy_inode(&context->names[idx], NULL, parent); | ||
2068 | } | 2241 | } |
2069 | 2242 | ||
2070 | if (!found_child) { | 2243 | if (!found_child) { |
2071 | if (audit_inc_name_count(context, inode)) | 2244 | n = audit_alloc_name(context); |
2245 | if (!n) | ||
2072 | return; | 2246 | return; |
2073 | idx = context->name_count - 1; | ||
2074 | 2247 | ||
2075 | /* Re-use the name belonging to the slot for a matching parent | 2248 | /* Re-use the name belonging to the slot for a matching parent |
2076 | * directory. All names for this context are relinquished in | 2249 | * directory. All names for this context are relinquished in |
2077 | * audit_free_names() */ | 2250 | * audit_free_names() */ |
2078 | if (found_parent) { | 2251 | if (found_parent) { |
2079 | context->names[idx].name = found_parent; | 2252 | n->name = found_parent; |
2080 | context->names[idx].name_len = AUDIT_NAME_FULL; | 2253 | n->name_len = AUDIT_NAME_FULL; |
2081 | /* don't call __putname() */ | 2254 | /* don't call __putname() */ |
2082 | context->names[idx].name_put = 0; | 2255 | n->name_put = false; |
2083 | } else { | ||
2084 | context->names[idx].name = NULL; | ||
2085 | } | 2256 | } |
2086 | 2257 | ||
2087 | if (inode) | 2258 | if (inode) |
2088 | audit_copy_inode(&context->names[idx], NULL, inode); | 2259 | audit_copy_inode(n, NULL, inode); |
2089 | else | ||
2090 | context->names[idx].ino = (unsigned long)-1; | ||
2091 | } | 2260 | } |
2092 | } | 2261 | } |
2093 | EXPORT_SYMBOL_GPL(__audit_inode_child); | 2262 | EXPORT_SYMBOL_GPL(__audit_inode_child); |
@@ -2121,19 +2290,28 @@ int auditsc_get_stamp(struct audit_context *ctx, | |||
2121 | static atomic_t session_id = ATOMIC_INIT(0); | 2290 | static atomic_t session_id = ATOMIC_INIT(0); |
2122 | 2291 | ||
2123 | /** | 2292 | /** |
2124 | * audit_set_loginuid - set a task's audit_context loginuid | 2293 | * audit_set_loginuid - set current task's audit_context loginuid |
2125 | * @task: task whose audit context is being modified | ||
2126 | * @loginuid: loginuid value | 2294 | * @loginuid: loginuid value |
2127 | * | 2295 | * |
2128 | * Returns 0. | 2296 | * Returns 0. |
2129 | * | 2297 | * |
2130 | * Called (set) from fs/proc/base.c::proc_loginuid_write(). | 2298 | * Called (set) from fs/proc/base.c::proc_loginuid_write(). |
2131 | */ | 2299 | */ |
2132 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) | 2300 | int audit_set_loginuid(uid_t loginuid) |
2133 | { | 2301 | { |
2134 | unsigned int sessionid = atomic_inc_return(&session_id); | 2302 | struct task_struct *task = current; |
2135 | struct audit_context *context = task->audit_context; | 2303 | struct audit_context *context = task->audit_context; |
2304 | unsigned int sessionid; | ||
2305 | |||
2306 | #ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE | ||
2307 | if (task->loginuid != -1) | ||
2308 | return -EPERM; | ||
2309 | #else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */ | ||
2310 | if (!capable(CAP_AUDIT_CONTROL)) | ||
2311 | return -EPERM; | ||
2312 | #endif /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */ | ||
2136 | 2313 | ||
2314 | sessionid = atomic_inc_return(&session_id); | ||
2137 | if (context && context->in_syscall) { | 2315 | if (context && context->in_syscall) { |
2138 | struct audit_buffer *ab; | 2316 | struct audit_buffer *ab; |
2139 | 2317 | ||
@@ -2271,14 +2449,11 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mo | |||
2271 | context->ipc.has_perm = 1; | 2449 | context->ipc.has_perm = 1; |
2272 | } | 2450 | } |
2273 | 2451 | ||
2274 | int audit_bprm(struct linux_binprm *bprm) | 2452 | int __audit_bprm(struct linux_binprm *bprm) |
2275 | { | 2453 | { |
2276 | struct audit_aux_data_execve *ax; | 2454 | struct audit_aux_data_execve *ax; |
2277 | struct audit_context *context = current->audit_context; | 2455 | struct audit_context *context = current->audit_context; |
2278 | 2456 | ||
2279 | if (likely(!audit_enabled || !context || context->dummy)) | ||
2280 | return 0; | ||
2281 | |||
2282 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); | 2457 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); |
2283 | if (!ax) | 2458 | if (!ax) |
2284 | return -ENOMEM; | 2459 | return -ENOMEM; |
@@ -2299,13 +2474,10 @@ int audit_bprm(struct linux_binprm *bprm) | |||
2299 | * @args: args array | 2474 | * @args: args array |
2300 | * | 2475 | * |
2301 | */ | 2476 | */ |
2302 | void audit_socketcall(int nargs, unsigned long *args) | 2477 | void __audit_socketcall(int nargs, unsigned long *args) |
2303 | { | 2478 | { |
2304 | struct audit_context *context = current->audit_context; | 2479 | struct audit_context *context = current->audit_context; |
2305 | 2480 | ||
2306 | if (likely(!context || context->dummy)) | ||
2307 | return; | ||
2308 | |||
2309 | context->type = AUDIT_SOCKETCALL; | 2481 | context->type = AUDIT_SOCKETCALL; |
2310 | context->socketcall.nargs = nargs; | 2482 | context->socketcall.nargs = nargs; |
2311 | memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long)); | 2483 | memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long)); |
@@ -2331,13 +2503,10 @@ void __audit_fd_pair(int fd1, int fd2) | |||
2331 | * | 2503 | * |
2332 | * Returns 0 for success or NULL context or < 0 on error. | 2504 | * Returns 0 for success or NULL context or < 0 on error. |
2333 | */ | 2505 | */ |
2334 | int audit_sockaddr(int len, void *a) | 2506 | int __audit_sockaddr(int len, void *a) |
2335 | { | 2507 | { |
2336 | struct audit_context *context = current->audit_context; | 2508 | struct audit_context *context = current->audit_context; |
2337 | 2509 | ||
2338 | if (likely(!context || context->dummy)) | ||
2339 | return 0; | ||
2340 | |||
2341 | if (!context->sockaddr) { | 2510 | if (!context->sockaddr) { |
2342 | void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL); | 2511 | void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL); |
2343 | if (!p) | 2512 | if (!p) |
@@ -2499,6 +2668,25 @@ void __audit_mmap_fd(int fd, int flags) | |||
2499 | context->type = AUDIT_MMAP; | 2668 | context->type = AUDIT_MMAP; |
2500 | } | 2669 | } |
2501 | 2670 | ||
2671 | static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr) | ||
2672 | { | ||
2673 | uid_t auid, uid; | ||
2674 | gid_t gid; | ||
2675 | unsigned int sessionid; | ||
2676 | |||
2677 | auid = audit_get_loginuid(current); | ||
2678 | sessionid = audit_get_sessionid(current); | ||
2679 | current_uid_gid(&uid, &gid); | ||
2680 | |||
2681 | audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u", | ||
2682 | auid, uid, gid, sessionid); | ||
2683 | audit_log_task_context(ab); | ||
2684 | audit_log_format(ab, " pid=%d comm=", current->pid); | ||
2685 | audit_log_untrustedstring(ab, current->comm); | ||
2686 | audit_log_format(ab, " reason="); | ||
2687 | audit_log_string(ab, reason); | ||
2688 | audit_log_format(ab, " sig=%ld", signr); | ||
2689 | } | ||
2502 | /** | 2690 | /** |
2503 | * audit_core_dumps - record information about processes that end abnormally | 2691 | * audit_core_dumps - record information about processes that end abnormally |
2504 | * @signr: signal value | 2692 | * @signr: signal value |
@@ -2509,10 +2697,6 @@ void __audit_mmap_fd(int fd, int flags) | |||
2509 | void audit_core_dumps(long signr) | 2697 | void audit_core_dumps(long signr) |
2510 | { | 2698 | { |
2511 | struct audit_buffer *ab; | 2699 | struct audit_buffer *ab; |
2512 | u32 sid; | ||
2513 | uid_t auid = audit_get_loginuid(current), uid; | ||
2514 | gid_t gid; | ||
2515 | unsigned int sessionid = audit_get_sessionid(current); | ||
2516 | 2700 | ||
2517 | if (!audit_enabled) | 2701 | if (!audit_enabled) |
2518 | return; | 2702 | return; |
@@ -2521,24 +2705,17 @@ void audit_core_dumps(long signr) | |||
2521 | return; | 2705 | return; |
2522 | 2706 | ||
2523 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); | 2707 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); |
2524 | current_uid_gid(&uid, &gid); | 2708 | audit_log_abend(ab, "memory violation", signr); |
2525 | audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u", | 2709 | audit_log_end(ab); |
2526 | auid, uid, gid, sessionid); | 2710 | } |
2527 | security_task_getsecid(current, &sid); | ||
2528 | if (sid) { | ||
2529 | char *ctx = NULL; | ||
2530 | u32 len; | ||
2531 | 2711 | ||
2532 | if (security_secid_to_secctx(sid, &ctx, &len)) | 2712 | void __audit_seccomp(unsigned long syscall) |
2533 | audit_log_format(ab, " ssid=%u", sid); | 2713 | { |
2534 | else { | 2714 | struct audit_buffer *ab; |
2535 | audit_log_format(ab, " subj=%s", ctx); | 2715 | |
2536 | security_release_secctx(ctx, len); | 2716 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); |
2537 | } | 2717 | audit_log_abend(ab, "seccomp", SIGKILL); |
2538 | } | 2718 | audit_log_format(ab, " syscall=%ld", syscall); |
2539 | audit_log_format(ab, " pid=%d comm=", current->pid); | ||
2540 | audit_log_untrustedstring(ab, current->comm); | ||
2541 | audit_log_format(ab, " sig=%ld", signr); | ||
2542 | audit_log_end(ab); | 2719 | audit_log_end(ab); |
2543 | } | 2720 | } |
2544 | 2721 | ||
diff --git a/kernel/exit.c b/kernel/exit.c index c44738267be7..294b1709170d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -964,8 +964,7 @@ void do_exit(long code) | |||
964 | acct_collect(code, group_dead); | 964 | acct_collect(code, group_dead); |
965 | if (group_dead) | 965 | if (group_dead) |
966 | tty_audit_exit(); | 966 | tty_audit_exit(); |
967 | if (unlikely(tsk->audit_context)) | 967 | audit_free(tsk); |
968 | audit_free(tsk); | ||
969 | 968 | ||
970 | tsk->exit_code = code; | 969 | tsk->exit_code = code; |
971 | taskstats_exit(tsk, group_dead); | 970 | taskstats_exit(tsk, group_dead); |
diff --git a/kernel/fork.c b/kernel/fork.c index f3fa18887cc9..051f090d40c1 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1527,8 +1527,6 @@ long do_fork(unsigned long clone_flags, | |||
1527 | init_completion(&vfork); | 1527 | init_completion(&vfork); |
1528 | } | 1528 | } |
1529 | 1529 | ||
1530 | audit_finish_fork(p); | ||
1531 | |||
1532 | /* | 1530 | /* |
1533 | * We set PF_STARTING at creation in case tracing wants to | 1531 | * We set PF_STARTING at creation in case tracing wants to |
1534 | * use this to distinguish a fully live task from one that | 1532 | * use this to distinguish a fully live task from one that |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 57d4b13b631d..e8d76c5895ea 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * This defines a simple but solid secure-computing mode. | 6 | * This defines a simple but solid secure-computing mode. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/audit.h> | ||
9 | #include <linux/seccomp.h> | 10 | #include <linux/seccomp.h> |
10 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
11 | #include <linux/compat.h> | 12 | #include <linux/compat.h> |
@@ -54,6 +55,7 @@ void __secure_computing(int this_syscall) | |||
54 | #ifdef SECCOMP_DEBUG | 55 | #ifdef SECCOMP_DEBUG |
55 | dump_stack(); | 56 | dump_stack(); |
56 | #endif | 57 | #endif |
58 | audit_seccomp(this_syscall); | ||
57 | do_exit(SIGKILL); | 59 | do_exit(SIGKILL); |
58 | } | 60 | } |
59 | 61 | ||
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index c5c5a72c30be..2ad942fb1e23 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c | |||
@@ -56,9 +56,11 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
56 | audit_log_format(ab, " name="); | 56 | audit_log_format(ab, " name="); |
57 | audit_log_untrustedstring(ab, fname); | 57 | audit_log_untrustedstring(ab, fname); |
58 | } | 58 | } |
59 | if (inode) | 59 | if (inode) { |
60 | audit_log_format(ab, " dev=%s ino=%lu", | 60 | audit_log_format(ab, " dev="); |
61 | inode->i_sb->s_id, inode->i_ino); | 61 | audit_log_untrustedstring(ab, inode->i_sb->s_id); |
62 | audit_log_format(ab, " ino=%lu", inode->i_ino); | ||
63 | } | ||
62 | audit_log_format(ab, " res=%d", !result ? 0 : 1); | 64 | audit_log_format(ab, " res=%d", !result ? 0 : 1); |
63 | audit_log_end(ab); | 65 | audit_log_end(ab); |
64 | } | 66 | } |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 7bd6f138236b..293b8c45b1d1 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
@@ -232,13 +232,14 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
232 | case LSM_AUDIT_DATA_PATH: { | 232 | case LSM_AUDIT_DATA_PATH: { |
233 | struct inode *inode; | 233 | struct inode *inode; |
234 | 234 | ||
235 | audit_log_d_path(ab, "path=", &a->u.path); | 235 | audit_log_d_path(ab, " path=", &a->u.path); |
236 | 236 | ||
237 | inode = a->u.path.dentry->d_inode; | 237 | inode = a->u.path.dentry->d_inode; |
238 | if (inode) | 238 | if (inode) { |
239 | audit_log_format(ab, " dev=%s ino=%lu", | 239 | audit_log_format(ab, " dev="); |
240 | inode->i_sb->s_id, | 240 | audit_log_untrustedstring(ab, inode->i_sb->s_id); |
241 | inode->i_ino); | 241 | audit_log_format(ab, " ino=%lu", inode->i_ino); |
242 | } | ||
242 | break; | 243 | break; |
243 | } | 244 | } |
244 | case LSM_AUDIT_DATA_DENTRY: { | 245 | case LSM_AUDIT_DATA_DENTRY: { |
@@ -248,10 +249,11 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
248 | audit_log_untrustedstring(ab, a->u.dentry->d_name.name); | 249 | audit_log_untrustedstring(ab, a->u.dentry->d_name.name); |
249 | 250 | ||
250 | inode = a->u.dentry->d_inode; | 251 | inode = a->u.dentry->d_inode; |
251 | if (inode) | 252 | if (inode) { |
252 | audit_log_format(ab, " dev=%s ino=%lu", | 253 | audit_log_format(ab, " dev="); |
253 | inode->i_sb->s_id, | 254 | audit_log_untrustedstring(ab, inode->i_sb->s_id); |
254 | inode->i_ino); | 255 | audit_log_format(ab, " ino=%lu", inode->i_ino); |
256 | } | ||
255 | break; | 257 | break; |
256 | } | 258 | } |
257 | case LSM_AUDIT_DATA_INODE: { | 259 | case LSM_AUDIT_DATA_INODE: { |
@@ -266,8 +268,9 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
266 | dentry->d_name.name); | 268 | dentry->d_name.name); |
267 | dput(dentry); | 269 | dput(dentry); |
268 | } | 270 | } |
269 | audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id, | 271 | audit_log_format(ab, " dev="); |
270 | inode->i_ino); | 272 | audit_log_untrustedstring(ab, inode->i_sb->s_id); |
273 | audit_log_format(ab, " ino=%lu", inode->i_ino); | ||
271 | break; | 274 | break; |
272 | } | 275 | } |
273 | case LSM_AUDIT_DATA_TASK: | 276 | case LSM_AUDIT_DATA_TASK: |
@@ -315,7 +318,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
315 | .dentry = u->dentry, | 318 | .dentry = u->dentry, |
316 | .mnt = u->mnt | 319 | .mnt = u->mnt |
317 | }; | 320 | }; |
318 | audit_log_d_path(ab, "path=", &path); | 321 | audit_log_d_path(ab, " path=", &path); |
319 | break; | 322 | break; |
320 | } | 323 | } |
321 | if (!u->addr) | 324 | if (!u->addr) |