diff options
-rw-r--r-- | arch/ppc/Kconfig | 17 | ||||
-rw-r--r-- | arch/ppc/kernel/entry.S | 16 | ||||
-rw-r--r-- | arch/ppc/kernel/ppc_ksyms.c | 2 | ||||
-rw-r--r-- | arch/ppc/kernel/ptrace.c | 40 | ||||
-rw-r--r-- | include/asm-ppc/seccomp.h | 10 | ||||
-rw-r--r-- | include/asm-ppc/thread_info.h | 7 | ||||
-rw-r--r-- | include/linux/audit.h | 81 | ||||
-rw-r--r-- | init/Kconfig | 3 | ||||
-rw-r--r-- | kernel/audit.c | 334 | ||||
-rw-r--r-- | kernel/auditsc.c | 65 | ||||
-rw-r--r-- | kernel/signal.c | 7 | ||||
-rw-r--r-- | security/selinux/avc.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 2 | ||||
-rw-r--r-- | security/selinux/nlmsgtab.c | 9 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 4 |
15 files changed, 370 insertions, 231 deletions
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 600f23d7fd33..cd752a3cf3bd 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig | |||
@@ -1083,6 +1083,23 @@ source "drivers/zorro/Kconfig" | |||
1083 | 1083 | ||
1084 | source kernel/power/Kconfig | 1084 | source kernel/power/Kconfig |
1085 | 1085 | ||
1086 | config SECCOMP | ||
1087 | bool "Enable seccomp to safely compute untrusted bytecode" | ||
1088 | depends on PROC_FS | ||
1089 | default y | ||
1090 | help | ||
1091 | This kernel feature is useful for number crunching applications | ||
1092 | that may need to compute untrusted bytecode during their | ||
1093 | execution. By using pipes or other transports made available to | ||
1094 | the process as file descriptors supporting the read/write | ||
1095 | syscalls, it's possible to isolate those applications in | ||
1096 | their own address space using seccomp. Once seccomp is | ||
1097 | enabled via /proc/<pid>/seccomp, it cannot be disabled | ||
1098 | and the task is only allowed to execute a few safe syscalls | ||
1099 | defined by each seccomp mode. | ||
1100 | |||
1101 | If unsure, say Y. Only embedded should say N here. | ||
1102 | |||
1086 | endmenu | 1103 | endmenu |
1087 | 1104 | ||
1088 | config ISA_DMA_API | 1105 | config ISA_DMA_API |
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 5f075dbc4ee7..661523707e8c 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S | |||
@@ -202,7 +202,7 @@ _GLOBAL(DoSyscall) | |||
202 | rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR | 202 | rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR |
203 | stw r11,TI_LOCAL_FLAGS(r10) | 203 | stw r11,TI_LOCAL_FLAGS(r10) |
204 | lwz r11,TI_FLAGS(r10) | 204 | lwz r11,TI_FLAGS(r10) |
205 | andi. r11,r11,_TIF_SYSCALL_TRACE | 205 | andi. r11,r11,_TIF_SYSCALL_T_OR_A |
206 | bne- syscall_dotrace | 206 | bne- syscall_dotrace |
207 | syscall_dotrace_cont: | 207 | syscall_dotrace_cont: |
208 | cmplwi 0,r0,NR_syscalls | 208 | cmplwi 0,r0,NR_syscalls |
@@ -237,7 +237,7 @@ ret_from_syscall: | |||
237 | SYNC | 237 | SYNC |
238 | MTMSRD(r10) | 238 | MTMSRD(r10) |
239 | lwz r9,TI_FLAGS(r12) | 239 | lwz r9,TI_FLAGS(r12) |
240 | andi. r0,r9,(_TIF_SYSCALL_TRACE|_TIF_SIGPENDING|_TIF_NEED_RESCHED) | 240 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) |
241 | bne- syscall_exit_work | 241 | bne- syscall_exit_work |
242 | syscall_exit_cont: | 242 | syscall_exit_cont: |
243 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) | 243 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) |
@@ -277,7 +277,8 @@ syscall_dotrace: | |||
277 | SAVE_NVGPRS(r1) | 277 | SAVE_NVGPRS(r1) |
278 | li r0,0xc00 | 278 | li r0,0xc00 |
279 | stw r0,TRAP(r1) | 279 | stw r0,TRAP(r1) |
280 | bl do_syscall_trace | 280 | addi r3,r1,STACK_FRAME_OVERHEAD |
281 | bl do_syscall_trace_enter | ||
281 | lwz r0,GPR0(r1) /* Restore original registers */ | 282 | lwz r0,GPR0(r1) /* Restore original registers */ |
282 | lwz r3,GPR3(r1) | 283 | lwz r3,GPR3(r1) |
283 | lwz r4,GPR4(r1) | 284 | lwz r4,GPR4(r1) |
@@ -291,7 +292,7 @@ syscall_dotrace: | |||
291 | syscall_exit_work: | 292 | syscall_exit_work: |
292 | stw r6,RESULT(r1) /* Save result */ | 293 | stw r6,RESULT(r1) /* Save result */ |
293 | stw r3,GPR3(r1) /* Update return value */ | 294 | stw r3,GPR3(r1) /* Update return value */ |
294 | andi. r0,r9,_TIF_SYSCALL_TRACE | 295 | andi. r0,r9,_TIF_SYSCALL_T_OR_A |
295 | beq 5f | 296 | beq 5f |
296 | ori r10,r10,MSR_EE | 297 | ori r10,r10,MSR_EE |
297 | SYNC | 298 | SYNC |
@@ -303,7 +304,8 @@ syscall_exit_work: | |||
303 | li r4,0xc00 | 304 | li r4,0xc00 |
304 | stw r4,TRAP(r1) | 305 | stw r4,TRAP(r1) |
305 | 4: | 306 | 4: |
306 | bl do_syscall_trace | 307 | addi r3,r1,STACK_FRAME_OVERHEAD |
308 | bl do_syscall_trace_leave | ||
307 | REST_NVGPRS(r1) | 309 | REST_NVGPRS(r1) |
308 | 2: | 310 | 2: |
309 | lwz r3,GPR3(r1) | 311 | lwz r3,GPR3(r1) |
@@ -627,8 +629,8 @@ sigreturn_exit: | |||
627 | subi r1,r3,STACK_FRAME_OVERHEAD | 629 | subi r1,r3,STACK_FRAME_OVERHEAD |
628 | rlwinm r12,r1,0,0,18 /* current_thread_info() */ | 630 | rlwinm r12,r1,0,0,18 /* current_thread_info() */ |
629 | lwz r9,TI_FLAGS(r12) | 631 | lwz r9,TI_FLAGS(r12) |
630 | andi. r0,r9,_TIF_SYSCALL_TRACE | 632 | andi. r0,r9,_TIF_SYSCALL_T_OR_A |
631 | bnel- do_syscall_trace | 633 | bnel- do_syscall_trace_leave |
632 | /* fall through */ | 634 | /* fall through */ |
633 | 635 | ||
634 | .globl ret_from_except_full | 636 | .globl ret_from_except_full |
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 2ccb58fe4fc3..d59ad07de8e7 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c | |||
@@ -55,7 +55,6 @@ | |||
55 | #define EXPORT_SYMTAB_STROPS | 55 | #define EXPORT_SYMTAB_STROPS |
56 | 56 | ||
57 | extern void transfer_to_handler(void); | 57 | extern void transfer_to_handler(void); |
58 | extern void do_syscall_trace(void); | ||
59 | extern void do_IRQ(struct pt_regs *regs); | 58 | extern void do_IRQ(struct pt_regs *regs); |
60 | extern void MachineCheckException(struct pt_regs *regs); | 59 | extern void MachineCheckException(struct pt_regs *regs); |
61 | extern void AlignmentException(struct pt_regs *regs); | 60 | extern void AlignmentException(struct pt_regs *regs); |
@@ -74,7 +73,6 @@ extern unsigned long mm_ptov (unsigned long paddr); | |||
74 | EXPORT_SYMBOL(clear_pages); | 73 | EXPORT_SYMBOL(clear_pages); |
75 | EXPORT_SYMBOL(clear_user_page); | 74 | EXPORT_SYMBOL(clear_user_page); |
76 | EXPORT_SYMBOL(do_signal); | 75 | EXPORT_SYMBOL(do_signal); |
77 | EXPORT_SYMBOL(do_syscall_trace); | ||
78 | EXPORT_SYMBOL(transfer_to_handler); | 76 | EXPORT_SYMBOL(transfer_to_handler); |
79 | EXPORT_SYMBOL(do_IRQ); | 77 | EXPORT_SYMBOL(do_IRQ); |
80 | EXPORT_SYMBOL(MachineCheckException); | 78 | EXPORT_SYMBOL(MachineCheckException); |
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index 59d59a8dc249..e7aee4108dea 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include <linux/user.h> | 27 | #include <linux/user.h> |
28 | #include <linux/security.h> | 28 | #include <linux/security.h> |
29 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
30 | #include <linux/seccomp.h> | ||
31 | #include <linux/audit.h> | ||
32 | #include <linux/module.h> | ||
30 | 33 | ||
31 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
32 | #include <asm/page.h> | 35 | #include <asm/page.h> |
@@ -455,11 +458,10 @@ out: | |||
455 | return ret; | 458 | return ret; |
456 | } | 459 | } |
457 | 460 | ||
458 | void do_syscall_trace(void) | 461 | static void do_syscall_trace(void) |
459 | { | 462 | { |
460 | if (!test_thread_flag(TIF_SYSCALL_TRACE) | 463 | /* the 0x80 provides a way for the tracing parent to distinguish |
461 | || !(current->ptrace & PT_PTRACED)) | 464 | between a syscall stop and SIGTRAP delivery */ |
462 | return; | ||
463 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | 465 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) |
464 | ? 0x80 : 0)); | 466 | ? 0x80 : 0)); |
465 | 467 | ||
@@ -473,3 +475,33 @@ void do_syscall_trace(void) | |||
473 | current->exit_code = 0; | 475 | current->exit_code = 0; |
474 | } | 476 | } |
475 | } | 477 | } |
478 | |||
479 | void do_syscall_trace_enter(struct pt_regs *regs) | ||
480 | { | ||
481 | if (test_thread_flag(TIF_SYSCALL_TRACE) | ||
482 | && (current->ptrace & PT_PTRACED)) | ||
483 | do_syscall_trace(); | ||
484 | |||
485 | if (unlikely(current->audit_context)) | ||
486 | audit_syscall_entry(current, AUDIT_ARCH_PPC, | ||
487 | regs->gpr[0], | ||
488 | regs->gpr[3], regs->gpr[4], | ||
489 | regs->gpr[5], regs->gpr[6]); | ||
490 | } | ||
491 | |||
492 | void do_syscall_trace_leave(struct pt_regs *regs) | ||
493 | { | ||
494 | secure_computing(regs->gpr[0]); | ||
495 | |||
496 | if (unlikely(current->audit_context)) | ||
497 | audit_syscall_exit(current, | ||
498 | (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, | ||
499 | regs->result); | ||
500 | |||
501 | if ((test_thread_flag(TIF_SYSCALL_TRACE)) | ||
502 | && (current->ptrace & PT_PTRACED)) | ||
503 | do_syscall_trace(); | ||
504 | } | ||
505 | |||
506 | EXPORT_SYMBOL(do_syscall_trace_enter); | ||
507 | EXPORT_SYMBOL(do_syscall_trace_leave); | ||
diff --git a/include/asm-ppc/seccomp.h b/include/asm-ppc/seccomp.h new file mode 100644 index 000000000000..666c4da96d87 --- /dev/null +++ b/include/asm-ppc/seccomp.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef _ASM_SECCOMP_H | ||
2 | |||
3 | #include <linux/unistd.h> | ||
4 | |||
5 | #define __NR_seccomp_read __NR_read | ||
6 | #define __NR_seccomp_write __NR_write | ||
7 | #define __NR_seccomp_exit __NR_exit | ||
8 | #define __NR_seccomp_sigreturn __NR_rt_sigreturn | ||
9 | |||
10 | #endif /* _ASM_SECCOMP_H */ | ||
diff --git a/include/asm-ppc/thread_info.h b/include/asm-ppc/thread_info.h index f7f01524e8a8..e3b5284a6f91 100644 --- a/include/asm-ppc/thread_info.h +++ b/include/asm-ppc/thread_info.h | |||
@@ -77,12 +77,19 @@ static inline struct thread_info *current_thread_info(void) | |||
77 | #define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling | 77 | #define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling |
78 | TIF_NEED_RESCHED */ | 78 | TIF_NEED_RESCHED */ |
79 | #define TIF_MEMDIE 5 | 79 | #define TIF_MEMDIE 5 |
80 | #define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ | ||
81 | #define TIF_SECCOMP 7 /* secure computing */ | ||
82 | |||
80 | /* as above, but as bit values */ | 83 | /* as above, but as bit values */ |
81 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) | 84 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) |
82 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | 85 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) |
83 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) | 86 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) |
84 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 87 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
85 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 88 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
89 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | ||
90 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | ||
91 | |||
92 | #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP) | ||
86 | 93 | ||
87 | /* | 94 | /* |
88 | * Non racy (local) flags bit numbers | 95 | * Non racy (local) flags bit numbers |
diff --git a/include/linux/audit.h b/include/linux/audit.h index 19f04b049798..51e5879af7fc 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -27,15 +27,55 @@ | |||
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/elf.h> | 28 | #include <linux/elf.h> |
29 | 29 | ||
30 | /* Request and reply types */ | 30 | /* The netlink messages for the audit system is divided into blocks: |
31 | #define AUDIT_GET 1000 /* Get status */ | 31 | * 1000 - 1099 are for commanding the audit system |
32 | #define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ | 32 | * 1100 - 1199 user space trusted application messages |
33 | #define AUDIT_LIST 1002 /* List filtering rules */ | 33 | * 1200 - 1299 messages internal to the audit daemon |
34 | #define AUDIT_ADD 1003 /* Add filtering rule */ | 34 | * 1300 - 1399 audit event messages |
35 | #define AUDIT_DEL 1004 /* Delete filtering rule */ | 35 | * 1400 - 1499 SE Linux use |
36 | #define AUDIT_USER 1005 /* Send a message from user-space */ | 36 | * 1500 - 1999 future use |
37 | #define AUDIT_LOGIN 1006 /* Define the login id and informaiton */ | 37 | * 2000 is for otherwise unclassified kernel audit messages |
38 | #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ | 38 | * |
39 | * Messages from 1000-1199 are bi-directional. 1200-1299 are exclusively user | ||
40 | * space. Anything over that is kernel --> user space communication. | ||
41 | */ | ||
42 | #define AUDIT_GET 1000 /* Get status */ | ||
43 | #define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ | ||
44 | #define AUDIT_LIST 1002 /* List syscall filtering rules */ | ||
45 | #define AUDIT_ADD 1003 /* Add syscall filtering rule */ | ||
46 | #define AUDIT_DEL 1004 /* Delete syscall filtering rule */ | ||
47 | #define AUDIT_USER 1005 /* Message from userspace -- deprecated */ | ||
48 | #define AUDIT_LOGIN 1006 /* Define the login id and information */ | ||
49 | #define AUDIT_WATCH_INS 1007 /* Insert file/dir watch entry */ | ||
50 | #define AUDIT_WATCH_REM 1008 /* Remove file/dir watch entry */ | ||
51 | #define AUDIT_WATCH_LIST 1009 /* List all file/dir watches */ | ||
52 | #define AUDIT_SIGNAL_INFO 1010 /* Get info about sender of signal to auditd */ | ||
53 | |||
54 | #define AUDIT_USER_AUTH 1100 /* User space authentication */ | ||
55 | #define AUDIT_USER_ACCT 1101 /* User space acct change */ | ||
56 | #define AUDIT_USER_MGMT 1102 /* User space acct management */ | ||
57 | #define AUDIT_CRED_ACQ 1103 /* User space credential acquired */ | ||
58 | #define AUDIT_CRED_DISP 1104 /* User space credential disposed */ | ||
59 | #define AUDIT_USER_START 1105 /* User space session start */ | ||
60 | #define AUDIT_USER_END 1106 /* User space session end */ | ||
61 | #define AUDIT_USER_AVC 1107 /* User space avc message */ | ||
62 | |||
63 | #define AUDIT_DAEMON_START 1200 /* Daemon startup record */ | ||
64 | #define AUDIT_DAEMON_END 1201 /* Daemon normal stop record */ | ||
65 | #define AUDIT_DAEMON_ABORT 1202 /* Daemon error stop record */ | ||
66 | #define AUDIT_DAEMON_CONFIG 1203 /* Daemon config change */ | ||
67 | |||
68 | #define AUDIT_SYSCALL 1300 /* Syscall event */ | ||
69 | #define AUDIT_FS_WATCH 1301 /* Filesystem watch event */ | ||
70 | #define AUDIT_PATH 1302 /* Filname path information */ | ||
71 | #define AUDIT_IPC 1303 /* IPC record */ | ||
72 | #define AUDIT_SOCKET 1304 /* Socket record */ | ||
73 | #define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */ | ||
74 | |||
75 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | ||
76 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | ||
77 | |||
78 | #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ | ||
39 | 79 | ||
40 | /* Rule flags */ | 80 | /* Rule flags */ |
41 | #define AUDIT_PER_TASK 0x01 /* Apply rule at task creation (not syscall) */ | 81 | #define AUDIT_PER_TASK 0x01 /* Apply rule at task creation (not syscall) */ |
@@ -141,7 +181,7 @@ struct audit_message { | |||
141 | 181 | ||
142 | struct audit_status { | 182 | struct audit_status { |
143 | __u32 mask; /* Bit mask for valid entries */ | 183 | __u32 mask; /* Bit mask for valid entries */ |
144 | __u32 enabled; /* 1 = enabled, 0 = disbaled */ | 184 | __u32 enabled; /* 1 = enabled, 0 = disabled */ |
145 | __u32 failure; /* Failure-to-log action */ | 185 | __u32 failure; /* Failure-to-log action */ |
146 | __u32 pid; /* pid of auditd process */ | 186 | __u32 pid; /* pid of auditd process */ |
147 | __u32 rate_limit; /* messages rate limit (per second) */ | 187 | __u32 rate_limit; /* messages rate limit (per second) */ |
@@ -161,6 +201,11 @@ struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */ | |||
161 | 201 | ||
162 | #ifdef __KERNEL__ | 202 | #ifdef __KERNEL__ |
163 | 203 | ||
204 | struct audit_sig_info { | ||
205 | uid_t uid; | ||
206 | pid_t pid; | ||
207 | }; | ||
208 | |||
164 | struct audit_buffer; | 209 | struct audit_buffer; |
165 | struct audit_context; | 210 | struct audit_context; |
166 | struct inode; | 211 | struct inode; |
@@ -185,11 +230,12 @@ extern void audit_inode(const char *name, const struct inode *inode); | |||
185 | /* Private API (for audit.c only) */ | 230 | /* Private API (for audit.c only) */ |
186 | extern int audit_receive_filter(int type, int pid, int uid, int seq, | 231 | extern int audit_receive_filter(int type, int pid, int uid, int seq, |
187 | void *data, uid_t loginuid); | 232 | void *data, uid_t loginuid); |
188 | extern void audit_get_stamp(struct audit_context *ctx, | 233 | extern int audit_get_stamp(struct audit_context *ctx, |
189 | struct timespec *t, unsigned int *serial); | 234 | struct timespec *t, unsigned int *serial); |
190 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); | 235 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); |
191 | extern uid_t audit_get_loginuid(struct audit_context *ctx); | 236 | extern uid_t audit_get_loginuid(struct audit_context *ctx); |
192 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); | 237 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); |
238 | extern void audit_signal_info(int sig, struct task_struct *t); | ||
193 | #else | 239 | #else |
194 | #define audit_alloc(t) ({ 0; }) | 240 | #define audit_alloc(t) ({ 0; }) |
195 | #define audit_free(t) do { ; } while (0) | 241 | #define audit_free(t) do { ; } while (0) |
@@ -198,18 +244,21 @@ extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mo | |||
198 | #define audit_getname(n) do { ; } while (0) | 244 | #define audit_getname(n) do { ; } while (0) |
199 | #define audit_putname(n) do { ; } while (0) | 245 | #define audit_putname(n) do { ; } while (0) |
200 | #define audit_inode(n,i) do { ; } while (0) | 246 | #define audit_inode(n,i) do { ; } while (0) |
247 | #define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) | ||
248 | #define audit_get_stamp(c,t,s) ({ 0; }) | ||
201 | #define audit_get_loginuid(c) ({ -1; }) | 249 | #define audit_get_loginuid(c) ({ -1; }) |
202 | #define audit_ipc_perms(q,u,g,m) ({ 0; }) | 250 | #define audit_ipc_perms(q,u,g,m) ({ 0; }) |
251 | #define audit_signal_info(s,t) do { ; } while (0) | ||
203 | #endif | 252 | #endif |
204 | 253 | ||
205 | #ifdef CONFIG_AUDIT | 254 | #ifdef CONFIG_AUDIT |
206 | /* These are defined in audit.c */ | 255 | /* These are defined in audit.c */ |
207 | /* Public API */ | 256 | /* Public API */ |
208 | extern void audit_log(struct audit_context *ctx, | 257 | extern void audit_log(struct audit_context *ctx, int type, |
209 | const char *fmt, ...) | 258 | const char *fmt, ...) |
210 | __attribute__((format(printf,2,3))); | 259 | __attribute__((format(printf,3,4))); |
211 | 260 | ||
212 | extern struct audit_buffer *audit_log_start(struct audit_context *ctx); | 261 | extern struct audit_buffer *audit_log_start(struct audit_context *ctx,int type); |
213 | extern void audit_log_format(struct audit_buffer *ab, | 262 | extern void audit_log_format(struct audit_buffer *ab, |
214 | const char *fmt, ...) | 263 | const char *fmt, ...) |
215 | __attribute__((format(printf,2,3))); | 264 | __attribute__((format(printf,2,3))); |
@@ -229,8 +278,8 @@ extern void audit_send_reply(int pid, int seq, int type, | |||
229 | void *payload, int size); | 278 | void *payload, int size); |
230 | extern void audit_log_lost(const char *message); | 279 | extern void audit_log_lost(const char *message); |
231 | #else | 280 | #else |
232 | #define audit_log(t,f,...) do { ; } while (0) | 281 | #define audit_log(c,t,f,...) do { ; } while (0) |
233 | #define audit_log_start(t) ({ NULL; }) | 282 | #define audit_log_start(c,t) ({ NULL; }) |
234 | #define audit_log_vformat(b,f,a) do { ; } while (0) | 283 | #define audit_log_vformat(b,f,a) do { ; } while (0) |
235 | #define audit_log_format(b,f,...) do { ; } while (0) | 284 | #define audit_log_format(b,f,...) do { ; } while (0) |
236 | #define audit_log_end(b) do { ; } while (0) | 285 | #define audit_log_end(b) do { ; } while (0) |
diff --git a/init/Kconfig b/init/Kconfig index d920baed109a..448939d183dd 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -164,6 +164,7 @@ config SYSCTL | |||
164 | 164 | ||
165 | config AUDIT | 165 | config AUDIT |
166 | bool "Auditing support" | 166 | bool "Auditing support" |
167 | depends on NET | ||
167 | default y if SECURITY_SELINUX | 168 | default y if SECURITY_SELINUX |
168 | help | 169 | help |
169 | Enable auditing infrastructure that can be used with another | 170 | Enable auditing infrastructure that can be used with another |
@@ -173,7 +174,7 @@ config AUDIT | |||
173 | 174 | ||
174 | config AUDITSYSCALL | 175 | config AUDITSYSCALL |
175 | bool "Enable system-call auditing support" | 176 | bool "Enable system-call auditing support" |
176 | depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64 || UML) | 177 | depends on AUDIT && (X86 || PPC || PPC64 || ARCH_S390 || IA64 || UML) |
177 | default y if SECURITY_SELINUX | 178 | default y if SECURITY_SELINUX |
178 | help | 179 | help |
179 | Enable low-overhead system-call auditing infrastructure that | 180 | Enable low-overhead system-call auditing infrastructure that |
diff --git a/kernel/audit.c b/kernel/audit.c index 9c4f1af0c794..a0e33b6897d7 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -68,7 +68,7 @@ static int audit_failure = AUDIT_FAIL_PRINTK; | |||
68 | 68 | ||
69 | /* If audit records are to be written to the netlink socket, audit_pid | 69 | /* If audit records are to be written to the netlink socket, audit_pid |
70 | * contains the (non-zero) pid. */ | 70 | * contains the (non-zero) pid. */ |
71 | static int audit_pid; | 71 | int audit_pid; |
72 | 72 | ||
73 | /* If audit_limit is non-zero, limit the rate of sending audit records | 73 | /* If audit_limit is non-zero, limit the rate of sending audit records |
74 | * to that number per second. This prevents DoS attacks, but results in | 74 | * to that number per second. This prevents DoS attacks, but results in |
@@ -79,6 +79,10 @@ static int audit_rate_limit; | |||
79 | static int audit_backlog_limit = 64; | 79 | static int audit_backlog_limit = 64; |
80 | static atomic_t audit_backlog = ATOMIC_INIT(0); | 80 | static atomic_t audit_backlog = ATOMIC_INIT(0); |
81 | 81 | ||
82 | /* The identity of the user shutting down the audit system. */ | ||
83 | uid_t audit_sig_uid = -1; | ||
84 | pid_t audit_sig_pid = -1; | ||
85 | |||
82 | /* Records can be lost in several ways: | 86 | /* Records can be lost in several ways: |
83 | 0) [suppressed in audit_alloc] | 87 | 0) [suppressed in audit_alloc] |
84 | 1) out of memory in audit_log_start [kmalloc of struct audit_buffer] | 88 | 1) out of memory in audit_log_start [kmalloc of struct audit_buffer] |
@@ -112,7 +116,7 @@ static LIST_HEAD(audit_entlist); | |||
112 | static LIST_HEAD(audit_extlist); | 116 | static LIST_HEAD(audit_extlist); |
113 | 117 | ||
114 | /* The netlink socket is only to be read by 1 CPU, which lets us assume | 118 | /* The netlink socket is only to be read by 1 CPU, which lets us assume |
115 | * that list additions and deletions never happen simultaneiously in | 119 | * that list additions and deletions never happen simultaneously in |
116 | * auditsc.c */ | 120 | * auditsc.c */ |
117 | static DECLARE_MUTEX(audit_netlink_sem); | 121 | static DECLARE_MUTEX(audit_netlink_sem); |
118 | 122 | ||
@@ -132,21 +136,14 @@ static DECLARE_MUTEX(audit_netlink_sem); | |||
132 | * use simultaneously. */ | 136 | * use simultaneously. */ |
133 | struct audit_buffer { | 137 | struct audit_buffer { |
134 | struct list_head list; | 138 | struct list_head list; |
135 | struct sk_buff_head sklist; /* formatted skbs ready to send */ | 139 | struct sk_buff *skb; /* formatted skb ready to send */ |
136 | struct audit_context *ctx; /* NULL or associated context */ | 140 | struct audit_context *ctx; /* NULL or associated context */ |
137 | int len; /* used area of tmp */ | ||
138 | char tmp[AUDIT_BUFSIZ]; | ||
139 | |||
140 | /* Pointer to header and contents */ | ||
141 | struct nlmsghdr *nlh; | ||
142 | int total; | ||
143 | int type; | ||
144 | int pid; | ||
145 | }; | 141 | }; |
146 | 142 | ||
147 | void audit_set_type(struct audit_buffer *ab, int type) | 143 | static void audit_set_pid(struct audit_buffer *ab, pid_t pid) |
148 | { | 144 | { |
149 | ab->type = type; | 145 | struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data; |
146 | nlh->nlmsg_pid = pid; | ||
150 | } | 147 | } |
151 | 148 | ||
152 | struct audit_entry { | 149 | struct audit_entry { |
@@ -242,7 +239,8 @@ static int audit_set_rate_limit(int limit, uid_t loginuid) | |||
242 | { | 239 | { |
243 | int old = audit_rate_limit; | 240 | int old = audit_rate_limit; |
244 | audit_rate_limit = limit; | 241 | audit_rate_limit = limit; |
245 | audit_log(NULL, "audit_rate_limit=%d old=%d by auid %u", | 242 | audit_log(NULL, AUDIT_CONFIG_CHANGE, |
243 | "audit_rate_limit=%d old=%d by auid %u", | ||
246 | audit_rate_limit, old, loginuid); | 244 | audit_rate_limit, old, loginuid); |
247 | return old; | 245 | return old; |
248 | } | 246 | } |
@@ -251,7 +249,8 @@ static int audit_set_backlog_limit(int limit, uid_t loginuid) | |||
251 | { | 249 | { |
252 | int old = audit_backlog_limit; | 250 | int old = audit_backlog_limit; |
253 | audit_backlog_limit = limit; | 251 | audit_backlog_limit = limit; |
254 | audit_log(NULL, "audit_backlog_limit=%d old=%d by auid %u", | 252 | audit_log(NULL, AUDIT_CONFIG_CHANGE, |
253 | "audit_backlog_limit=%d old=%d by auid %u", | ||
255 | audit_backlog_limit, old, loginuid); | 254 | audit_backlog_limit, old, loginuid); |
256 | return old; | 255 | return old; |
257 | } | 256 | } |
@@ -262,8 +261,9 @@ static int audit_set_enabled(int state, uid_t loginuid) | |||
262 | if (state != 0 && state != 1) | 261 | if (state != 0 && state != 1) |
263 | return -EINVAL; | 262 | return -EINVAL; |
264 | audit_enabled = state; | 263 | audit_enabled = state; |
265 | audit_log(NULL, "audit_enabled=%d old=%d by auid %u", | 264 | audit_log(NULL, AUDIT_CONFIG_CHANGE, |
266 | audit_enabled, old, loginuid); | 265 | "audit_enabled=%d old=%d by auid %u", |
266 | audit_enabled, old, loginuid); | ||
267 | return old; | 267 | return old; |
268 | } | 268 | } |
269 | 269 | ||
@@ -275,12 +275,12 @@ static int audit_set_failure(int state, uid_t loginuid) | |||
275 | && state != AUDIT_FAIL_PANIC) | 275 | && state != AUDIT_FAIL_PANIC) |
276 | return -EINVAL; | 276 | return -EINVAL; |
277 | audit_failure = state; | 277 | audit_failure = state; |
278 | audit_log(NULL, "audit_failure=%d old=%d by auid %u", | 278 | audit_log(NULL, AUDIT_CONFIG_CHANGE, |
279 | audit_failure, old, loginuid); | 279 | "audit_failure=%d old=%d by auid %u", |
280 | audit_failure, old, loginuid); | ||
280 | return old; | 281 | return old; |
281 | } | 282 | } |
282 | 283 | ||
283 | #ifdef CONFIG_NET | ||
284 | void audit_send_reply(int pid, int seq, int type, int done, int multi, | 284 | void audit_send_reply(int pid, int seq, int type, int done, int multi, |
285 | void *payload, int size) | 285 | void *payload, int size) |
286 | { | 286 | { |
@@ -321,10 +321,19 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type) | |||
321 | case AUDIT_SET: | 321 | case AUDIT_SET: |
322 | case AUDIT_ADD: | 322 | case AUDIT_ADD: |
323 | case AUDIT_DEL: | 323 | case AUDIT_DEL: |
324 | case AUDIT_SIGNAL_INFO: | ||
324 | if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL)) | 325 | if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL)) |
325 | err = -EPERM; | 326 | err = -EPERM; |
326 | break; | 327 | break; |
327 | case AUDIT_USER: | 328 | case AUDIT_USER: |
329 | case AUDIT_USER_AUTH: | ||
330 | case AUDIT_USER_ACCT: | ||
331 | case AUDIT_USER_MGMT: | ||
332 | case AUDIT_CRED_ACQ: | ||
333 | case AUDIT_CRED_DISP: | ||
334 | case AUDIT_USER_START: | ||
335 | case AUDIT_USER_END: | ||
336 | case AUDIT_USER_AVC: | ||
328 | if (!cap_raised(eff_cap, CAP_AUDIT_WRITE)) | 337 | if (!cap_raised(eff_cap, CAP_AUDIT_WRITE)) |
329 | err = -EPERM; | 338 | err = -EPERM; |
330 | break; | 339 | break; |
@@ -344,6 +353,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
344 | struct audit_buffer *ab; | 353 | struct audit_buffer *ab; |
345 | u16 msg_type = nlh->nlmsg_type; | 354 | u16 msg_type = nlh->nlmsg_type; |
346 | uid_t loginuid; /* loginuid of sender */ | 355 | uid_t loginuid; /* loginuid of sender */ |
356 | struct audit_sig_info sig_data; | ||
347 | 357 | ||
348 | err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); | 358 | err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); |
349 | if (err) | 359 | if (err) |
@@ -382,7 +392,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
382 | if (status_get->mask & AUDIT_STATUS_PID) { | 392 | if (status_get->mask & AUDIT_STATUS_PID) { |
383 | int old = audit_pid; | 393 | int old = audit_pid; |
384 | audit_pid = status_get->pid; | 394 | audit_pid = status_get->pid; |
385 | audit_log(NULL, "audit_pid=%d old=%d by auid %u", | 395 | audit_log(NULL, AUDIT_CONFIG_CHANGE, |
396 | "audit_pid=%d old=%d by auid %u", | ||
386 | audit_pid, old, loginuid); | 397 | audit_pid, old, loginuid); |
387 | } | 398 | } |
388 | if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) | 399 | if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) |
@@ -392,7 +403,15 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
392 | loginuid); | 403 | loginuid); |
393 | break; | 404 | break; |
394 | case AUDIT_USER: | 405 | case AUDIT_USER: |
395 | ab = audit_log_start(NULL); | 406 | case AUDIT_USER_AUTH: |
407 | case AUDIT_USER_ACCT: | ||
408 | case AUDIT_USER_MGMT: | ||
409 | case AUDIT_CRED_ACQ: | ||
410 | case AUDIT_CRED_DISP: | ||
411 | case AUDIT_USER_START: | ||
412 | case AUDIT_USER_END: | ||
413 | case AUDIT_USER_AVC: | ||
414 | ab = audit_log_start(NULL, msg_type); | ||
396 | if (!ab) | 415 | if (!ab) |
397 | break; /* audit_panic has been called */ | 416 | break; /* audit_panic has been called */ |
398 | audit_log_format(ab, | 417 | audit_log_format(ab, |
@@ -402,8 +421,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
402 | (int)(nlh->nlmsg_len | 421 | (int)(nlh->nlmsg_len |
403 | - ((char *)data - (char *)nlh)), | 422 | - ((char *)data - (char *)nlh)), |
404 | loginuid, (char *)data); | 423 | loginuid, (char *)data); |
405 | ab->type = AUDIT_USER; | 424 | audit_set_pid(ab, pid); |
406 | ab->pid = pid; | ||
407 | audit_log_end(ab); | 425 | audit_log_end(ab); |
408 | break; | 426 | break; |
409 | case AUDIT_ADD: | 427 | case AUDIT_ADD: |
@@ -412,12 +430,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
412 | return -EINVAL; | 430 | return -EINVAL; |
413 | /* fallthrough */ | 431 | /* fallthrough */ |
414 | case AUDIT_LIST: | 432 | case AUDIT_LIST: |
415 | #ifdef CONFIG_AUDITSYSCALL | ||
416 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, | 433 | err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, |
417 | uid, seq, data, loginuid); | 434 | uid, seq, data, loginuid); |
418 | #else | 435 | break; |
419 | err = -EOPNOTSUPP; | 436 | case AUDIT_SIGNAL_INFO: |
420 | #endif | 437 | sig_data.uid = audit_sig_uid; |
438 | sig_data.pid = audit_sig_pid; | ||
439 | audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO, | ||
440 | 0, 0, &sig_data, sizeof(sig_data)); | ||
421 | break; | 441 | break; |
422 | default: | 442 | default: |
423 | err = -EINVAL; | 443 | err = -EINVAL; |
@@ -467,64 +487,23 @@ static void audit_receive(struct sock *sk, int length) | |||
467 | up(&audit_netlink_sem); | 487 | up(&audit_netlink_sem); |
468 | } | 488 | } |
469 | 489 | ||
470 | /* Move data from tmp buffer into an skb. This is an extra copy, and | 490 | /* Grab skbuff from the audit_buffer and send to user space. */ |
471 | * that is unfortunate. However, the copy will only occur when a record | ||
472 | * is being written to user space, which is already a high-overhead | ||
473 | * operation. (Elimination of the copy is possible, for example, by | ||
474 | * writing directly into a pre-allocated skb, at the cost of wasting | ||
475 | * memory. */ | ||
476 | static void audit_log_move(struct audit_buffer *ab) | ||
477 | { | ||
478 | struct sk_buff *skb; | ||
479 | char *start; | ||
480 | int extra = ab->nlh ? 0 : NLMSG_SPACE(0); | ||
481 | |||
482 | /* possible resubmission */ | ||
483 | if (ab->len == 0) | ||
484 | return; | ||
485 | |||
486 | skb = skb_peek_tail(&ab->sklist); | ||
487 | if (!skb || skb_tailroom(skb) <= ab->len + extra) { | ||
488 | skb = alloc_skb(2 * ab->len + extra, GFP_ATOMIC); | ||
489 | if (!skb) { | ||
490 | ab->len = 0; /* Lose information in ab->tmp */ | ||
491 | audit_log_lost("out of memory in audit_log_move"); | ||
492 | return; | ||
493 | } | ||
494 | __skb_queue_tail(&ab->sklist, skb); | ||
495 | if (!ab->nlh) | ||
496 | ab->nlh = (struct nlmsghdr *)skb_put(skb, | ||
497 | NLMSG_SPACE(0)); | ||
498 | } | ||
499 | start = skb_put(skb, ab->len); | ||
500 | memcpy(start, ab->tmp, ab->len); | ||
501 | ab->len = 0; | ||
502 | } | ||
503 | |||
504 | /* Iterate over the skbuff in the audit_buffer, sending their contents | ||
505 | * to user space. */ | ||
506 | static inline int audit_log_drain(struct audit_buffer *ab) | 491 | static inline int audit_log_drain(struct audit_buffer *ab) |
507 | { | 492 | { |
508 | struct sk_buff *skb; | 493 | struct sk_buff *skb = ab->skb; |
509 | 494 | ||
510 | while ((skb = skb_dequeue(&ab->sklist))) { | 495 | if (skb) { |
511 | int retval = 0; | 496 | int retval = 0; |
512 | 497 | ||
513 | if (audit_pid) { | 498 | if (audit_pid) { |
514 | if (ab->nlh) { | 499 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; |
515 | ab->nlh->nlmsg_len = ab->total; | 500 | nlh->nlmsg_len = skb->len - NLMSG_SPACE(0); |
516 | ab->nlh->nlmsg_type = ab->type; | ||
517 | ab->nlh->nlmsg_flags = 0; | ||
518 | ab->nlh->nlmsg_seq = 0; | ||
519 | ab->nlh->nlmsg_pid = ab->pid; | ||
520 | } | ||
521 | skb_get(skb); /* because netlink_* frees */ | 501 | skb_get(skb); /* because netlink_* frees */ |
522 | retval = netlink_unicast(audit_sock, skb, audit_pid, | 502 | retval = netlink_unicast(audit_sock, skb, audit_pid, |
523 | MSG_DONTWAIT); | 503 | MSG_DONTWAIT); |
524 | } | 504 | } |
525 | if (retval == -EAGAIN && | 505 | if (retval == -EAGAIN && |
526 | (atomic_read(&audit_backlog)) < audit_backlog_limit) { | 506 | (atomic_read(&audit_backlog)) < audit_backlog_limit) { |
527 | skb_queue_head(&ab->sklist, skb); | ||
528 | audit_log_end_irq(ab); | 507 | audit_log_end_irq(ab); |
529 | return 1; | 508 | return 1; |
530 | } | 509 | } |
@@ -538,13 +517,11 @@ static inline int audit_log_drain(struct audit_buffer *ab) | |||
538 | audit_log_lost("netlink socket too busy"); | 517 | audit_log_lost("netlink socket too busy"); |
539 | } | 518 | } |
540 | if (!audit_pid) { /* No daemon */ | 519 | if (!audit_pid) { /* No daemon */ |
541 | int offset = ab->nlh ? NLMSG_SPACE(0) : 0; | 520 | int offset = NLMSG_SPACE(0); |
542 | int len = skb->len - offset; | 521 | int len = skb->len - offset; |
543 | skb->data[offset + len] = '\0'; | 522 | skb->data[offset + len] = '\0'; |
544 | printk(KERN_ERR "%s\n", skb->data + offset); | 523 | printk(KERN_ERR "%s\n", skb->data + offset); |
545 | } | 524 | } |
546 | kfree_skb(skb); | ||
547 | ab->nlh = NULL; | ||
548 | } | 525 | } |
549 | return 0; | 526 | return 0; |
550 | } | 527 | } |
@@ -560,38 +537,9 @@ static int __init audit_init(void) | |||
560 | 537 | ||
561 | audit_initialized = 1; | 538 | audit_initialized = 1; |
562 | audit_enabled = audit_default; | 539 | audit_enabled = audit_default; |
563 | audit_log(NULL, "initialized"); | 540 | audit_log(NULL, AUDIT_KERNEL, "initialized"); |
564 | return 0; | 541 | return 0; |
565 | } | 542 | } |
566 | |||
567 | #else | ||
568 | /* Without CONFIG_NET, we have no skbuffs. For now, print what we have | ||
569 | * in the buffer. */ | ||
570 | static void audit_log_move(struct audit_buffer *ab) | ||
571 | { | ||
572 | printk(KERN_ERR "%*.*s\n", ab->len, ab->len, ab->tmp); | ||
573 | ab->len = 0; | ||
574 | } | ||
575 | |||
576 | static inline int audit_log_drain(struct audit_buffer *ab) | ||
577 | { | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | /* Initialize audit support at boot time. */ | ||
582 | int __init audit_init(void) | ||
583 | { | ||
584 | printk(KERN_INFO "audit: initializing WITHOUT netlink support\n"); | ||
585 | audit_sock = NULL; | ||
586 | audit_pid = 0; | ||
587 | |||
588 | audit_initialized = 1; | ||
589 | audit_enabled = audit_default; | ||
590 | audit_log(NULL, "initialized"); | ||
591 | return 0; | ||
592 | } | ||
593 | #endif | ||
594 | |||
595 | __initcall(audit_init); | 543 | __initcall(audit_init); |
596 | 544 | ||
597 | /* Process kernel command-line parameter at boot time. audit=0 or audit=1. */ | 545 | /* Process kernel command-line parameter at boot time. audit=0 or audit=1. */ |
@@ -608,6 +556,62 @@ static int __init audit_enable(char *str) | |||
608 | 556 | ||
609 | __setup("audit=", audit_enable); | 557 | __setup("audit=", audit_enable); |
610 | 558 | ||
559 | static void audit_buffer_free(struct audit_buffer *ab) | ||
560 | { | ||
561 | unsigned long flags; | ||
562 | |||
563 | if (!ab) | ||
564 | return; | ||
565 | |||
566 | if (ab->skb) | ||
567 | kfree_skb(ab->skb); | ||
568 | atomic_dec(&audit_backlog); | ||
569 | spin_lock_irqsave(&audit_freelist_lock, flags); | ||
570 | if (++audit_freelist_count > AUDIT_MAXFREE) | ||
571 | kfree(ab); | ||
572 | else | ||
573 | list_add(&ab->list, &audit_freelist); | ||
574 | spin_unlock_irqrestore(&audit_freelist_lock, flags); | ||
575 | } | ||
576 | |||
577 | static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx, | ||
578 | int gfp_mask, int type) | ||
579 | { | ||
580 | unsigned long flags; | ||
581 | struct audit_buffer *ab = NULL; | ||
582 | struct nlmsghdr *nlh; | ||
583 | |||
584 | spin_lock_irqsave(&audit_freelist_lock, flags); | ||
585 | if (!list_empty(&audit_freelist)) { | ||
586 | ab = list_entry(audit_freelist.next, | ||
587 | struct audit_buffer, list); | ||
588 | list_del(&ab->list); | ||
589 | --audit_freelist_count; | ||
590 | } | ||
591 | spin_unlock_irqrestore(&audit_freelist_lock, flags); | ||
592 | |||
593 | if (!ab) { | ||
594 | ab = kmalloc(sizeof(*ab), gfp_mask); | ||
595 | if (!ab) | ||
596 | goto err; | ||
597 | } | ||
598 | atomic_inc(&audit_backlog); | ||
599 | |||
600 | ab->skb = alloc_skb(AUDIT_BUFSIZ, gfp_mask); | ||
601 | if (!ab->skb) | ||
602 | goto err; | ||
603 | |||
604 | ab->ctx = ctx; | ||
605 | nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0)); | ||
606 | nlh->nlmsg_type = type; | ||
607 | nlh->nlmsg_flags = 0; | ||
608 | nlh->nlmsg_pid = 0; | ||
609 | nlh->nlmsg_seq = 0; | ||
610 | return ab; | ||
611 | err: | ||
612 | audit_buffer_free(ab); | ||
613 | return NULL; | ||
614 | } | ||
611 | 615 | ||
612 | /* Obtain an audit buffer. This routine does locking to obtain the | 616 | /* Obtain an audit buffer. This routine does locking to obtain the |
613 | * audit buffer, but then no locking is required for calls to | 617 | * audit buffer, but then no locking is required for calls to |
@@ -615,10 +619,9 @@ __setup("audit=", audit_enable); | |||
615 | * syscall, then the syscall is marked as auditable and an audit record | 619 | * syscall, then the syscall is marked as auditable and an audit record |
616 | * will be written at syscall exit. If there is no associated task, tsk | 620 | * will be written at syscall exit. If there is no associated task, tsk |
617 | * should be NULL. */ | 621 | * should be NULL. */ |
618 | struct audit_buffer *audit_log_start(struct audit_context *ctx) | 622 | struct audit_buffer *audit_log_start(struct audit_context *ctx, int type) |
619 | { | 623 | { |
620 | struct audit_buffer *ab = NULL; | 624 | struct audit_buffer *ab = NULL; |
621 | unsigned long flags; | ||
622 | struct timespec t; | 625 | struct timespec t; |
623 | unsigned int serial; | 626 | unsigned int serial; |
624 | 627 | ||
@@ -637,46 +640,40 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx) | |||
637 | return NULL; | 640 | return NULL; |
638 | } | 641 | } |
639 | 642 | ||
640 | spin_lock_irqsave(&audit_freelist_lock, flags); | 643 | ab = audit_buffer_alloc(ctx, GFP_ATOMIC, type); |
641 | if (!list_empty(&audit_freelist)) { | ||
642 | ab = list_entry(audit_freelist.next, | ||
643 | struct audit_buffer, list); | ||
644 | list_del(&ab->list); | ||
645 | --audit_freelist_count; | ||
646 | } | ||
647 | spin_unlock_irqrestore(&audit_freelist_lock, flags); | ||
648 | |||
649 | if (!ab) | ||
650 | ab = kmalloc(sizeof(*ab), GFP_ATOMIC); | ||
651 | if (!ab) { | 644 | if (!ab) { |
652 | audit_log_lost("out of memory in audit_log_start"); | 645 | audit_log_lost("out of memory in audit_log_start"); |
653 | return NULL; | 646 | return NULL; |
654 | } | 647 | } |
655 | 648 | ||
656 | atomic_inc(&audit_backlog); | 649 | if (!audit_get_stamp(ab->ctx, &t, &serial)) { |
657 | skb_queue_head_init(&ab->sklist); | ||
658 | |||
659 | ab->ctx = ctx; | ||
660 | ab->len = 0; | ||
661 | ab->nlh = NULL; | ||
662 | ab->total = 0; | ||
663 | ab->type = AUDIT_KERNEL; | ||
664 | ab->pid = 0; | ||
665 | |||
666 | #ifdef CONFIG_AUDITSYSCALL | ||
667 | if (ab->ctx) | ||
668 | audit_get_stamp(ab->ctx, &t, &serial); | ||
669 | else | ||
670 | #endif | ||
671 | { | ||
672 | t = CURRENT_TIME; | 650 | t = CURRENT_TIME; |
673 | serial = 0; | 651 | serial = 0; |
674 | } | 652 | } |
653 | |||
675 | audit_log_format(ab, "audit(%lu.%03lu:%u): ", | 654 | audit_log_format(ab, "audit(%lu.%03lu:%u): ", |
676 | t.tv_sec, t.tv_nsec/1000000, serial); | 655 | t.tv_sec, t.tv_nsec/1000000, serial); |
677 | return ab; | 656 | return ab; |
678 | } | 657 | } |
679 | 658 | ||
659 | /** | ||
660 | * audit_expand - expand skb in the audit buffer | ||
661 | * @ab: audit_buffer | ||
662 | * | ||
663 | * Returns 0 (no space) on failed expansion, or available space if | ||
664 | * successful. | ||
665 | */ | ||
666 | static inline int audit_expand(struct audit_buffer *ab, int extra) | ||
667 | { | ||
668 | struct sk_buff *skb = ab->skb; | ||
669 | int ret = pskb_expand_head(skb, skb_headroom(skb), extra, | ||
670 | GFP_ATOMIC); | ||
671 | if (ret < 0) { | ||
672 | audit_log_lost("out of memory in audit_expand"); | ||
673 | return 0; | ||
674 | } | ||
675 | return skb_tailroom(skb); | ||
676 | } | ||
680 | 677 | ||
681 | /* Format an audit message into the audit buffer. If there isn't enough | 678 | /* Format an audit message into the audit buffer. If there isn't enough |
682 | * room in the audit buffer, more room will be allocated and vsnprint | 679 | * room in the audit buffer, more room will be allocated and vsnprint |
@@ -686,26 +683,34 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt, | |||
686 | va_list args) | 683 | va_list args) |
687 | { | 684 | { |
688 | int len, avail; | 685 | int len, avail; |
686 | struct sk_buff *skb; | ||
687 | va_list args2; | ||
689 | 688 | ||
690 | if (!ab) | 689 | if (!ab) |
691 | return; | 690 | return; |
692 | 691 | ||
693 | avail = sizeof(ab->tmp) - ab->len; | 692 | BUG_ON(!ab->skb); |
694 | if (avail <= 0) { | 693 | skb = ab->skb; |
695 | audit_log_move(ab); | 694 | avail = skb_tailroom(skb); |
696 | avail = sizeof(ab->tmp) - ab->len; | 695 | if (avail == 0) { |
696 | avail = audit_expand(ab, AUDIT_BUFSIZ); | ||
697 | if (!avail) | ||
698 | goto out; | ||
697 | } | 699 | } |
698 | len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); | 700 | va_copy(args2, args); |
701 | len = vsnprintf(skb->tail, avail, fmt, args); | ||
699 | if (len >= avail) { | 702 | if (len >= avail) { |
700 | /* The printk buffer is 1024 bytes long, so if we get | 703 | /* The printk buffer is 1024 bytes long, so if we get |
701 | * here and AUDIT_BUFSIZ is at least 1024, then we can | 704 | * here and AUDIT_BUFSIZ is at least 1024, then we can |
702 | * log everything that printk could have logged. */ | 705 | * log everything that printk could have logged. */ |
703 | audit_log_move(ab); | 706 | avail = audit_expand(ab, max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail)); |
704 | avail = sizeof(ab->tmp) - ab->len; | 707 | if (!avail) |
705 | len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); | 708 | goto out; |
709 | len = vsnprintf(skb->tail, avail, fmt, args2); | ||
706 | } | 710 | } |
707 | ab->len += (len < avail) ? len : avail; | 711 | skb_put(skb, (len < avail) ? len : avail); |
708 | ab->total += (len < avail) ? len : avail; | 712 | out: |
713 | return; | ||
709 | } | 714 | } |
710 | 715 | ||
711 | /* Format a message into the audit buffer. All the work is done in | 716 | /* Format a message into the audit buffer. All the work is done in |
@@ -751,27 +756,26 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, | |||
751 | struct dentry *dentry, struct vfsmount *vfsmnt) | 756 | struct dentry *dentry, struct vfsmount *vfsmnt) |
752 | { | 757 | { |
753 | char *p; | 758 | char *p; |
759 | struct sk_buff *skb = ab->skb; | ||
754 | int len, avail; | 760 | int len, avail; |
755 | 761 | ||
756 | if (prefix) audit_log_format(ab, " %s", prefix); | 762 | if (prefix) |
763 | audit_log_format(ab, " %s", prefix); | ||
757 | 764 | ||
758 | if (ab->len > 128) | 765 | avail = skb_tailroom(skb); |
759 | audit_log_move(ab); | 766 | p = d_path(dentry, vfsmnt, skb->tail, avail); |
760 | avail = sizeof(ab->tmp) - ab->len; | ||
761 | p = d_path(dentry, vfsmnt, ab->tmp + ab->len, avail); | ||
762 | if (IS_ERR(p)) { | 767 | if (IS_ERR(p)) { |
763 | /* FIXME: can we save some information here? */ | 768 | /* FIXME: can we save some information here? */ |
764 | audit_log_format(ab, "<toolong>"); | 769 | audit_log_format(ab, "<toolong>"); |
765 | } else { | 770 | } else { |
766 | /* path isn't at start of buffer */ | 771 | /* path isn't at start of buffer */ |
767 | len = (ab->tmp + sizeof(ab->tmp) - 1) - p; | 772 | len = ((char *)skb->tail + avail - 1) - p; |
768 | memmove(ab->tmp + ab->len, p, len); | 773 | memmove(skb->tail, p, len); |
769 | ab->len += len; | 774 | skb_put(skb, len); |
770 | ab->total += len; | ||
771 | } | 775 | } |
772 | } | 776 | } |
773 | 777 | ||
774 | /* Remove queued messages from the audit_txlist and send them to userspace. */ | 778 | /* Remove queued messages from the audit_txlist and send them to user space. */ |
775 | static void audit_tasklet_handler(unsigned long arg) | 779 | static void audit_tasklet_handler(unsigned long arg) |
776 | { | 780 | { |
777 | LIST_HEAD(list); | 781 | LIST_HEAD(list); |
@@ -812,26 +816,16 @@ static void audit_log_end_irq(struct audit_buffer *ab) | |||
812 | * be called in an irq context. */ | 816 | * be called in an irq context. */ |
813 | static void audit_log_end_fast(struct audit_buffer *ab) | 817 | static void audit_log_end_fast(struct audit_buffer *ab) |
814 | { | 818 | { |
815 | unsigned long flags; | ||
816 | |||
817 | BUG_ON(in_irq()); | 819 | BUG_ON(in_irq()); |
818 | if (!ab) | 820 | if (!ab) |
819 | return; | 821 | return; |
820 | if (!audit_rate_check()) { | 822 | if (!audit_rate_check()) { |
821 | audit_log_lost("rate limit exceeded"); | 823 | audit_log_lost("rate limit exceeded"); |
822 | } else { | 824 | } else { |
823 | audit_log_move(ab); | ||
824 | if (audit_log_drain(ab)) | 825 | if (audit_log_drain(ab)) |
825 | return; | 826 | return; |
826 | } | 827 | } |
827 | 828 | audit_buffer_free(ab); | |
828 | atomic_dec(&audit_backlog); | ||
829 | spin_lock_irqsave(&audit_freelist_lock, flags); | ||
830 | if (++audit_freelist_count > AUDIT_MAXFREE) | ||
831 | kfree(ab); | ||
832 | else | ||
833 | list_add(&ab->list, &audit_freelist); | ||
834 | spin_unlock_irqrestore(&audit_freelist_lock, flags); | ||
835 | } | 829 | } |
836 | 830 | ||
837 | /* Send or queue the message in the audit buffer, depending on the | 831 | /* Send or queue the message in the audit buffer, depending on the |
@@ -848,12 +842,12 @@ void audit_log_end(struct audit_buffer *ab) | |||
848 | /* Log an audit record. This is a convenience function that calls | 842 | /* Log an audit record. This is a convenience function that calls |
849 | * audit_log_start, audit_log_vformat, and audit_log_end. It may be | 843 | * audit_log_start, audit_log_vformat, and audit_log_end. It may be |
850 | * called in any context. */ | 844 | * called in any context. */ |
851 | void audit_log(struct audit_context *ctx, const char *fmt, ...) | 845 | void audit_log(struct audit_context *ctx, int type, const char *fmt, ...) |
852 | { | 846 | { |
853 | struct audit_buffer *ab; | 847 | struct audit_buffer *ab; |
854 | va_list args; | 848 | va_list args; |
855 | 849 | ||
856 | ab = audit_log_start(ctx); | 850 | ab = audit_log_start(ctx, type); |
857 | if (ab) { | 851 | if (ab) { |
858 | va_start(args, fmt); | 852 | va_start(args, fmt); |
859 | audit_log_vformat(ab, fmt, args); | 853 | audit_log_vformat(ab, fmt, args); |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 37b3ac94bc47..773d28a3f701 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -226,7 +226,6 @@ static inline int audit_del_rule(struct audit_rule *rule, | |||
226 | return -EFAULT; /* No matching rule */ | 226 | return -EFAULT; /* No matching rule */ |
227 | } | 227 | } |
228 | 228 | ||
229 | #ifdef CONFIG_NET | ||
230 | /* Copy rule from user-space to kernel-space. Called during | 229 | /* Copy rule from user-space to kernel-space. Called during |
231 | * AUDIT_ADD. */ | 230 | * AUDIT_ADD. */ |
232 | static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) | 231 | static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) |
@@ -287,7 +286,8 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | |||
287 | err = audit_add_rule(entry, &audit_entlist); | 286 | err = audit_add_rule(entry, &audit_entlist); |
288 | if (!err && (flags & AUDIT_AT_EXIT)) | 287 | if (!err && (flags & AUDIT_AT_EXIT)) |
289 | err = audit_add_rule(entry, &audit_extlist); | 288 | err = audit_add_rule(entry, &audit_extlist); |
290 | audit_log(NULL, "auid %u added an audit rule\n", loginuid); | 289 | audit_log(NULL, AUDIT_CONFIG_CHANGE, |
290 | "auid %u added an audit rule\n", loginuid); | ||
291 | break; | 291 | break; |
292 | case AUDIT_DEL: | 292 | case AUDIT_DEL: |
293 | flags =((struct audit_rule *)data)->flags; | 293 | flags =((struct audit_rule *)data)->flags; |
@@ -297,7 +297,8 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | |||
297 | err = audit_del_rule(data, &audit_entlist); | 297 | err = audit_del_rule(data, &audit_entlist); |
298 | if (!err && (flags & AUDIT_AT_EXIT)) | 298 | if (!err && (flags & AUDIT_AT_EXIT)) |
299 | err = audit_del_rule(data, &audit_extlist); | 299 | err = audit_del_rule(data, &audit_extlist); |
300 | audit_log(NULL, "auid %u removed an audit rule\n", loginuid); | 300 | audit_log(NULL, AUDIT_CONFIG_CHANGE, |
301 | "auid %u removed an audit rule\n", loginuid); | ||
301 | break; | 302 | break; |
302 | default: | 303 | default: |
303 | return -EINVAL; | 304 | return -EINVAL; |
@@ -305,7 +306,6 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | |||
305 | 306 | ||
306 | return err; | 307 | return err; |
307 | } | 308 | } |
308 | #endif | ||
309 | 309 | ||
310 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 | 310 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 |
311 | * otherwise. */ | 311 | * otherwise. */ |
@@ -444,7 +444,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk) | |||
444 | 444 | ||
445 | /* At syscall entry and exit time, this filter is called if the | 445 | /* At syscall entry and exit time, this filter is called if the |
446 | * audit_state is not low enough that auditing cannot take place, but is | 446 | * audit_state is not low enough that auditing cannot take place, but is |
447 | * also not high enough that we already know we have to write and audit | 447 | * also not high enough that we already know we have to write an audit |
448 | * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT). | 448 | * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT). |
449 | */ | 449 | */ |
450 | static enum audit_state audit_filter_syscall(struct task_struct *tsk, | 450 | static enum audit_state audit_filter_syscall(struct task_struct *tsk, |
@@ -650,7 +650,7 @@ static void audit_log_exit(struct audit_context *context) | |||
650 | int i; | 650 | int i; |
651 | struct audit_buffer *ab; | 651 | struct audit_buffer *ab; |
652 | 652 | ||
653 | ab = audit_log_start(context); | 653 | ab = audit_log_start(context, AUDIT_SYSCALL); |
654 | if (!ab) | 654 | if (!ab) |
655 | return; /* audit_panic has been called */ | 655 | return; /* audit_panic has been called */ |
656 | audit_log_format(ab, "syscall=%d", context->major); | 656 | audit_log_format(ab, "syscall=%d", context->major); |
@@ -682,28 +682,28 @@ static void audit_log_exit(struct audit_context *context) | |||
682 | while (context->aux) { | 682 | while (context->aux) { |
683 | struct audit_aux_data *aux; | 683 | struct audit_aux_data *aux; |
684 | 684 | ||
685 | ab = audit_log_start(context); | 685 | aux = context->aux; |
686 | |||
687 | ab = audit_log_start(context, aux->type); | ||
686 | if (!ab) | 688 | if (!ab) |
687 | continue; /* audit_panic has been called */ | 689 | continue; /* audit_panic has been called */ |
688 | 690 | ||
689 | aux = context->aux; | ||
690 | context->aux = aux->next; | ||
691 | |||
692 | audit_log_format(ab, "auxitem=%d", aux->type); | ||
693 | switch (aux->type) { | 691 | switch (aux->type) { |
694 | case AUDIT_AUX_IPCPERM: { | 692 | case AUDIT_IPC: { |
695 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 693 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
696 | audit_log_format(ab, | 694 | audit_log_format(ab, |
697 | " qbytes=%lx uid=%d gid=%d mode=%x", | 695 | " qbytes=%lx iuid=%d igid=%d mode=%x", |
698 | axi->qbytes, axi->uid, axi->gid, axi->mode); | 696 | axi->qbytes, axi->uid, axi->gid, axi->mode); |
699 | } | 697 | } |
700 | } | 698 | } |
701 | audit_log_end(ab); | 699 | audit_log_end(ab); |
700 | |||
701 | context->aux = aux->next; | ||
702 | kfree(aux); | 702 | kfree(aux); |
703 | } | 703 | } |
704 | 704 | ||
705 | for (i = 0; i < context->name_count; i++) { | 705 | for (i = 0; i < context->name_count; i++) { |
706 | ab = audit_log_start(context); | 706 | ab = audit_log_start(context, AUDIT_PATH); |
707 | if (!ab) | 707 | if (!ab) |
708 | continue; /* audit_panic has been called */ | 708 | continue; /* audit_panic has been called */ |
709 | audit_log_format(ab, "item=%d", i); | 709 | audit_log_format(ab, "item=%d", i); |
@@ -713,7 +713,7 @@ static void audit_log_exit(struct audit_context *context) | |||
713 | } | 713 | } |
714 | if (context->names[i].ino != (unsigned long)-1) | 714 | if (context->names[i].ino != (unsigned long)-1) |
715 | audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o" | 715 | audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o" |
716 | " uid=%d gid=%d rdev=%02x:%02x", | 716 | " ouid=%d ogid=%d rdev=%02x:%02x", |
717 | context->names[i].ino, | 717 | context->names[i].ino, |
718 | MAJOR(context->names[i].dev), | 718 | MAJOR(context->names[i].dev), |
719 | MINOR(context->names[i].dev), | 719 | MINOR(context->names[i].dev), |
@@ -750,7 +750,7 @@ void audit_free(struct task_struct *tsk) | |||
750 | /* Compute a serial number for the audit record. Audit records are | 750 | /* Compute a serial number for the audit record. Audit records are |
751 | * written to user-space as soon as they are generated, so a complete | 751 | * written to user-space as soon as they are generated, so a complete |
752 | * audit record may be written in several pieces. The timestamp of the | 752 | * audit record may be written in several pieces. The timestamp of the |
753 | * record and this serial number are used by the user-space daemon to | 753 | * record and this serial number are used by the user-space tools to |
754 | * determine which pieces belong to the same audit record. The | 754 | * determine which pieces belong to the same audit record. The |
755 | * (timestamp,serial) tuple is unique for each syscall and is live from | 755 | * (timestamp,serial) tuple is unique for each syscall and is live from |
756 | * syscall entry to syscall exit. | 756 | * syscall entry to syscall exit. |
@@ -994,7 +994,7 @@ void audit_inode(const char *name, const struct inode *inode) | |||
994 | context->names[idx].rdev = inode->i_rdev; | 994 | context->names[idx].rdev = inode->i_rdev; |
995 | } | 995 | } |
996 | 996 | ||
997 | void audit_get_stamp(struct audit_context *ctx, | 997 | int audit_get_stamp(struct audit_context *ctx, |
998 | struct timespec *t, unsigned int *serial) | 998 | struct timespec *t, unsigned int *serial) |
999 | { | 999 | { |
1000 | if (ctx) { | 1000 | if (ctx) { |
@@ -1002,26 +1002,22 @@ void audit_get_stamp(struct audit_context *ctx, | |||
1002 | t->tv_nsec = ctx->ctime.tv_nsec; | 1002 | t->tv_nsec = ctx->ctime.tv_nsec; |
1003 | *serial = ctx->serial; | 1003 | *serial = ctx->serial; |
1004 | ctx->auditable = 1; | 1004 | ctx->auditable = 1; |
1005 | } else { | 1005 | return 1; |
1006 | *t = CURRENT_TIME; | ||
1007 | *serial = 0; | ||
1008 | } | 1006 | } |
1007 | return 0; | ||
1009 | } | 1008 | } |
1010 | 1009 | ||
1011 | extern int audit_set_type(struct audit_buffer *ab, int type); | ||
1012 | |||
1013 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) | 1010 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) |
1014 | { | 1011 | { |
1015 | if (task->audit_context) { | 1012 | if (task->audit_context) { |
1016 | struct audit_buffer *ab; | 1013 | struct audit_buffer *ab; |
1017 | 1014 | ||
1018 | ab = audit_log_start(NULL); | 1015 | ab = audit_log_start(NULL, AUDIT_LOGIN); |
1019 | if (ab) { | 1016 | if (ab) { |
1020 | audit_log_format(ab, "login pid=%d uid=%u " | 1017 | audit_log_format(ab, "login pid=%d uid=%u " |
1021 | "old loginuid=%u new loginuid=%u", | 1018 | "old loginuid=%u new loginuid=%u", |
1022 | task->pid, task->uid, | 1019 | task->pid, task->uid, |
1023 | task->audit_context->loginuid, loginuid); | 1020 | task->audit_context->loginuid, loginuid); |
1024 | audit_set_type(ab, AUDIT_LOGIN); | ||
1025 | audit_log_end(ab); | 1021 | audit_log_end(ab); |
1026 | } | 1022 | } |
1027 | task->audit_context->loginuid = loginuid; | 1023 | task->audit_context->loginuid = loginuid; |
@@ -1051,8 +1047,27 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) | |||
1051 | ax->gid = gid; | 1047 | ax->gid = gid; |
1052 | ax->mode = mode; | 1048 | ax->mode = mode; |
1053 | 1049 | ||
1054 | ax->d.type = AUDIT_AUX_IPCPERM; | 1050 | ax->d.type = AUDIT_IPC; |
1055 | ax->d.next = context->aux; | 1051 | ax->d.next = context->aux; |
1056 | context->aux = (void *)ax; | 1052 | context->aux = (void *)ax; |
1057 | return 0; | 1053 | return 0; |
1058 | } | 1054 | } |
1055 | |||
1056 | void audit_signal_info(int sig, struct task_struct *t) | ||
1057 | { | ||
1058 | extern pid_t audit_sig_pid; | ||
1059 | extern uid_t audit_sig_uid; | ||
1060 | extern int audit_pid; | ||
1061 | |||
1062 | if (unlikely(audit_pid && t->pid == audit_pid)) { | ||
1063 | if (sig == SIGTERM || sig == SIGHUP) { | ||
1064 | struct audit_context *ctx = current->audit_context; | ||
1065 | audit_sig_pid = current->pid; | ||
1066 | if (ctx) | ||
1067 | audit_sig_uid = ctx->loginuid; | ||
1068 | else | ||
1069 | audit_sig_uid = current->uid; | ||
1070 | } | ||
1071 | } | ||
1072 | } | ||
1073 | |||
diff --git a/kernel/signal.c b/kernel/signal.c index 8f3debc77c5b..293e189d8bc3 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/ptrace.h> | 24 | #include <linux/ptrace.h> |
25 | #include <linux/posix-timers.h> | 25 | #include <linux/posix-timers.h> |
26 | #include <linux/signal.h> | 26 | #include <linux/signal.h> |
27 | #include <linux/audit.h> | ||
27 | #include <asm/param.h> | 28 | #include <asm/param.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
29 | #include <asm/unistd.h> | 30 | #include <asm/unistd.h> |
@@ -658,7 +659,11 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
658 | && (current->uid ^ t->suid) && (current->uid ^ t->uid) | 659 | && (current->uid ^ t->suid) && (current->uid ^ t->uid) |
659 | && !capable(CAP_KILL)) | 660 | && !capable(CAP_KILL)) |
660 | return error; | 661 | return error; |
661 | return security_task_kill(t, info, sig); | 662 | |
663 | error = security_task_kill(t, info, sig); | ||
664 | if (!error) | ||
665 | audit_signal_info(sig, t); /* Let audit system see the signal */ | ||
666 | return error; | ||
662 | } | 667 | } |
663 | 668 | ||
664 | /* forward decl */ | 669 | /* forward decl */ |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 85a6f66a873f..042f91e9f9d2 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -242,7 +242,7 @@ void __init avc_init(void) | |||
242 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), | 242 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), |
243 | 0, SLAB_PANIC, NULL, NULL); | 243 | 0, SLAB_PANIC, NULL, NULL); |
244 | 244 | ||
245 | audit_log(current->audit_context, "AVC INITIALIZED\n"); | 245 | audit_log(current->audit_context, AUDIT_KERNEL, "AVC INITIALIZED\n"); |
246 | } | 246 | } |
247 | 247 | ||
248 | int avc_get_hash_stats(char *page) | 248 | int avc_get_hash_stats(char *page) |
@@ -549,7 +549,7 @@ void avc_audit(u32 ssid, u32 tsid, | |||
549 | return; | 549 | return; |
550 | } | 550 | } |
551 | 551 | ||
552 | ab = audit_log_start(current->audit_context); | 552 | ab = audit_log_start(current->audit_context, AUDIT_AVC); |
553 | if (!ab) | 553 | if (!ab) |
554 | return; /* audit_panic has been called */ | 554 | return; /* audit_panic has been called */ |
555 | audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); | 555 | audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index aae1e794fe48..db845cbd5841 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3419,7 +3419,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | |||
3419 | err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm); | 3419 | err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm); |
3420 | if (err) { | 3420 | if (err) { |
3421 | if (err == -EINVAL) { | 3421 | if (err == -EINVAL) { |
3422 | audit_log(current->audit_context, | 3422 | audit_log(current->audit_context, AUDIT_SELINUX_ERR, |
3423 | "SELinux: unrecognized netlink message" | 3423 | "SELinux: unrecognized netlink message" |
3424 | " type=%hu for sclass=%hu\n", | 3424 | " type=%hu for sclass=%hu\n", |
3425 | nlh->nlmsg_type, isec->sclass); | 3425 | nlh->nlmsg_type, isec->sclass); |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index b3adb481bc25..67e77acc4795 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
@@ -97,6 +97,15 @@ static struct nlmsg_perm nlmsg_audit_perms[] = | |||
97 | { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, | 97 | { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, |
98 | { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, | 98 | { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, |
99 | { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | 99 | { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, |
100 | { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, | ||
101 | { AUDIT_USER_AUTH, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
102 | { AUDIT_USER_ACCT, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
103 | { AUDIT_USER_MGMT, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
104 | { AUDIT_CRED_ACQ, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
105 | { AUDIT_CRED_DISP, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
106 | { AUDIT_USER_START, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
107 | { AUDIT_USER_END, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
108 | { AUDIT_USER_AVC, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | ||
100 | }; | 109 | }; |
101 | 110 | ||
102 | 111 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 5a820cf88c9c..07fdf6ee6148 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -365,7 +365,7 @@ static int security_validtrans_handle_fail(struct context *ocontext, | |||
365 | goto out; | 365 | goto out; |
366 | if (context_struct_to_string(tcontext, &t, &tlen) < 0) | 366 | if (context_struct_to_string(tcontext, &t, &tlen) < 0) |
367 | goto out; | 367 | goto out; |
368 | audit_log(current->audit_context, | 368 | audit_log(current->audit_context, AUDIT_SELINUX_ERR, |
369 | "security_validate_transition: denied for" | 369 | "security_validate_transition: denied for" |
370 | " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", | 370 | " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", |
371 | o, n, t, policydb.p_class_val_to_name[tclass-1]); | 371 | o, n, t, policydb.p_class_val_to_name[tclass-1]); |
@@ -742,7 +742,7 @@ static int compute_sid_handle_invalid_context( | |||
742 | goto out; | 742 | goto out; |
743 | if (context_struct_to_string(newcontext, &n, &nlen) < 0) | 743 | if (context_struct_to_string(newcontext, &n, &nlen) < 0) |
744 | goto out; | 744 | goto out; |
745 | audit_log(current->audit_context, | 745 | audit_log(current->audit_context, AUDIT_SELINUX_ERR, |
746 | "security_compute_sid: invalid context %s" | 746 | "security_compute_sid: invalid context %s" |
747 | " for scontext=%s" | 747 | " for scontext=%s" |
748 | " tcontext=%s" | 748 | " tcontext=%s" |