diff options
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r-- | kernel/auditsc.c | 716 |
1 files changed, 577 insertions, 139 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 1c03a4ed1b27..ae40ac8c39e7 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. | 4 | * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. |
5 | * Copyright 2005 Hewlett-Packard Development Company, L.P. | 5 | * Copyright 2005 Hewlett-Packard Development Company, L.P. |
6 | * Copyright (C) 2005 IBM Corporation | 6 | * Copyright (C) 2005, 2006 IBM Corporation |
7 | * All Rights Reserved. | 7 | * All Rights Reserved. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
@@ -29,6 +29,9 @@ | |||
29 | * this file -- see entry.S) is based on a GPL'd patch written by | 29 | * this file -- see entry.S) is based on a GPL'd patch written by |
30 | * okir@suse.de and Copyright 2003 SuSE Linux AG. | 30 | * okir@suse.de and Copyright 2003 SuSE Linux AG. |
31 | * | 31 | * |
32 | * POSIX message queue support added by George Wilson <ltcgcw@us.ibm.com>, | ||
33 | * 2006. | ||
34 | * | ||
32 | * The support of additional filter rules compares (>, <, >=, <=) was | 35 | * The support of additional filter rules compares (>, <, >=, <=) was |
33 | * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005. | 36 | * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005. |
34 | * | 37 | * |
@@ -49,6 +52,7 @@ | |||
49 | #include <linux/module.h> | 52 | #include <linux/module.h> |
50 | #include <linux/mount.h> | 53 | #include <linux/mount.h> |
51 | #include <linux/socket.h> | 54 | #include <linux/socket.h> |
55 | #include <linux/mqueue.h> | ||
52 | #include <linux/audit.h> | 56 | #include <linux/audit.h> |
53 | #include <linux/personality.h> | 57 | #include <linux/personality.h> |
54 | #include <linux/time.h> | 58 | #include <linux/time.h> |
@@ -59,6 +63,8 @@ | |||
59 | #include <linux/list.h> | 63 | #include <linux/list.h> |
60 | #include <linux/tty.h> | 64 | #include <linux/tty.h> |
61 | #include <linux/selinux.h> | 65 | #include <linux/selinux.h> |
66 | #include <linux/binfmts.h> | ||
67 | #include <linux/syscalls.h> | ||
62 | 68 | ||
63 | #include "audit.h" | 69 | #include "audit.h" |
64 | 70 | ||
@@ -76,6 +82,9 @@ extern int audit_enabled; | |||
76 | * path_lookup. */ | 82 | * path_lookup. */ |
77 | #define AUDIT_NAMES_RESERVED 7 | 83 | #define AUDIT_NAMES_RESERVED 7 |
78 | 84 | ||
85 | /* Indicates that audit should log the full pathname. */ | ||
86 | #define AUDIT_NAME_FULL -1 | ||
87 | |||
79 | /* When fs/namei.c:getname() is called, we store the pointer in name and | 88 | /* When fs/namei.c:getname() is called, we store the pointer in name and |
80 | * we don't let putname() free it (instead we free all of the saved | 89 | * we don't let putname() free it (instead we free all of the saved |
81 | * pointers at syscall exit time). | 90 | * pointers at syscall exit time). |
@@ -83,8 +92,9 @@ extern int audit_enabled; | |||
83 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ | 92 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ |
84 | struct audit_names { | 93 | struct audit_names { |
85 | const char *name; | 94 | const char *name; |
95 | int name_len; /* number of name's characters to log */ | ||
96 | unsigned name_put; /* call __putname() for this name */ | ||
86 | unsigned long ino; | 97 | unsigned long ino; |
87 | unsigned long pino; | ||
88 | dev_t dev; | 98 | dev_t dev; |
89 | umode_t mode; | 99 | umode_t mode; |
90 | uid_t uid; | 100 | uid_t uid; |
@@ -100,6 +110,33 @@ struct audit_aux_data { | |||
100 | 110 | ||
101 | #define AUDIT_AUX_IPCPERM 0 | 111 | #define AUDIT_AUX_IPCPERM 0 |
102 | 112 | ||
113 | struct audit_aux_data_mq_open { | ||
114 | struct audit_aux_data d; | ||
115 | int oflag; | ||
116 | mode_t mode; | ||
117 | struct mq_attr attr; | ||
118 | }; | ||
119 | |||
120 | struct audit_aux_data_mq_sendrecv { | ||
121 | struct audit_aux_data d; | ||
122 | mqd_t mqdes; | ||
123 | size_t msg_len; | ||
124 | unsigned int msg_prio; | ||
125 | struct timespec abs_timeout; | ||
126 | }; | ||
127 | |||
128 | struct audit_aux_data_mq_notify { | ||
129 | struct audit_aux_data d; | ||
130 | mqd_t mqdes; | ||
131 | struct sigevent notification; | ||
132 | }; | ||
133 | |||
134 | struct audit_aux_data_mq_getsetattr { | ||
135 | struct audit_aux_data d; | ||
136 | mqd_t mqdes; | ||
137 | struct mq_attr mqstat; | ||
138 | }; | ||
139 | |||
103 | struct audit_aux_data_ipcctl { | 140 | struct audit_aux_data_ipcctl { |
104 | struct audit_aux_data d; | 141 | struct audit_aux_data d; |
105 | struct ipc_perm p; | 142 | struct ipc_perm p; |
@@ -110,6 +147,13 @@ struct audit_aux_data_ipcctl { | |||
110 | u32 osid; | 147 | u32 osid; |
111 | }; | 148 | }; |
112 | 149 | ||
150 | struct audit_aux_data_execve { | ||
151 | struct audit_aux_data d; | ||
152 | int argc; | ||
153 | int envc; | ||
154 | char mem[0]; | ||
155 | }; | ||
156 | |||
113 | struct audit_aux_data_socketcall { | 157 | struct audit_aux_data_socketcall { |
114 | struct audit_aux_data d; | 158 | struct audit_aux_data d; |
115 | int nargs; | 159 | int nargs; |
@@ -142,13 +186,14 @@ struct audit_context { | |||
142 | int auditable; /* 1 if record should be written */ | 186 | int auditable; /* 1 if record should be written */ |
143 | int name_count; | 187 | int name_count; |
144 | struct audit_names names[AUDIT_NAMES]; | 188 | struct audit_names names[AUDIT_NAMES]; |
189 | char * filterkey; /* key for rule that triggered record */ | ||
145 | struct dentry * pwd; | 190 | struct dentry * pwd; |
146 | struct vfsmount * pwdmnt; | 191 | struct vfsmount * pwdmnt; |
147 | struct audit_context *previous; /* For nested syscalls */ | 192 | struct audit_context *previous; /* For nested syscalls */ |
148 | struct audit_aux_data *aux; | 193 | struct audit_aux_data *aux; |
149 | 194 | ||
150 | /* Save things to print about task_struct */ | 195 | /* Save things to print about task_struct */ |
151 | pid_t pid; | 196 | pid_t pid, ppid; |
152 | uid_t uid, euid, suid, fsuid; | 197 | uid_t uid, euid, suid, fsuid; |
153 | gid_t gid, egid, sgid, fsgid; | 198 | gid_t gid, egid, sgid, fsgid; |
154 | unsigned long personality; | 199 | unsigned long personality; |
@@ -160,12 +205,13 @@ struct audit_context { | |||
160 | #endif | 205 | #endif |
161 | }; | 206 | }; |
162 | 207 | ||
163 | 208 | /* Determine if any context name data matches a rule's watch data */ | |
164 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 | 209 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 |
165 | * otherwise. */ | 210 | * otherwise. */ |
166 | static int audit_filter_rules(struct task_struct *tsk, | 211 | static int audit_filter_rules(struct task_struct *tsk, |
167 | struct audit_krule *rule, | 212 | struct audit_krule *rule, |
168 | struct audit_context *ctx, | 213 | struct audit_context *ctx, |
214 | struct audit_names *name, | ||
169 | enum audit_state *state) | 215 | enum audit_state *state) |
170 | { | 216 | { |
171 | int i, j, need_sid = 1; | 217 | int i, j, need_sid = 1; |
@@ -179,6 +225,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
179 | case AUDIT_PID: | 225 | case AUDIT_PID: |
180 | result = audit_comparator(tsk->pid, f->op, f->val); | 226 | result = audit_comparator(tsk->pid, f->op, f->val); |
181 | break; | 227 | break; |
228 | case AUDIT_PPID: | ||
229 | if (ctx) | ||
230 | result = audit_comparator(ctx->ppid, f->op, f->val); | ||
231 | break; | ||
182 | case AUDIT_UID: | 232 | case AUDIT_UID: |
183 | result = audit_comparator(tsk->uid, f->op, f->val); | 233 | result = audit_comparator(tsk->uid, f->op, f->val); |
184 | break; | 234 | break; |
@@ -224,7 +274,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
224 | } | 274 | } |
225 | break; | 275 | break; |
226 | case AUDIT_DEVMAJOR: | 276 | case AUDIT_DEVMAJOR: |
227 | if (ctx) { | 277 | if (name) |
278 | result = audit_comparator(MAJOR(name->dev), | ||
279 | f->op, f->val); | ||
280 | else if (ctx) { | ||
228 | for (j = 0; j < ctx->name_count; j++) { | 281 | for (j = 0; j < ctx->name_count; j++) { |
229 | if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { | 282 | if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { |
230 | ++result; | 283 | ++result; |
@@ -234,7 +287,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
234 | } | 287 | } |
235 | break; | 288 | break; |
236 | case AUDIT_DEVMINOR: | 289 | case AUDIT_DEVMINOR: |
237 | if (ctx) { | 290 | if (name) |
291 | result = audit_comparator(MINOR(name->dev), | ||
292 | f->op, f->val); | ||
293 | else if (ctx) { | ||
238 | for (j = 0; j < ctx->name_count; j++) { | 294 | for (j = 0; j < ctx->name_count; j++) { |
239 | if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { | 295 | if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { |
240 | ++result; | 296 | ++result; |
@@ -244,26 +300,32 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
244 | } | 300 | } |
245 | break; | 301 | break; |
246 | case AUDIT_INODE: | 302 | case AUDIT_INODE: |
247 | if (ctx) { | 303 | if (name) |
304 | result = (name->ino == f->val); | ||
305 | else if (ctx) { | ||
248 | for (j = 0; j < ctx->name_count; j++) { | 306 | for (j = 0; j < ctx->name_count; j++) { |
249 | if (audit_comparator(ctx->names[j].ino, f->op, f->val) || | 307 | if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { |
250 | audit_comparator(ctx->names[j].pino, f->op, f->val)) { | ||
251 | ++result; | 308 | ++result; |
252 | break; | 309 | break; |
253 | } | 310 | } |
254 | } | 311 | } |
255 | } | 312 | } |
256 | break; | 313 | break; |
314 | case AUDIT_WATCH: | ||
315 | if (name && rule->watch->ino != (unsigned long)-1) | ||
316 | result = (name->dev == rule->watch->dev && | ||
317 | name->ino == rule->watch->ino); | ||
318 | break; | ||
257 | case AUDIT_LOGINUID: | 319 | case AUDIT_LOGINUID: |
258 | result = 0; | 320 | result = 0; |
259 | if (ctx) | 321 | if (ctx) |
260 | result = audit_comparator(ctx->loginuid, f->op, f->val); | 322 | result = audit_comparator(ctx->loginuid, f->op, f->val); |
261 | break; | 323 | break; |
262 | case AUDIT_SE_USER: | 324 | case AUDIT_SUBJ_USER: |
263 | case AUDIT_SE_ROLE: | 325 | case AUDIT_SUBJ_ROLE: |
264 | case AUDIT_SE_TYPE: | 326 | case AUDIT_SUBJ_TYPE: |
265 | case AUDIT_SE_SEN: | 327 | case AUDIT_SUBJ_SEN: |
266 | case AUDIT_SE_CLR: | 328 | case AUDIT_SUBJ_CLR: |
267 | /* NOTE: this may return negative values indicating | 329 | /* NOTE: this may return negative values indicating |
268 | a temporary error. We simply treat this as a | 330 | a temporary error. We simply treat this as a |
269 | match for now to avoid losing information that | 331 | match for now to avoid losing information that |
@@ -280,6 +342,46 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
280 | ctx); | 342 | ctx); |
281 | } | 343 | } |
282 | break; | 344 | break; |
345 | case AUDIT_OBJ_USER: | ||
346 | case AUDIT_OBJ_ROLE: | ||
347 | case AUDIT_OBJ_TYPE: | ||
348 | case AUDIT_OBJ_LEV_LOW: | ||
349 | case AUDIT_OBJ_LEV_HIGH: | ||
350 | /* The above note for AUDIT_SUBJ_USER...AUDIT_SUBJ_CLR | ||
351 | also applies here */ | ||
352 | if (f->se_rule) { | ||
353 | /* Find files that match */ | ||
354 | if (name) { | ||
355 | result = selinux_audit_rule_match( | ||
356 | name->osid, f->type, f->op, | ||
357 | f->se_rule, ctx); | ||
358 | } else if (ctx) { | ||
359 | for (j = 0; j < ctx->name_count; j++) { | ||
360 | if (selinux_audit_rule_match( | ||
361 | ctx->names[j].osid, | ||
362 | f->type, f->op, | ||
363 | f->se_rule, ctx)) { | ||
364 | ++result; | ||
365 | break; | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | /* Find ipc objects that match */ | ||
370 | if (ctx) { | ||
371 | struct audit_aux_data *aux; | ||
372 | for (aux = ctx->aux; aux; | ||
373 | aux = aux->next) { | ||
374 | if (aux->type == AUDIT_IPC) { | ||
375 | struct audit_aux_data_ipcctl *axi = (void *)aux; | ||
376 | if (selinux_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) { | ||
377 | ++result; | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | break; | ||
283 | case AUDIT_ARG0: | 385 | case AUDIT_ARG0: |
284 | case AUDIT_ARG1: | 386 | case AUDIT_ARG1: |
285 | case AUDIT_ARG2: | 387 | case AUDIT_ARG2: |
@@ -287,14 +389,19 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
287 | if (ctx) | 389 | if (ctx) |
288 | result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val); | 390 | result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val); |
289 | break; | 391 | break; |
392 | case AUDIT_FILTERKEY: | ||
393 | /* ignore this field for filtering */ | ||
394 | result = 1; | ||
395 | break; | ||
290 | } | 396 | } |
291 | 397 | ||
292 | if (!result) | 398 | if (!result) |
293 | return 0; | 399 | return 0; |
294 | } | 400 | } |
401 | if (rule->filterkey) | ||
402 | ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); | ||
295 | switch (rule->action) { | 403 | switch (rule->action) { |
296 | case AUDIT_NEVER: *state = AUDIT_DISABLED; break; | 404 | case AUDIT_NEVER: *state = AUDIT_DISABLED; break; |
297 | case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT; break; | ||
298 | case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; | 405 | case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; |
299 | } | 406 | } |
300 | return 1; | 407 | return 1; |
@@ -311,7 +418,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk) | |||
311 | 418 | ||
312 | rcu_read_lock(); | 419 | rcu_read_lock(); |
313 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { | 420 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { |
314 | if (audit_filter_rules(tsk, &e->rule, NULL, &state)) { | 421 | if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) { |
315 | rcu_read_unlock(); | 422 | rcu_read_unlock(); |
316 | return state; | 423 | return state; |
317 | } | 424 | } |
@@ -341,8 +448,47 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, | |||
341 | int bit = AUDIT_BIT(ctx->major); | 448 | int bit = AUDIT_BIT(ctx->major); |
342 | 449 | ||
343 | list_for_each_entry_rcu(e, list, list) { | 450 | list_for_each_entry_rcu(e, list, list) { |
344 | if ((e->rule.mask[word] & bit) == bit | 451 | if ((e->rule.mask[word] & bit) == bit && |
345 | && audit_filter_rules(tsk, &e->rule, ctx, &state)) { | 452 | audit_filter_rules(tsk, &e->rule, ctx, NULL, |
453 | &state)) { | ||
454 | rcu_read_unlock(); | ||
455 | return state; | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | rcu_read_unlock(); | ||
460 | return AUDIT_BUILD_CONTEXT; | ||
461 | } | ||
462 | |||
463 | /* At syscall exit time, this filter is called if any audit_names[] have been | ||
464 | * collected during syscall processing. We only check rules in sublists at hash | ||
465 | * buckets applicable to the inode numbers in audit_names[]. | ||
466 | * Regarding audit_state, same rules apply as for audit_filter_syscall(). | ||
467 | */ | ||
468 | enum audit_state audit_filter_inodes(struct task_struct *tsk, | ||
469 | struct audit_context *ctx) | ||
470 | { | ||
471 | int i; | ||
472 | struct audit_entry *e; | ||
473 | enum audit_state state; | ||
474 | |||
475 | if (audit_pid && tsk->tgid == audit_pid) | ||
476 | return AUDIT_DISABLED; | ||
477 | |||
478 | rcu_read_lock(); | ||
479 | for (i = 0; i < ctx->name_count; i++) { | ||
480 | int word = AUDIT_WORD(ctx->major); | ||
481 | int bit = AUDIT_BIT(ctx->major); | ||
482 | struct audit_names *n = &ctx->names[i]; | ||
483 | int h = audit_hash_ino((u32)n->ino); | ||
484 | struct list_head *list = &audit_inode_hash[h]; | ||
485 | |||
486 | if (list_empty(list)) | ||
487 | continue; | ||
488 | |||
489 | list_for_each_entry_rcu(e, list, list) { | ||
490 | if ((e->rule.mask[word] & bit) == bit && | ||
491 | audit_filter_rules(tsk, &e->rule, ctx, n, &state)) { | ||
346 | rcu_read_unlock(); | 492 | rcu_read_unlock(); |
347 | return state; | 493 | return state; |
348 | } | 494 | } |
@@ -352,6 +498,11 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, | |||
352 | return AUDIT_BUILD_CONTEXT; | 498 | return AUDIT_BUILD_CONTEXT; |
353 | } | 499 | } |
354 | 500 | ||
501 | void audit_set_auditable(struct audit_context *ctx) | ||
502 | { | ||
503 | ctx->auditable = 1; | ||
504 | } | ||
505 | |||
355 | static inline struct audit_context *audit_get_context(struct task_struct *tsk, | 506 | static inline struct audit_context *audit_get_context(struct task_struct *tsk, |
356 | int return_valid, | 507 | int return_valid, |
357 | int return_code) | 508 | int return_code) |
@@ -365,12 +516,22 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, | |||
365 | 516 | ||
366 | if (context->in_syscall && !context->auditable) { | 517 | if (context->in_syscall && !context->auditable) { |
367 | enum audit_state state; | 518 | enum audit_state state; |
519 | |||
368 | state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); | 520 | state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); |
521 | if (state == AUDIT_RECORD_CONTEXT) { | ||
522 | context->auditable = 1; | ||
523 | goto get_context; | ||
524 | } | ||
525 | |||
526 | state = audit_filter_inodes(tsk, context); | ||
369 | if (state == AUDIT_RECORD_CONTEXT) | 527 | if (state == AUDIT_RECORD_CONTEXT) |
370 | context->auditable = 1; | 528 | context->auditable = 1; |
529 | |||
371 | } | 530 | } |
372 | 531 | ||
532 | get_context: | ||
373 | context->pid = tsk->pid; | 533 | context->pid = tsk->pid; |
534 | context->ppid = sys_getppid(); /* sic. tsk == current in all cases */ | ||
374 | context->uid = tsk->uid; | 535 | context->uid = tsk->uid; |
375 | context->gid = tsk->gid; | 536 | context->gid = tsk->gid; |
376 | context->euid = tsk->euid; | 537 | context->euid = tsk->euid; |
@@ -413,7 +574,7 @@ static inline void audit_free_names(struct audit_context *context) | |||
413 | #endif | 574 | #endif |
414 | 575 | ||
415 | for (i = 0; i < context->name_count; i++) { | 576 | for (i = 0; i < context->name_count; i++) { |
416 | if (context->names[i].name) | 577 | if (context->names[i].name && context->names[i].name_put) |
417 | __putname(context->names[i].name); | 578 | __putname(context->names[i].name); |
418 | } | 579 | } |
419 | context->name_count = 0; | 580 | context->name_count = 0; |
@@ -513,6 +674,7 @@ static inline void audit_free_context(struct audit_context *context) | |||
513 | } | 674 | } |
514 | audit_free_names(context); | 675 | audit_free_names(context); |
515 | audit_free_aux(context); | 676 | audit_free_aux(context); |
677 | kfree(context->filterkey); | ||
516 | kfree(context); | 678 | kfree(context); |
517 | context = previous; | 679 | context = previous; |
518 | } while (context); | 680 | } while (context); |
@@ -544,8 +706,7 @@ static void audit_log_task_context(struct audit_buffer *ab) | |||
544 | return; | 706 | return; |
545 | 707 | ||
546 | error_path: | 708 | error_path: |
547 | if (ctx) | 709 | kfree(ctx); |
548 | kfree(ctx); | ||
549 | audit_panic("error in audit_log_task_context"); | 710 | audit_panic("error in audit_log_task_context"); |
550 | return; | 711 | return; |
551 | } | 712 | } |
@@ -606,7 +767,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
606 | tty = "(none)"; | 767 | tty = "(none)"; |
607 | audit_log_format(ab, | 768 | audit_log_format(ab, |
608 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" | 769 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" |
609 | " pid=%d auid=%u uid=%u gid=%u" | 770 | " ppid=%d pid=%d auid=%u uid=%u gid=%u" |
610 | " euid=%u suid=%u fsuid=%u" | 771 | " euid=%u suid=%u fsuid=%u" |
611 | " egid=%u sgid=%u fsgid=%u tty=%s", | 772 | " egid=%u sgid=%u fsgid=%u tty=%s", |
612 | context->argv[0], | 773 | context->argv[0], |
@@ -614,6 +775,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
614 | context->argv[2], | 775 | context->argv[2], |
615 | context->argv[3], | 776 | context->argv[3], |
616 | context->name_count, | 777 | context->name_count, |
778 | context->ppid, | ||
617 | context->pid, | 779 | context->pid, |
618 | context->loginuid, | 780 | context->loginuid, |
619 | context->uid, | 781 | context->uid, |
@@ -621,6 +783,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
621 | context->euid, context->suid, context->fsuid, | 783 | context->euid, context->suid, context->fsuid, |
622 | context->egid, context->sgid, context->fsgid, tty); | 784 | context->egid, context->sgid, context->fsgid, tty); |
623 | audit_log_task_info(ab, tsk); | 785 | audit_log_task_info(ab, tsk); |
786 | if (context->filterkey) { | ||
787 | audit_log_format(ab, " key="); | ||
788 | audit_log_untrustedstring(ab, context->filterkey); | ||
789 | } else | ||
790 | audit_log_format(ab, " key=(null)"); | ||
624 | audit_log_end(ab); | 791 | audit_log_end(ab); |
625 | 792 | ||
626 | for (aux = context->aux; aux; aux = aux->next) { | 793 | for (aux = context->aux; aux; aux = aux->next) { |
@@ -630,11 +797,48 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
630 | continue; /* audit_panic has been called */ | 797 | continue; /* audit_panic has been called */ |
631 | 798 | ||
632 | switch (aux->type) { | 799 | switch (aux->type) { |
800 | case AUDIT_MQ_OPEN: { | ||
801 | struct audit_aux_data_mq_open *axi = (void *)aux; | ||
802 | audit_log_format(ab, | ||
803 | "oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld " | ||
804 | "mq_msgsize=%ld mq_curmsgs=%ld", | ||
805 | axi->oflag, axi->mode, axi->attr.mq_flags, | ||
806 | axi->attr.mq_maxmsg, axi->attr.mq_msgsize, | ||
807 | axi->attr.mq_curmsgs); | ||
808 | break; } | ||
809 | |||
810 | case AUDIT_MQ_SENDRECV: { | ||
811 | struct audit_aux_data_mq_sendrecv *axi = (void *)aux; | ||
812 | audit_log_format(ab, | ||
813 | "mqdes=%d msg_len=%zd msg_prio=%u " | ||
814 | "abs_timeout_sec=%ld abs_timeout_nsec=%ld", | ||
815 | axi->mqdes, axi->msg_len, axi->msg_prio, | ||
816 | axi->abs_timeout.tv_sec, axi->abs_timeout.tv_nsec); | ||
817 | break; } | ||
818 | |||
819 | case AUDIT_MQ_NOTIFY: { | ||
820 | struct audit_aux_data_mq_notify *axi = (void *)aux; | ||
821 | audit_log_format(ab, | ||
822 | "mqdes=%d sigev_signo=%d", | ||
823 | axi->mqdes, | ||
824 | axi->notification.sigev_signo); | ||
825 | break; } | ||
826 | |||
827 | case AUDIT_MQ_GETSETATTR: { | ||
828 | struct audit_aux_data_mq_getsetattr *axi = (void *)aux; | ||
829 | audit_log_format(ab, | ||
830 | "mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld " | ||
831 | "mq_curmsgs=%ld ", | ||
832 | axi->mqdes, | ||
833 | axi->mqstat.mq_flags, axi->mqstat.mq_maxmsg, | ||
834 | axi->mqstat.mq_msgsize, axi->mqstat.mq_curmsgs); | ||
835 | break; } | ||
836 | |||
633 | case AUDIT_IPC: { | 837 | case AUDIT_IPC: { |
634 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 838 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
635 | audit_log_format(ab, | 839 | audit_log_format(ab, |
636 | " qbytes=%lx iuid=%u igid=%u mode=%x", | 840 | "ouid=%u ogid=%u mode=%x", |
637 | axi->qbytes, axi->uid, axi->gid, axi->mode); | 841 | axi->uid, axi->gid, axi->mode); |
638 | if (axi->osid != 0) { | 842 | if (axi->osid != 0) { |
639 | char *ctx = NULL; | 843 | char *ctx = NULL; |
640 | u32 len; | 844 | u32 len; |
@@ -652,19 +856,18 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
652 | case AUDIT_IPC_SET_PERM: { | 856 | case AUDIT_IPC_SET_PERM: { |
653 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 857 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
654 | audit_log_format(ab, | 858 | audit_log_format(ab, |
655 | " new qbytes=%lx new iuid=%u new igid=%u new mode=%x", | 859 | "qbytes=%lx ouid=%u ogid=%u mode=%x", |
656 | axi->qbytes, axi->uid, axi->gid, axi->mode); | 860 | axi->qbytes, axi->uid, axi->gid, axi->mode); |
657 | if (axi->osid != 0) { | 861 | break; } |
658 | char *ctx = NULL; | 862 | |
659 | u32 len; | 863 | case AUDIT_EXECVE: { |
660 | if (selinux_ctxid_to_string( | 864 | struct audit_aux_data_execve *axi = (void *)aux; |
661 | axi->osid, &ctx, &len)) { | 865 | int i; |
662 | audit_log_format(ab, " osid=%u", | 866 | const char *p; |
663 | axi->osid); | 867 | for (i = 0, p = axi->mem; i < axi->argc; i++) { |
664 | call_panic = 1; | 868 | audit_log_format(ab, "a%d=", i); |
665 | } else | 869 | p = audit_log_untrustedstring(ab, p); |
666 | audit_log_format(ab, " obj=%s", ctx); | 870 | audit_log_format(ab, "\n"); |
667 | kfree(ctx); | ||
668 | } | 871 | } |
669 | break; } | 872 | break; } |
670 | 873 | ||
@@ -700,8 +903,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
700 | } | 903 | } |
701 | } | 904 | } |
702 | for (i = 0; i < context->name_count; i++) { | 905 | for (i = 0; i < context->name_count; i++) { |
703 | unsigned long ino = context->names[i].ino; | 906 | struct audit_names *n = &context->names[i]; |
704 | unsigned long pino = context->names[i].pino; | ||
705 | 907 | ||
706 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | 908 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); |
707 | if (!ab) | 909 | if (!ab) |
@@ -709,33 +911,47 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
709 | 911 | ||
710 | audit_log_format(ab, "item=%d", i); | 912 | audit_log_format(ab, "item=%d", i); |
711 | 913 | ||
712 | audit_log_format(ab, " name="); | 914 | if (n->name) { |
713 | if (context->names[i].name) | 915 | switch(n->name_len) { |
714 | audit_log_untrustedstring(ab, context->names[i].name); | 916 | case AUDIT_NAME_FULL: |
715 | else | 917 | /* log the full path */ |
716 | audit_log_format(ab, "(null)"); | 918 | audit_log_format(ab, " name="); |
717 | 919 | audit_log_untrustedstring(ab, n->name); | |
718 | if (pino != (unsigned long)-1) | 920 | break; |
719 | audit_log_format(ab, " parent=%lu", pino); | 921 | case 0: |
720 | if (ino != (unsigned long)-1) | 922 | /* name was specified as a relative path and the |
721 | audit_log_format(ab, " inode=%lu", ino); | 923 | * directory component is the cwd */ |
722 | if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1)) | 924 | audit_log_d_path(ab, " name=", context->pwd, |
723 | audit_log_format(ab, " dev=%02x:%02x mode=%#o" | 925 | context->pwdmnt); |
724 | " ouid=%u ogid=%u rdev=%02x:%02x", | 926 | break; |
725 | MAJOR(context->names[i].dev), | 927 | default: |
726 | MINOR(context->names[i].dev), | 928 | /* log the name's directory component */ |
727 | context->names[i].mode, | 929 | audit_log_format(ab, " name="); |
728 | context->names[i].uid, | 930 | audit_log_n_untrustedstring(ab, n->name_len, |
729 | context->names[i].gid, | 931 | n->name); |
730 | MAJOR(context->names[i].rdev), | 932 | } |
731 | MINOR(context->names[i].rdev)); | 933 | } else |
732 | if (context->names[i].osid != 0) { | 934 | audit_log_format(ab, " name=(null)"); |
935 | |||
936 | if (n->ino != (unsigned long)-1) { | ||
937 | audit_log_format(ab, " inode=%lu" | ||
938 | " dev=%02x:%02x mode=%#o" | ||
939 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
940 | n->ino, | ||
941 | MAJOR(n->dev), | ||
942 | MINOR(n->dev), | ||
943 | n->mode, | ||
944 | n->uid, | ||
945 | n->gid, | ||
946 | MAJOR(n->rdev), | ||
947 | MINOR(n->rdev)); | ||
948 | } | ||
949 | if (n->osid != 0) { | ||
733 | char *ctx = NULL; | 950 | char *ctx = NULL; |
734 | u32 len; | 951 | u32 len; |
735 | if (selinux_ctxid_to_string( | 952 | if (selinux_ctxid_to_string( |
736 | context->names[i].osid, &ctx, &len)) { | 953 | n->osid, &ctx, &len)) { |
737 | audit_log_format(ab, " osid=%u", | 954 | audit_log_format(ab, " osid=%u", n->osid); |
738 | context->names[i].osid); | ||
739 | call_panic = 2; | 955 | call_panic = 2; |
740 | } else | 956 | } else |
741 | audit_log_format(ab, " obj=%s", ctx); | 957 | audit_log_format(ab, " obj=%s", ctx); |
@@ -897,6 +1113,8 @@ void audit_syscall_exit(int valid, long return_code) | |||
897 | } else { | 1113 | } else { |
898 | audit_free_names(context); | 1114 | audit_free_names(context); |
899 | audit_free_aux(context); | 1115 | audit_free_aux(context); |
1116 | kfree(context->filterkey); | ||
1117 | context->filterkey = NULL; | ||
900 | tsk->audit_context = context; | 1118 | tsk->audit_context = context; |
901 | } | 1119 | } |
902 | } | 1120 | } |
@@ -908,11 +1126,11 @@ void audit_syscall_exit(int valid, long return_code) | |||
908 | * Add a name to the list of audit names for this context. | 1126 | * Add a name to the list of audit names for this context. |
909 | * Called from fs/namei.c:getname(). | 1127 | * Called from fs/namei.c:getname(). |
910 | */ | 1128 | */ |
911 | void audit_getname(const char *name) | 1129 | void __audit_getname(const char *name) |
912 | { | 1130 | { |
913 | struct audit_context *context = current->audit_context; | 1131 | struct audit_context *context = current->audit_context; |
914 | 1132 | ||
915 | if (!context || IS_ERR(name) || !name) | 1133 | if (IS_ERR(name) || !name) |
916 | return; | 1134 | return; |
917 | 1135 | ||
918 | if (!context->in_syscall) { | 1136 | if (!context->in_syscall) { |
@@ -925,6 +1143,8 @@ void audit_getname(const char *name) | |||
925 | } | 1143 | } |
926 | BUG_ON(context->name_count >= AUDIT_NAMES); | 1144 | BUG_ON(context->name_count >= AUDIT_NAMES); |
927 | context->names[context->name_count].name = name; | 1145 | context->names[context->name_count].name = name; |
1146 | context->names[context->name_count].name_len = AUDIT_NAME_FULL; | ||
1147 | context->names[context->name_count].name_put = 1; | ||
928 | context->names[context->name_count].ino = (unsigned long)-1; | 1148 | context->names[context->name_count].ino = (unsigned long)-1; |
929 | ++context->name_count; | 1149 | ++context->name_count; |
930 | if (!context->pwd) { | 1150 | if (!context->pwd) { |
@@ -991,11 +1211,10 @@ static void audit_inode_context(int idx, const struct inode *inode) | |||
991 | * audit_inode - store the inode and device from a lookup | 1211 | * audit_inode - store the inode and device from a lookup |
992 | * @name: name being audited | 1212 | * @name: name being audited |
993 | * @inode: inode being audited | 1213 | * @inode: inode being audited |
994 | * @flags: lookup flags (as used in path_lookup()) | ||
995 | * | 1214 | * |
996 | * Called from fs/namei.c:path_lookup(). | 1215 | * Called from fs/namei.c:path_lookup(). |
997 | */ | 1216 | */ |
998 | void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | 1217 | void __audit_inode(const char *name, const struct inode *inode) |
999 | { | 1218 | { |
1000 | int idx; | 1219 | int idx; |
1001 | struct audit_context *context = current->audit_context; | 1220 | struct audit_context *context = current->audit_context; |
@@ -1021,20 +1240,13 @@ void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | |||
1021 | ++context->ino_count; | 1240 | ++context->ino_count; |
1022 | #endif | 1241 | #endif |
1023 | } | 1242 | } |
1243 | context->names[idx].ino = inode->i_ino; | ||
1024 | context->names[idx].dev = inode->i_sb->s_dev; | 1244 | context->names[idx].dev = inode->i_sb->s_dev; |
1025 | context->names[idx].mode = inode->i_mode; | 1245 | context->names[idx].mode = inode->i_mode; |
1026 | context->names[idx].uid = inode->i_uid; | 1246 | context->names[idx].uid = inode->i_uid; |
1027 | context->names[idx].gid = inode->i_gid; | 1247 | context->names[idx].gid = inode->i_gid; |
1028 | context->names[idx].rdev = inode->i_rdev; | 1248 | context->names[idx].rdev = inode->i_rdev; |
1029 | audit_inode_context(idx, inode); | 1249 | audit_inode_context(idx, inode); |
1030 | if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && | ||
1031 | (strcmp(name, ".") != 0)) { | ||
1032 | context->names[idx].ino = (unsigned long)-1; | ||
1033 | context->names[idx].pino = inode->i_ino; | ||
1034 | } else { | ||
1035 | context->names[idx].ino = inode->i_ino; | ||
1036 | context->names[idx].pino = (unsigned long)-1; | ||
1037 | } | ||
1038 | } | 1250 | } |
1039 | 1251 | ||
1040 | /** | 1252 | /** |
@@ -1056,51 +1268,40 @@ void __audit_inode_child(const char *dname, const struct inode *inode, | |||
1056 | { | 1268 | { |
1057 | int idx; | 1269 | int idx; |
1058 | struct audit_context *context = current->audit_context; | 1270 | struct audit_context *context = current->audit_context; |
1271 | const char *found_name = NULL; | ||
1272 | int dirlen = 0; | ||
1059 | 1273 | ||
1060 | if (!context->in_syscall) | 1274 | if (!context->in_syscall) |
1061 | return; | 1275 | return; |
1062 | 1276 | ||
1063 | /* determine matching parent */ | 1277 | /* determine matching parent */ |
1064 | if (dname) | 1278 | if (!dname) |
1065 | for (idx = 0; idx < context->name_count; idx++) | 1279 | goto update_context; |
1066 | if (context->names[idx].pino == pino) { | 1280 | for (idx = 0; idx < context->name_count; idx++) |
1067 | const char *n; | 1281 | if (context->names[idx].ino == pino) { |
1068 | const char *name = context->names[idx].name; | 1282 | const char *name = context->names[idx].name; |
1069 | int dlen = strlen(dname); | 1283 | |
1070 | int nlen = name ? strlen(name) : 0; | 1284 | if (!name) |
1071 | 1285 | continue; | |
1072 | if (nlen < dlen) | 1286 | |
1073 | continue; | 1287 | if (audit_compare_dname_path(dname, name, &dirlen) == 0) { |
1074 | 1288 | context->names[idx].name_len = dirlen; | |
1075 | /* disregard trailing slashes */ | 1289 | found_name = name; |
1076 | n = name + nlen - 1; | 1290 | break; |
1077 | while ((*n == '/') && (n > name)) | ||
1078 | n--; | ||
1079 | |||
1080 | /* find last path component */ | ||
1081 | n = n - dlen + 1; | ||
1082 | if (n < name) | ||
1083 | continue; | ||
1084 | else if (n > name) { | ||
1085 | if (*--n != '/') | ||
1086 | continue; | ||
1087 | else | ||
1088 | n++; | ||
1089 | } | ||
1090 | |||
1091 | if (strncmp(n, dname, dlen) == 0) | ||
1092 | goto update_context; | ||
1093 | } | 1291 | } |
1292 | } | ||
1094 | 1293 | ||
1095 | /* catch-all in case match not found */ | 1294 | update_context: |
1096 | idx = context->name_count++; | 1295 | idx = context->name_count++; |
1097 | context->names[idx].name = NULL; | ||
1098 | context->names[idx].pino = pino; | ||
1099 | #if AUDIT_DEBUG | 1296 | #if AUDIT_DEBUG |
1100 | context->ino_count++; | 1297 | context->ino_count++; |
1101 | #endif | 1298 | #endif |
1299 | /* Re-use the name belonging to the slot for a matching parent directory. | ||
1300 | * All names for this context are relinquished in audit_free_names() */ | ||
1301 | context->names[idx].name = found_name; | ||
1302 | context->names[idx].name_len = AUDIT_NAME_FULL; | ||
1303 | context->names[idx].name_put = 0; /* don't call __putname() */ | ||
1102 | 1304 | ||
1103 | update_context: | ||
1104 | if (inode) { | 1305 | if (inode) { |
1105 | context->names[idx].ino = inode->i_ino; | 1306 | context->names[idx].ino = inode->i_ino; |
1106 | context->names[idx].dev = inode->i_sb->s_dev; | 1307 | context->names[idx].dev = inode->i_sb->s_dev; |
@@ -1109,7 +1310,8 @@ update_context: | |||
1109 | context->names[idx].gid = inode->i_gid; | 1310 | context->names[idx].gid = inode->i_gid; |
1110 | context->names[idx].rdev = inode->i_rdev; | 1311 | context->names[idx].rdev = inode->i_rdev; |
1111 | audit_inode_context(idx, inode); | 1312 | audit_inode_context(idx, inode); |
1112 | } | 1313 | } else |
1314 | context->names[idx].ino = (unsigned long)-1; | ||
1113 | } | 1315 | } |
1114 | 1316 | ||
1115 | /** | 1317 | /** |
@@ -1142,18 +1344,23 @@ void auditsc_get_stamp(struct audit_context *ctx, | |||
1142 | */ | 1344 | */ |
1143 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) | 1345 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) |
1144 | { | 1346 | { |
1145 | if (task->audit_context) { | 1347 | struct audit_context *context = task->audit_context; |
1146 | struct audit_buffer *ab; | 1348 | |
1147 | 1349 | if (context) { | |
1148 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); | 1350 | /* Only log if audit is enabled */ |
1149 | if (ab) { | 1351 | if (context->in_syscall) { |
1150 | audit_log_format(ab, "login pid=%d uid=%u " | 1352 | struct audit_buffer *ab; |
1151 | "old auid=%u new auid=%u", | 1353 | |
1152 | task->pid, task->uid, | 1354 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); |
1153 | task->audit_context->loginuid, loginuid); | 1355 | if (ab) { |
1154 | audit_log_end(ab); | 1356 | audit_log_format(ab, "login pid=%d uid=%u " |
1357 | "old auid=%u new auid=%u", | ||
1358 | task->pid, task->uid, | ||
1359 | context->loginuid, loginuid); | ||
1360 | audit_log_end(ab); | ||
1361 | } | ||
1155 | } | 1362 | } |
1156 | task->audit_context->loginuid = loginuid; | 1363 | context->loginuid = loginuid; |
1157 | } | 1364 | } |
1158 | return 0; | 1365 | return 0; |
1159 | } | 1366 | } |
@@ -1170,16 +1377,193 @@ uid_t audit_get_loginuid(struct audit_context *ctx) | |||
1170 | } | 1377 | } |
1171 | 1378 | ||
1172 | /** | 1379 | /** |
1173 | * audit_ipc_obj - record audit data for ipc object | 1380 | * __audit_mq_open - record audit data for a POSIX MQ open |
1174 | * @ipcp: ipc permissions | 1381 | * @oflag: open flag |
1382 | * @mode: mode bits | ||
1383 | * @u_attr: queue attributes | ||
1175 | * | 1384 | * |
1176 | * Returns 0 for success or NULL context or < 0 on error. | 1385 | * Returns 0 for success or NULL context or < 0 on error. |
1177 | */ | 1386 | */ |
1178 | int audit_ipc_obj(struct kern_ipc_perm *ipcp) | 1387 | int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr) |
1179 | { | 1388 | { |
1180 | struct audit_aux_data_ipcctl *ax; | 1389 | struct audit_aux_data_mq_open *ax; |
1390 | struct audit_context *context = current->audit_context; | ||
1391 | |||
1392 | if (!audit_enabled) | ||
1393 | return 0; | ||
1394 | |||
1395 | if (likely(!context)) | ||
1396 | return 0; | ||
1397 | |||
1398 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
1399 | if (!ax) | ||
1400 | return -ENOMEM; | ||
1401 | |||
1402 | if (u_attr != NULL) { | ||
1403 | if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr))) { | ||
1404 | kfree(ax); | ||
1405 | return -EFAULT; | ||
1406 | } | ||
1407 | } else | ||
1408 | memset(&ax->attr, 0, sizeof(ax->attr)); | ||
1409 | |||
1410 | ax->oflag = oflag; | ||
1411 | ax->mode = mode; | ||
1412 | |||
1413 | ax->d.type = AUDIT_MQ_OPEN; | ||
1414 | ax->d.next = context->aux; | ||
1415 | context->aux = (void *)ax; | ||
1416 | return 0; | ||
1417 | } | ||
1418 | |||
1419 | /** | ||
1420 | * __audit_mq_timedsend - record audit data for a POSIX MQ timed send | ||
1421 | * @mqdes: MQ descriptor | ||
1422 | * @msg_len: Message length | ||
1423 | * @msg_prio: Message priority | ||
1424 | * @u_abs_timeout: Message timeout in absolute time | ||
1425 | * | ||
1426 | * Returns 0 for success or NULL context or < 0 on error. | ||
1427 | */ | ||
1428 | int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, | ||
1429 | const struct timespec __user *u_abs_timeout) | ||
1430 | { | ||
1431 | struct audit_aux_data_mq_sendrecv *ax; | ||
1432 | struct audit_context *context = current->audit_context; | ||
1433 | |||
1434 | if (!audit_enabled) | ||
1435 | return 0; | ||
1436 | |||
1437 | if (likely(!context)) | ||
1438 | return 0; | ||
1439 | |||
1440 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
1441 | if (!ax) | ||
1442 | return -ENOMEM; | ||
1443 | |||
1444 | if (u_abs_timeout != NULL) { | ||
1445 | if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) { | ||
1446 | kfree(ax); | ||
1447 | return -EFAULT; | ||
1448 | } | ||
1449 | } else | ||
1450 | memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout)); | ||
1451 | |||
1452 | ax->mqdes = mqdes; | ||
1453 | ax->msg_len = msg_len; | ||
1454 | ax->msg_prio = msg_prio; | ||
1455 | |||
1456 | ax->d.type = AUDIT_MQ_SENDRECV; | ||
1457 | ax->d.next = context->aux; | ||
1458 | context->aux = (void *)ax; | ||
1459 | return 0; | ||
1460 | } | ||
1461 | |||
1462 | /** | ||
1463 | * __audit_mq_timedreceive - record audit data for a POSIX MQ timed receive | ||
1464 | * @mqdes: MQ descriptor | ||
1465 | * @msg_len: Message length | ||
1466 | * @u_msg_prio: Message priority | ||
1467 | * @u_abs_timeout: Message timeout in absolute time | ||
1468 | * | ||
1469 | * Returns 0 for success or NULL context or < 0 on error. | ||
1470 | */ | ||
1471 | int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, | ||
1472 | unsigned int __user *u_msg_prio, | ||
1473 | const struct timespec __user *u_abs_timeout) | ||
1474 | { | ||
1475 | struct audit_aux_data_mq_sendrecv *ax; | ||
1476 | struct audit_context *context = current->audit_context; | ||
1477 | |||
1478 | if (!audit_enabled) | ||
1479 | return 0; | ||
1480 | |||
1481 | if (likely(!context)) | ||
1482 | return 0; | ||
1483 | |||
1484 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
1485 | if (!ax) | ||
1486 | return -ENOMEM; | ||
1487 | |||
1488 | if (u_msg_prio != NULL) { | ||
1489 | if (get_user(ax->msg_prio, u_msg_prio)) { | ||
1490 | kfree(ax); | ||
1491 | return -EFAULT; | ||
1492 | } | ||
1493 | } else | ||
1494 | ax->msg_prio = 0; | ||
1495 | |||
1496 | if (u_abs_timeout != NULL) { | ||
1497 | if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) { | ||
1498 | kfree(ax); | ||
1499 | return -EFAULT; | ||
1500 | } | ||
1501 | } else | ||
1502 | memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout)); | ||
1503 | |||
1504 | ax->mqdes = mqdes; | ||
1505 | ax->msg_len = msg_len; | ||
1506 | |||
1507 | ax->d.type = AUDIT_MQ_SENDRECV; | ||
1508 | ax->d.next = context->aux; | ||
1509 | context->aux = (void *)ax; | ||
1510 | return 0; | ||
1511 | } | ||
1512 | |||
1513 | /** | ||
1514 | * __audit_mq_notify - record audit data for a POSIX MQ notify | ||
1515 | * @mqdes: MQ descriptor | ||
1516 | * @u_notification: Notification event | ||
1517 | * | ||
1518 | * Returns 0 for success or NULL context or < 0 on error. | ||
1519 | */ | ||
1520 | |||
1521 | int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) | ||
1522 | { | ||
1523 | struct audit_aux_data_mq_notify *ax; | ||
1524 | struct audit_context *context = current->audit_context; | ||
1525 | |||
1526 | if (!audit_enabled) | ||
1527 | return 0; | ||
1528 | |||
1529 | if (likely(!context)) | ||
1530 | return 0; | ||
1531 | |||
1532 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
1533 | if (!ax) | ||
1534 | return -ENOMEM; | ||
1535 | |||
1536 | if (u_notification != NULL) { | ||
1537 | if (copy_from_user(&ax->notification, u_notification, sizeof(ax->notification))) { | ||
1538 | kfree(ax); | ||
1539 | return -EFAULT; | ||
1540 | } | ||
1541 | } else | ||
1542 | memset(&ax->notification, 0, sizeof(ax->notification)); | ||
1543 | |||
1544 | ax->mqdes = mqdes; | ||
1545 | |||
1546 | ax->d.type = AUDIT_MQ_NOTIFY; | ||
1547 | ax->d.next = context->aux; | ||
1548 | context->aux = (void *)ax; | ||
1549 | return 0; | ||
1550 | } | ||
1551 | |||
1552 | /** | ||
1553 | * __audit_mq_getsetattr - record audit data for a POSIX MQ get/set attribute | ||
1554 | * @mqdes: MQ descriptor | ||
1555 | * @mqstat: MQ flags | ||
1556 | * | ||
1557 | * Returns 0 for success or NULL context or < 0 on error. | ||
1558 | */ | ||
1559 | int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) | ||
1560 | { | ||
1561 | struct audit_aux_data_mq_getsetattr *ax; | ||
1181 | struct audit_context *context = current->audit_context; | 1562 | struct audit_context *context = current->audit_context; |
1182 | 1563 | ||
1564 | if (!audit_enabled) | ||
1565 | return 0; | ||
1566 | |||
1183 | if (likely(!context)) | 1567 | if (likely(!context)) |
1184 | return 0; | 1568 | return 0; |
1185 | 1569 | ||
@@ -1187,6 +1571,30 @@ int audit_ipc_obj(struct kern_ipc_perm *ipcp) | |||
1187 | if (!ax) | 1571 | if (!ax) |
1188 | return -ENOMEM; | 1572 | return -ENOMEM; |
1189 | 1573 | ||
1574 | ax->mqdes = mqdes; | ||
1575 | ax->mqstat = *mqstat; | ||
1576 | |||
1577 | ax->d.type = AUDIT_MQ_GETSETATTR; | ||
1578 | ax->d.next = context->aux; | ||
1579 | context->aux = (void *)ax; | ||
1580 | return 0; | ||
1581 | } | ||
1582 | |||
1583 | /** | ||
1584 | * audit_ipc_obj - record audit data for ipc object | ||
1585 | * @ipcp: ipc permissions | ||
1586 | * | ||
1587 | * Returns 0 for success or NULL context or < 0 on error. | ||
1588 | */ | ||
1589 | int __audit_ipc_obj(struct kern_ipc_perm *ipcp) | ||
1590 | { | ||
1591 | struct audit_aux_data_ipcctl *ax; | ||
1592 | struct audit_context *context = current->audit_context; | ||
1593 | |||
1594 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
1595 | if (!ax) | ||
1596 | return -ENOMEM; | ||
1597 | |||
1190 | ax->uid = ipcp->uid; | 1598 | ax->uid = ipcp->uid; |
1191 | ax->gid = ipcp->gid; | 1599 | ax->gid = ipcp->gid; |
1192 | ax->mode = ipcp->mode; | 1600 | ax->mode = ipcp->mode; |
@@ -1207,14 +1615,11 @@ int audit_ipc_obj(struct kern_ipc_perm *ipcp) | |||
1207 | * | 1615 | * |
1208 | * Returns 0 for success or NULL context or < 0 on error. | 1616 | * Returns 0 for success or NULL context or < 0 on error. |
1209 | */ | 1617 | */ |
1210 | int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp) | 1618 | int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) |
1211 | { | 1619 | { |
1212 | struct audit_aux_data_ipcctl *ax; | 1620 | struct audit_aux_data_ipcctl *ax; |
1213 | struct audit_context *context = current->audit_context; | 1621 | struct audit_context *context = current->audit_context; |
1214 | 1622 | ||
1215 | if (likely(!context)) | ||
1216 | return 0; | ||
1217 | |||
1218 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | 1623 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); |
1219 | if (!ax) | 1624 | if (!ax) |
1220 | return -ENOMEM; | 1625 | return -ENOMEM; |
@@ -1223,7 +1628,6 @@ int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, | |||
1223 | ax->uid = uid; | 1628 | ax->uid = uid; |
1224 | ax->gid = gid; | 1629 | ax->gid = gid; |
1225 | ax->mode = mode; | 1630 | ax->mode = mode; |
1226 | selinux_get_ipc_sid(ipcp, &ax->osid); | ||
1227 | 1631 | ||
1228 | ax->d.type = AUDIT_IPC_SET_PERM; | 1632 | ax->d.type = AUDIT_IPC_SET_PERM; |
1229 | ax->d.next = context->aux; | 1633 | ax->d.next = context->aux; |
@@ -1231,6 +1635,39 @@ int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, | |||
1231 | return 0; | 1635 | return 0; |
1232 | } | 1636 | } |
1233 | 1637 | ||
1638 | int audit_bprm(struct linux_binprm *bprm) | ||
1639 | { | ||
1640 | struct audit_aux_data_execve *ax; | ||
1641 | struct audit_context *context = current->audit_context; | ||
1642 | unsigned long p, next; | ||
1643 | void *to; | ||
1644 | |||
1645 | if (likely(!audit_enabled || !context)) | ||
1646 | return 0; | ||
1647 | |||
1648 | ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p, | ||
1649 | GFP_KERNEL); | ||
1650 | if (!ax) | ||
1651 | return -ENOMEM; | ||
1652 | |||
1653 | ax->argc = bprm->argc; | ||
1654 | ax->envc = bprm->envc; | ||
1655 | for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) { | ||
1656 | struct page *page = bprm->page[p / PAGE_SIZE]; | ||
1657 | void *kaddr = kmap(page); | ||
1658 | next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1); | ||
1659 | memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p); | ||
1660 | to += next - p; | ||
1661 | kunmap(page); | ||
1662 | } | ||
1663 | |||
1664 | ax->d.type = AUDIT_EXECVE; | ||
1665 | ax->d.next = context->aux; | ||
1666 | context->aux = (void *)ax; | ||
1667 | return 0; | ||
1668 | } | ||
1669 | |||
1670 | |||
1234 | /** | 1671 | /** |
1235 | * audit_socketcall - record audit data for sys_socketcall | 1672 | * audit_socketcall - record audit data for sys_socketcall |
1236 | * @nargs: number of args | 1673 | * @nargs: number of args |
@@ -1325,19 +1762,20 @@ int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt) | |||
1325 | * If the audit subsystem is being terminated, record the task (pid) | 1762 | * If the audit subsystem is being terminated, record the task (pid) |
1326 | * and uid that is doing that. | 1763 | * and uid that is doing that. |
1327 | */ | 1764 | */ |
1328 | void audit_signal_info(int sig, struct task_struct *t) | 1765 | void __audit_signal_info(int sig, struct task_struct *t) |
1329 | { | 1766 | { |
1330 | extern pid_t audit_sig_pid; | 1767 | extern pid_t audit_sig_pid; |
1331 | extern uid_t audit_sig_uid; | 1768 | extern uid_t audit_sig_uid; |
1332 | 1769 | extern u32 audit_sig_sid; | |
1333 | if (unlikely(audit_pid && t->tgid == audit_pid)) { | 1770 | |
1334 | if (sig == SIGTERM || sig == SIGHUP) { | 1771 | if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) { |
1335 | struct audit_context *ctx = current->audit_context; | 1772 | struct task_struct *tsk = current; |
1336 | audit_sig_pid = current->pid; | 1773 | struct audit_context *ctx = tsk->audit_context; |
1337 | if (ctx) | 1774 | audit_sig_pid = tsk->pid; |
1338 | audit_sig_uid = ctx->loginuid; | 1775 | if (ctx) |
1339 | else | 1776 | audit_sig_uid = ctx->loginuid; |
1340 | audit_sig_uid = current->uid; | 1777 | else |
1341 | } | 1778 | audit_sig_uid = tsk->uid; |
1779 | selinux_get_task_sid(tsk, &audit_sig_sid); | ||
1342 | } | 1780 | } |
1343 | } | 1781 | } |