diff options
| author | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-06-26 01:31:38 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-06-26 01:31:38 -0400 |
| commit | 4854c7b27f0975a2b629f35ea3996d2968eb7c4f (patch) | |
| tree | 4102bdb70289764a2058aff0f907b13d7cf0e0d1 /kernel/auditsc.c | |
| parent | 3cbd5b32cb625f5c0f1b1476d154fac873dd49ce (diff) | |
| parent | fcc18e83e1f6fd9fa6b333735bf0fcd530655511 (diff) | |
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'kernel/auditsc.c')
| -rw-r--r-- | kernel/auditsc.c | 649 |
1 files changed, 517 insertions, 132 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 1c03a4ed1b27..9ebd96fda295 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; |
| @@ -148,7 +192,7 @@ struct audit_context { | |||
| 148 | struct audit_aux_data *aux; | 192 | struct audit_aux_data *aux; |
| 149 | 193 | ||
| 150 | /* Save things to print about task_struct */ | 194 | /* Save things to print about task_struct */ |
| 151 | pid_t pid; | 195 | pid_t pid, ppid; |
| 152 | uid_t uid, euid, suid, fsuid; | 196 | uid_t uid, euid, suid, fsuid; |
| 153 | gid_t gid, egid, sgid, fsgid; | 197 | gid_t gid, egid, sgid, fsgid; |
| 154 | unsigned long personality; | 198 | unsigned long personality; |
| @@ -160,12 +204,13 @@ struct audit_context { | |||
| 160 | #endif | 204 | #endif |
| 161 | }; | 205 | }; |
| 162 | 206 | ||
| 163 | 207 | /* 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 | 208 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 |
| 165 | * otherwise. */ | 209 | * otherwise. */ |
| 166 | static int audit_filter_rules(struct task_struct *tsk, | 210 | static int audit_filter_rules(struct task_struct *tsk, |
| 167 | struct audit_krule *rule, | 211 | struct audit_krule *rule, |
| 168 | struct audit_context *ctx, | 212 | struct audit_context *ctx, |
| 213 | struct audit_names *name, | ||
| 169 | enum audit_state *state) | 214 | enum audit_state *state) |
| 170 | { | 215 | { |
| 171 | int i, j, need_sid = 1; | 216 | int i, j, need_sid = 1; |
| @@ -179,6 +224,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 179 | case AUDIT_PID: | 224 | case AUDIT_PID: |
| 180 | result = audit_comparator(tsk->pid, f->op, f->val); | 225 | result = audit_comparator(tsk->pid, f->op, f->val); |
| 181 | break; | 226 | break; |
| 227 | case AUDIT_PPID: | ||
| 228 | if (ctx) | ||
| 229 | result = audit_comparator(ctx->ppid, f->op, f->val); | ||
| 230 | break; | ||
| 182 | case AUDIT_UID: | 231 | case AUDIT_UID: |
| 183 | result = audit_comparator(tsk->uid, f->op, f->val); | 232 | result = audit_comparator(tsk->uid, f->op, f->val); |
| 184 | break; | 233 | break; |
| @@ -224,7 +273,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 224 | } | 273 | } |
| 225 | break; | 274 | break; |
| 226 | case AUDIT_DEVMAJOR: | 275 | case AUDIT_DEVMAJOR: |
| 227 | if (ctx) { | 276 | if (name) |
| 277 | result = audit_comparator(MAJOR(name->dev), | ||
| 278 | f->op, f->val); | ||
| 279 | else if (ctx) { | ||
| 228 | for (j = 0; j < ctx->name_count; j++) { | 280 | for (j = 0; j < ctx->name_count; j++) { |
| 229 | if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { | 281 | if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { |
| 230 | ++result; | 282 | ++result; |
| @@ -234,7 +286,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 234 | } | 286 | } |
| 235 | break; | 287 | break; |
| 236 | case AUDIT_DEVMINOR: | 288 | case AUDIT_DEVMINOR: |
| 237 | if (ctx) { | 289 | if (name) |
| 290 | result = audit_comparator(MINOR(name->dev), | ||
| 291 | f->op, f->val); | ||
| 292 | else if (ctx) { | ||
| 238 | for (j = 0; j < ctx->name_count; j++) { | 293 | for (j = 0; j < ctx->name_count; j++) { |
| 239 | if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { | 294 | if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { |
| 240 | ++result; | 295 | ++result; |
| @@ -244,16 +299,22 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 244 | } | 299 | } |
| 245 | break; | 300 | break; |
| 246 | case AUDIT_INODE: | 301 | case AUDIT_INODE: |
| 247 | if (ctx) { | 302 | if (name) |
| 303 | result = (name->ino == f->val); | ||
| 304 | else if (ctx) { | ||
| 248 | for (j = 0; j < ctx->name_count; j++) { | 305 | for (j = 0; j < ctx->name_count; j++) { |
| 249 | if (audit_comparator(ctx->names[j].ino, f->op, f->val) || | 306 | if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { |
| 250 | audit_comparator(ctx->names[j].pino, f->op, f->val)) { | ||
| 251 | ++result; | 307 | ++result; |
| 252 | break; | 308 | break; |
| 253 | } | 309 | } |
| 254 | } | 310 | } |
| 255 | } | 311 | } |
| 256 | break; | 312 | break; |
| 313 | case AUDIT_WATCH: | ||
| 314 | if (name && rule->watch->ino != (unsigned long)-1) | ||
| 315 | result = (name->dev == rule->watch->dev && | ||
| 316 | name->ino == rule->watch->ino); | ||
| 317 | break; | ||
| 257 | case AUDIT_LOGINUID: | 318 | case AUDIT_LOGINUID: |
| 258 | result = 0; | 319 | result = 0; |
| 259 | if (ctx) | 320 | if (ctx) |
| @@ -294,7 +355,6 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 294 | } | 355 | } |
| 295 | switch (rule->action) { | 356 | switch (rule->action) { |
| 296 | case AUDIT_NEVER: *state = AUDIT_DISABLED; break; | 357 | 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; | 358 | case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; |
| 299 | } | 359 | } |
| 300 | return 1; | 360 | return 1; |
| @@ -311,7 +371,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk) | |||
| 311 | 371 | ||
| 312 | rcu_read_lock(); | 372 | rcu_read_lock(); |
| 313 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { | 373 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { |
| 314 | if (audit_filter_rules(tsk, &e->rule, NULL, &state)) { | 374 | if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) { |
| 315 | rcu_read_unlock(); | 375 | rcu_read_unlock(); |
| 316 | return state; | 376 | return state; |
| 317 | } | 377 | } |
| @@ -341,8 +401,47 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, | |||
| 341 | int bit = AUDIT_BIT(ctx->major); | 401 | int bit = AUDIT_BIT(ctx->major); |
| 342 | 402 | ||
| 343 | list_for_each_entry_rcu(e, list, list) { | 403 | list_for_each_entry_rcu(e, list, list) { |
| 344 | if ((e->rule.mask[word] & bit) == bit | 404 | if ((e->rule.mask[word] & bit) == bit && |
| 345 | && audit_filter_rules(tsk, &e->rule, ctx, &state)) { | 405 | audit_filter_rules(tsk, &e->rule, ctx, NULL, |
| 406 | &state)) { | ||
| 407 | rcu_read_unlock(); | ||
| 408 | return state; | ||
| 409 | } | ||
| 410 | } | ||
| 411 | } | ||
| 412 | rcu_read_unlock(); | ||
| 413 | return AUDIT_BUILD_CONTEXT; | ||
| 414 | } | ||
| 415 | |||
| 416 | /* At syscall exit time, this filter is called if any audit_names[] have been | ||
| 417 | * collected during syscall processing. We only check rules in sublists at hash | ||
| 418 | * buckets applicable to the inode numbers in audit_names[]. | ||
| 419 | * Regarding audit_state, same rules apply as for audit_filter_syscall(). | ||
| 420 | */ | ||
| 421 | enum audit_state audit_filter_inodes(struct task_struct *tsk, | ||
| 422 | struct audit_context *ctx) | ||
| 423 | { | ||
| 424 | int i; | ||
| 425 | struct audit_entry *e; | ||
| 426 | enum audit_state state; | ||
| 427 | |||
| 428 | if (audit_pid && tsk->tgid == audit_pid) | ||
| 429 | return AUDIT_DISABLED; | ||
| 430 | |||
| 431 | rcu_read_lock(); | ||
| 432 | for (i = 0; i < ctx->name_count; i++) { | ||
| 433 | int word = AUDIT_WORD(ctx->major); | ||
| 434 | int bit = AUDIT_BIT(ctx->major); | ||
| 435 | struct audit_names *n = &ctx->names[i]; | ||
| 436 | int h = audit_hash_ino((u32)n->ino); | ||
| 437 | struct list_head *list = &audit_inode_hash[h]; | ||
| 438 | |||
| 439 | if (list_empty(list)) | ||
| 440 | continue; | ||
| 441 | |||
| 442 | list_for_each_entry_rcu(e, list, list) { | ||
| 443 | if ((e->rule.mask[word] & bit) == bit && | ||
| 444 | audit_filter_rules(tsk, &e->rule, ctx, n, &state)) { | ||
| 346 | rcu_read_unlock(); | 445 | rcu_read_unlock(); |
| 347 | return state; | 446 | return state; |
| 348 | } | 447 | } |
| @@ -352,6 +451,11 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, | |||
| 352 | return AUDIT_BUILD_CONTEXT; | 451 | return AUDIT_BUILD_CONTEXT; |
| 353 | } | 452 | } |
| 354 | 453 | ||
| 454 | void audit_set_auditable(struct audit_context *ctx) | ||
| 455 | { | ||
| 456 | ctx->auditable = 1; | ||
| 457 | } | ||
| 458 | |||
| 355 | static inline struct audit_context *audit_get_context(struct task_struct *tsk, | 459 | static inline struct audit_context *audit_get_context(struct task_struct *tsk, |
| 356 | int return_valid, | 460 | int return_valid, |
| 357 | int return_code) | 461 | int return_code) |
| @@ -365,12 +469,22 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, | |||
| 365 | 469 | ||
| 366 | if (context->in_syscall && !context->auditable) { | 470 | if (context->in_syscall && !context->auditable) { |
| 367 | enum audit_state state; | 471 | enum audit_state state; |
| 472 | |||
| 368 | state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); | 473 | state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); |
| 474 | if (state == AUDIT_RECORD_CONTEXT) { | ||
| 475 | context->auditable = 1; | ||
| 476 | goto get_context; | ||
| 477 | } | ||
| 478 | |||
| 479 | state = audit_filter_inodes(tsk, context); | ||
| 369 | if (state == AUDIT_RECORD_CONTEXT) | 480 | if (state == AUDIT_RECORD_CONTEXT) |
| 370 | context->auditable = 1; | 481 | context->auditable = 1; |
| 482 | |||
| 371 | } | 483 | } |
| 372 | 484 | ||
| 485 | get_context: | ||
| 373 | context->pid = tsk->pid; | 486 | context->pid = tsk->pid; |
| 487 | context->ppid = sys_getppid(); /* sic. tsk == current in all cases */ | ||
| 374 | context->uid = tsk->uid; | 488 | context->uid = tsk->uid; |
| 375 | context->gid = tsk->gid; | 489 | context->gid = tsk->gid; |
| 376 | context->euid = tsk->euid; | 490 | context->euid = tsk->euid; |
| @@ -413,7 +527,7 @@ static inline void audit_free_names(struct audit_context *context) | |||
| 413 | #endif | 527 | #endif |
| 414 | 528 | ||
| 415 | for (i = 0; i < context->name_count; i++) { | 529 | for (i = 0; i < context->name_count; i++) { |
| 416 | if (context->names[i].name) | 530 | if (context->names[i].name && context->names[i].name_put) |
| 417 | __putname(context->names[i].name); | 531 | __putname(context->names[i].name); |
| 418 | } | 532 | } |
| 419 | context->name_count = 0; | 533 | context->name_count = 0; |
| @@ -606,7 +720,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 606 | tty = "(none)"; | 720 | tty = "(none)"; |
| 607 | audit_log_format(ab, | 721 | audit_log_format(ab, |
| 608 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" | 722 | " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" |
| 609 | " pid=%d auid=%u uid=%u gid=%u" | 723 | " ppid=%d pid=%d auid=%u uid=%u gid=%u" |
| 610 | " euid=%u suid=%u fsuid=%u" | 724 | " euid=%u suid=%u fsuid=%u" |
| 611 | " egid=%u sgid=%u fsgid=%u tty=%s", | 725 | " egid=%u sgid=%u fsgid=%u tty=%s", |
| 612 | context->argv[0], | 726 | context->argv[0], |
| @@ -614,6 +728,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 614 | context->argv[2], | 728 | context->argv[2], |
| 615 | context->argv[3], | 729 | context->argv[3], |
| 616 | context->name_count, | 730 | context->name_count, |
| 731 | context->ppid, | ||
| 617 | context->pid, | 732 | context->pid, |
| 618 | context->loginuid, | 733 | context->loginuid, |
| 619 | context->uid, | 734 | context->uid, |
| @@ -630,11 +745,48 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 630 | continue; /* audit_panic has been called */ | 745 | continue; /* audit_panic has been called */ |
| 631 | 746 | ||
| 632 | switch (aux->type) { | 747 | switch (aux->type) { |
| 748 | case AUDIT_MQ_OPEN: { | ||
| 749 | struct audit_aux_data_mq_open *axi = (void *)aux; | ||
| 750 | audit_log_format(ab, | ||
| 751 | "oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld " | ||
| 752 | "mq_msgsize=%ld mq_curmsgs=%ld", | ||
| 753 | axi->oflag, axi->mode, axi->attr.mq_flags, | ||
| 754 | axi->attr.mq_maxmsg, axi->attr.mq_msgsize, | ||
| 755 | axi->attr.mq_curmsgs); | ||
| 756 | break; } | ||
| 757 | |||
| 758 | case AUDIT_MQ_SENDRECV: { | ||
| 759 | struct audit_aux_data_mq_sendrecv *axi = (void *)aux; | ||
| 760 | audit_log_format(ab, | ||
| 761 | "mqdes=%d msg_len=%zd msg_prio=%u " | ||
| 762 | "abs_timeout_sec=%ld abs_timeout_nsec=%ld", | ||
| 763 | axi->mqdes, axi->msg_len, axi->msg_prio, | ||
| 764 | axi->abs_timeout.tv_sec, axi->abs_timeout.tv_nsec); | ||
| 765 | break; } | ||
| 766 | |||
| 767 | case AUDIT_MQ_NOTIFY: { | ||
| 768 | struct audit_aux_data_mq_notify *axi = (void *)aux; | ||
| 769 | audit_log_format(ab, | ||
| 770 | "mqdes=%d sigev_signo=%d", | ||
| 771 | axi->mqdes, | ||
| 772 | axi->notification.sigev_signo); | ||
| 773 | break; } | ||
| 774 | |||
| 775 | case AUDIT_MQ_GETSETATTR: { | ||
| 776 | struct audit_aux_data_mq_getsetattr *axi = (void *)aux; | ||
| 777 | audit_log_format(ab, | ||
| 778 | "mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld " | ||
| 779 | "mq_curmsgs=%ld ", | ||
| 780 | axi->mqdes, | ||
| 781 | axi->mqstat.mq_flags, axi->mqstat.mq_maxmsg, | ||
| 782 | axi->mqstat.mq_msgsize, axi->mqstat.mq_curmsgs); | ||
| 783 | break; } | ||
| 784 | |||
| 633 | case AUDIT_IPC: { | 785 | case AUDIT_IPC: { |
| 634 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 786 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
| 635 | audit_log_format(ab, | 787 | audit_log_format(ab, |
| 636 | " qbytes=%lx iuid=%u igid=%u mode=%x", | 788 | "ouid=%u ogid=%u mode=%x", |
| 637 | axi->qbytes, axi->uid, axi->gid, axi->mode); | 789 | axi->uid, axi->gid, axi->mode); |
| 638 | if (axi->osid != 0) { | 790 | if (axi->osid != 0) { |
| 639 | char *ctx = NULL; | 791 | char *ctx = NULL; |
| 640 | u32 len; | 792 | u32 len; |
| @@ -652,19 +804,18 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 652 | case AUDIT_IPC_SET_PERM: { | 804 | case AUDIT_IPC_SET_PERM: { |
| 653 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 805 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
| 654 | audit_log_format(ab, | 806 | audit_log_format(ab, |
| 655 | " new qbytes=%lx new iuid=%u new igid=%u new mode=%x", | 807 | "qbytes=%lx ouid=%u ogid=%u mode=%x", |
| 656 | axi->qbytes, axi->uid, axi->gid, axi->mode); | 808 | axi->qbytes, axi->uid, axi->gid, axi->mode); |
| 657 | if (axi->osid != 0) { | 809 | break; } |
| 658 | char *ctx = NULL; | 810 | |
| 659 | u32 len; | 811 | case AUDIT_EXECVE: { |
| 660 | if (selinux_ctxid_to_string( | 812 | struct audit_aux_data_execve *axi = (void *)aux; |
| 661 | axi->osid, &ctx, &len)) { | 813 | int i; |
| 662 | audit_log_format(ab, " osid=%u", | 814 | const char *p; |
| 663 | axi->osid); | 815 | for (i = 0, p = axi->mem; i < axi->argc; i++) { |
| 664 | call_panic = 1; | 816 | audit_log_format(ab, "a%d=", i); |
| 665 | } else | 817 | p = audit_log_untrustedstring(ab, p); |
| 666 | audit_log_format(ab, " obj=%s", ctx); | 818 | audit_log_format(ab, "\n"); |
| 667 | kfree(ctx); | ||
| 668 | } | 819 | } |
| 669 | break; } | 820 | break; } |
| 670 | 821 | ||
| @@ -700,8 +851,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 700 | } | 851 | } |
| 701 | } | 852 | } |
| 702 | for (i = 0; i < context->name_count; i++) { | 853 | for (i = 0; i < context->name_count; i++) { |
| 703 | unsigned long ino = context->names[i].ino; | 854 | struct audit_names *n = &context->names[i]; |
| 704 | unsigned long pino = context->names[i].pino; | ||
| 705 | 855 | ||
| 706 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | 856 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); |
| 707 | if (!ab) | 857 | if (!ab) |
| @@ -709,33 +859,47 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 709 | 859 | ||
| 710 | audit_log_format(ab, "item=%d", i); | 860 | audit_log_format(ab, "item=%d", i); |
| 711 | 861 | ||
| 712 | audit_log_format(ab, " name="); | 862 | if (n->name) { |
| 713 | if (context->names[i].name) | 863 | switch(n->name_len) { |
| 714 | audit_log_untrustedstring(ab, context->names[i].name); | 864 | case AUDIT_NAME_FULL: |
| 715 | else | 865 | /* log the full path */ |
| 716 | audit_log_format(ab, "(null)"); | 866 | audit_log_format(ab, " name="); |
| 717 | 867 | audit_log_untrustedstring(ab, n->name); | |
| 718 | if (pino != (unsigned long)-1) | 868 | break; |
| 719 | audit_log_format(ab, " parent=%lu", pino); | 869 | case 0: |
| 720 | if (ino != (unsigned long)-1) | 870 | /* name was specified as a relative path and the |
| 721 | audit_log_format(ab, " inode=%lu", ino); | 871 | * directory component is the cwd */ |
| 722 | if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1)) | 872 | audit_log_d_path(ab, " name=", context->pwd, |
| 723 | audit_log_format(ab, " dev=%02x:%02x mode=%#o" | 873 | context->pwdmnt); |
| 724 | " ouid=%u ogid=%u rdev=%02x:%02x", | 874 | break; |
| 725 | MAJOR(context->names[i].dev), | 875 | default: |
| 726 | MINOR(context->names[i].dev), | 876 | /* log the name's directory component */ |
| 727 | context->names[i].mode, | 877 | audit_log_format(ab, " name="); |
| 728 | context->names[i].uid, | 878 | audit_log_n_untrustedstring(ab, n->name_len, |
| 729 | context->names[i].gid, | 879 | n->name); |
| 730 | MAJOR(context->names[i].rdev), | 880 | } |
| 731 | MINOR(context->names[i].rdev)); | 881 | } else |
| 732 | if (context->names[i].osid != 0) { | 882 | audit_log_format(ab, " name=(null)"); |
| 883 | |||
| 884 | if (n->ino != (unsigned long)-1) { | ||
| 885 | audit_log_format(ab, " inode=%lu" | ||
| 886 | " dev=%02x:%02x mode=%#o" | ||
| 887 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
| 888 | n->ino, | ||
| 889 | MAJOR(n->dev), | ||
| 890 | MINOR(n->dev), | ||
| 891 | n->mode, | ||
| 892 | n->uid, | ||
| 893 | n->gid, | ||
| 894 | MAJOR(n->rdev), | ||
| 895 | MINOR(n->rdev)); | ||
| 896 | } | ||
| 897 | if (n->osid != 0) { | ||
| 733 | char *ctx = NULL; | 898 | char *ctx = NULL; |
| 734 | u32 len; | 899 | u32 len; |
| 735 | if (selinux_ctxid_to_string( | 900 | if (selinux_ctxid_to_string( |
| 736 | context->names[i].osid, &ctx, &len)) { | 901 | n->osid, &ctx, &len)) { |
| 737 | audit_log_format(ab, " osid=%u", | 902 | audit_log_format(ab, " osid=%u", n->osid); |
| 738 | context->names[i].osid); | ||
| 739 | call_panic = 2; | 903 | call_panic = 2; |
| 740 | } else | 904 | } else |
| 741 | audit_log_format(ab, " obj=%s", ctx); | 905 | audit_log_format(ab, " obj=%s", ctx); |
| @@ -908,11 +1072,11 @@ void audit_syscall_exit(int valid, long return_code) | |||
| 908 | * Add a name to the list of audit names for this context. | 1072 | * Add a name to the list of audit names for this context. |
| 909 | * Called from fs/namei.c:getname(). | 1073 | * Called from fs/namei.c:getname(). |
| 910 | */ | 1074 | */ |
| 911 | void audit_getname(const char *name) | 1075 | void __audit_getname(const char *name) |
| 912 | { | 1076 | { |
| 913 | struct audit_context *context = current->audit_context; | 1077 | struct audit_context *context = current->audit_context; |
| 914 | 1078 | ||
| 915 | if (!context || IS_ERR(name) || !name) | 1079 | if (IS_ERR(name) || !name) |
| 916 | return; | 1080 | return; |
| 917 | 1081 | ||
| 918 | if (!context->in_syscall) { | 1082 | if (!context->in_syscall) { |
| @@ -925,6 +1089,8 @@ void audit_getname(const char *name) | |||
| 925 | } | 1089 | } |
| 926 | BUG_ON(context->name_count >= AUDIT_NAMES); | 1090 | BUG_ON(context->name_count >= AUDIT_NAMES); |
| 927 | context->names[context->name_count].name = name; | 1091 | context->names[context->name_count].name = name; |
| 1092 | context->names[context->name_count].name_len = AUDIT_NAME_FULL; | ||
| 1093 | context->names[context->name_count].name_put = 1; | ||
| 928 | context->names[context->name_count].ino = (unsigned long)-1; | 1094 | context->names[context->name_count].ino = (unsigned long)-1; |
| 929 | ++context->name_count; | 1095 | ++context->name_count; |
| 930 | if (!context->pwd) { | 1096 | if (!context->pwd) { |
| @@ -991,11 +1157,10 @@ static void audit_inode_context(int idx, const struct inode *inode) | |||
| 991 | * audit_inode - store the inode and device from a lookup | 1157 | * audit_inode - store the inode and device from a lookup |
| 992 | * @name: name being audited | 1158 | * @name: name being audited |
| 993 | * @inode: inode being audited | 1159 | * @inode: inode being audited |
| 994 | * @flags: lookup flags (as used in path_lookup()) | ||
| 995 | * | 1160 | * |
| 996 | * Called from fs/namei.c:path_lookup(). | 1161 | * Called from fs/namei.c:path_lookup(). |
| 997 | */ | 1162 | */ |
| 998 | void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | 1163 | void __audit_inode(const char *name, const struct inode *inode) |
| 999 | { | 1164 | { |
| 1000 | int idx; | 1165 | int idx; |
| 1001 | struct audit_context *context = current->audit_context; | 1166 | struct audit_context *context = current->audit_context; |
| @@ -1021,20 +1186,13 @@ void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | |||
| 1021 | ++context->ino_count; | 1186 | ++context->ino_count; |
| 1022 | #endif | 1187 | #endif |
| 1023 | } | 1188 | } |
| 1189 | context->names[idx].ino = inode->i_ino; | ||
| 1024 | context->names[idx].dev = inode->i_sb->s_dev; | 1190 | context->names[idx].dev = inode->i_sb->s_dev; |
| 1025 | context->names[idx].mode = inode->i_mode; | 1191 | context->names[idx].mode = inode->i_mode; |
| 1026 | context->names[idx].uid = inode->i_uid; | 1192 | context->names[idx].uid = inode->i_uid; |
| 1027 | context->names[idx].gid = inode->i_gid; | 1193 | context->names[idx].gid = inode->i_gid; |
| 1028 | context->names[idx].rdev = inode->i_rdev; | 1194 | context->names[idx].rdev = inode->i_rdev; |
| 1029 | audit_inode_context(idx, inode); | 1195 | 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 | } | 1196 | } |
| 1039 | 1197 | ||
| 1040 | /** | 1198 | /** |
| @@ -1056,51 +1214,40 @@ void __audit_inode_child(const char *dname, const struct inode *inode, | |||
| 1056 | { | 1214 | { |
| 1057 | int idx; | 1215 | int idx; |
| 1058 | struct audit_context *context = current->audit_context; | 1216 | struct audit_context *context = current->audit_context; |
| 1217 | const char *found_name = NULL; | ||
| 1218 | int dirlen = 0; | ||
| 1059 | 1219 | ||
| 1060 | if (!context->in_syscall) | 1220 | if (!context->in_syscall) |
| 1061 | return; | 1221 | return; |
| 1062 | 1222 | ||
| 1063 | /* determine matching parent */ | 1223 | /* determine matching parent */ |
| 1064 | if (dname) | 1224 | if (!dname) |
| 1065 | for (idx = 0; idx < context->name_count; idx++) | 1225 | goto update_context; |
| 1066 | if (context->names[idx].pino == pino) { | 1226 | for (idx = 0; idx < context->name_count; idx++) |
| 1067 | const char *n; | 1227 | if (context->names[idx].ino == pino) { |
| 1068 | const char *name = context->names[idx].name; | 1228 | const char *name = context->names[idx].name; |
| 1069 | int dlen = strlen(dname); | 1229 | |
| 1070 | int nlen = name ? strlen(name) : 0; | 1230 | if (!name) |
| 1071 | 1231 | continue; | |
| 1072 | if (nlen < dlen) | 1232 | |
| 1073 | continue; | 1233 | if (audit_compare_dname_path(dname, name, &dirlen) == 0) { |
| 1074 | 1234 | context->names[idx].name_len = dirlen; | |
| 1075 | /* disregard trailing slashes */ | 1235 | found_name = name; |
| 1076 | n = name + nlen - 1; | 1236 | 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 | } | 1237 | } |
| 1238 | } | ||
| 1094 | 1239 | ||
| 1095 | /* catch-all in case match not found */ | 1240 | update_context: |
| 1096 | idx = context->name_count++; | 1241 | idx = context->name_count++; |
| 1097 | context->names[idx].name = NULL; | ||
| 1098 | context->names[idx].pino = pino; | ||
| 1099 | #if AUDIT_DEBUG | 1242 | #if AUDIT_DEBUG |
| 1100 | context->ino_count++; | 1243 | context->ino_count++; |
| 1101 | #endif | 1244 | #endif |
| 1245 | /* Re-use the name belonging to the slot for a matching parent directory. | ||
| 1246 | * All names for this context are relinquished in audit_free_names() */ | ||
| 1247 | context->names[idx].name = found_name; | ||
| 1248 | context->names[idx].name_len = AUDIT_NAME_FULL; | ||
| 1249 | context->names[idx].name_put = 0; /* don't call __putname() */ | ||
| 1102 | 1250 | ||
| 1103 | update_context: | ||
| 1104 | if (inode) { | 1251 | if (inode) { |
| 1105 | context->names[idx].ino = inode->i_ino; | 1252 | context->names[idx].ino = inode->i_ino; |
| 1106 | context->names[idx].dev = inode->i_sb->s_dev; | 1253 | context->names[idx].dev = inode->i_sb->s_dev; |
| @@ -1109,7 +1256,8 @@ update_context: | |||
| 1109 | context->names[idx].gid = inode->i_gid; | 1256 | context->names[idx].gid = inode->i_gid; |
| 1110 | context->names[idx].rdev = inode->i_rdev; | 1257 | context->names[idx].rdev = inode->i_rdev; |
| 1111 | audit_inode_context(idx, inode); | 1258 | audit_inode_context(idx, inode); |
| 1112 | } | 1259 | } else |
| 1260 | context->names[idx].ino = (unsigned long)-1; | ||
| 1113 | } | 1261 | } |
| 1114 | 1262 | ||
| 1115 | /** | 1263 | /** |
| @@ -1142,18 +1290,23 @@ void auditsc_get_stamp(struct audit_context *ctx, | |||
| 1142 | */ | 1290 | */ |
| 1143 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) | 1291 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) |
| 1144 | { | 1292 | { |
| 1145 | if (task->audit_context) { | 1293 | struct audit_context *context = task->audit_context; |
| 1146 | struct audit_buffer *ab; | 1294 | |
| 1147 | 1295 | if (context) { | |
| 1148 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); | 1296 | /* Only log if audit is enabled */ |
| 1149 | if (ab) { | 1297 | if (context->in_syscall) { |
| 1150 | audit_log_format(ab, "login pid=%d uid=%u " | 1298 | struct audit_buffer *ab; |
| 1151 | "old auid=%u new auid=%u", | 1299 | |
| 1152 | task->pid, task->uid, | 1300 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); |
| 1153 | task->audit_context->loginuid, loginuid); | 1301 | if (ab) { |
| 1154 | audit_log_end(ab); | 1302 | audit_log_format(ab, "login pid=%d uid=%u " |
| 1303 | "old auid=%u new auid=%u", | ||
| 1304 | task->pid, task->uid, | ||
| 1305 | context->loginuid, loginuid); | ||
| 1306 | audit_log_end(ab); | ||
| 1307 | } | ||
| 1155 | } | 1308 | } |
| 1156 | task->audit_context->loginuid = loginuid; | 1309 | context->loginuid = loginuid; |
| 1157 | } | 1310 | } |
| 1158 | return 0; | 1311 | return 0; |
| 1159 | } | 1312 | } |
| @@ -1170,16 +1323,193 @@ uid_t audit_get_loginuid(struct audit_context *ctx) | |||
| 1170 | } | 1323 | } |
| 1171 | 1324 | ||
| 1172 | /** | 1325 | /** |
| 1173 | * audit_ipc_obj - record audit data for ipc object | 1326 | * __audit_mq_open - record audit data for a POSIX MQ open |
| 1174 | * @ipcp: ipc permissions | 1327 | * @oflag: open flag |
| 1328 | * @mode: mode bits | ||
| 1329 | * @u_attr: queue attributes | ||
| 1175 | * | 1330 | * |
| 1176 | * Returns 0 for success or NULL context or < 0 on error. | 1331 | * Returns 0 for success or NULL context or < 0 on error. |
| 1177 | */ | 1332 | */ |
| 1178 | int audit_ipc_obj(struct kern_ipc_perm *ipcp) | 1333 | int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr) |
| 1179 | { | 1334 | { |
| 1180 | struct audit_aux_data_ipcctl *ax; | 1335 | struct audit_aux_data_mq_open *ax; |
| 1336 | struct audit_context *context = current->audit_context; | ||
| 1337 | |||
| 1338 | if (!audit_enabled) | ||
| 1339 | return 0; | ||
| 1340 | |||
| 1341 | if (likely(!context)) | ||
| 1342 | return 0; | ||
| 1343 | |||
| 1344 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
| 1345 | if (!ax) | ||
| 1346 | return -ENOMEM; | ||
| 1347 | |||
| 1348 | if (u_attr != NULL) { | ||
| 1349 | if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr))) { | ||
| 1350 | kfree(ax); | ||
| 1351 | return -EFAULT; | ||
| 1352 | } | ||
| 1353 | } else | ||
| 1354 | memset(&ax->attr, 0, sizeof(ax->attr)); | ||
| 1355 | |||
| 1356 | ax->oflag = oflag; | ||
| 1357 | ax->mode = mode; | ||
| 1358 | |||
| 1359 | ax->d.type = AUDIT_MQ_OPEN; | ||
| 1360 | ax->d.next = context->aux; | ||
| 1361 | context->aux = (void *)ax; | ||
| 1362 | return 0; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | /** | ||
| 1366 | * __audit_mq_timedsend - record audit data for a POSIX MQ timed send | ||
| 1367 | * @mqdes: MQ descriptor | ||
| 1368 | * @msg_len: Message length | ||
| 1369 | * @msg_prio: Message priority | ||
| 1370 | * @abs_timeout: Message timeout in absolute time | ||
| 1371 | * | ||
| 1372 | * Returns 0 for success or NULL context or < 0 on error. | ||
| 1373 | */ | ||
| 1374 | int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, | ||
| 1375 | const struct timespec __user *u_abs_timeout) | ||
| 1376 | { | ||
| 1377 | struct audit_aux_data_mq_sendrecv *ax; | ||
| 1378 | struct audit_context *context = current->audit_context; | ||
| 1379 | |||
| 1380 | if (!audit_enabled) | ||
| 1381 | return 0; | ||
| 1382 | |||
| 1383 | if (likely(!context)) | ||
| 1384 | return 0; | ||
| 1385 | |||
| 1386 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
| 1387 | if (!ax) | ||
| 1388 | return -ENOMEM; | ||
| 1389 | |||
| 1390 | if (u_abs_timeout != NULL) { | ||
| 1391 | if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) { | ||
| 1392 | kfree(ax); | ||
| 1393 | return -EFAULT; | ||
| 1394 | } | ||
| 1395 | } else | ||
| 1396 | memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout)); | ||
| 1397 | |||
| 1398 | ax->mqdes = mqdes; | ||
| 1399 | ax->msg_len = msg_len; | ||
| 1400 | ax->msg_prio = msg_prio; | ||
| 1401 | |||
| 1402 | ax->d.type = AUDIT_MQ_SENDRECV; | ||
| 1403 | ax->d.next = context->aux; | ||
| 1404 | context->aux = (void *)ax; | ||
| 1405 | return 0; | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | /** | ||
| 1409 | * __audit_mq_timedreceive - record audit data for a POSIX MQ timed receive | ||
| 1410 | * @mqdes: MQ descriptor | ||
| 1411 | * @msg_len: Message length | ||
| 1412 | * @msg_prio: Message priority | ||
| 1413 | * @abs_timeout: Message timeout in absolute time | ||
| 1414 | * | ||
| 1415 | * Returns 0 for success or NULL context or < 0 on error. | ||
| 1416 | */ | ||
| 1417 | int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, | ||
| 1418 | unsigned int __user *u_msg_prio, | ||
| 1419 | const struct timespec __user *u_abs_timeout) | ||
| 1420 | { | ||
| 1421 | struct audit_aux_data_mq_sendrecv *ax; | ||
| 1422 | struct audit_context *context = current->audit_context; | ||
| 1423 | |||
| 1424 | if (!audit_enabled) | ||
| 1425 | return 0; | ||
| 1426 | |||
| 1427 | if (likely(!context)) | ||
| 1428 | return 0; | ||
| 1429 | |||
| 1430 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
| 1431 | if (!ax) | ||
| 1432 | return -ENOMEM; | ||
| 1433 | |||
| 1434 | if (u_msg_prio != NULL) { | ||
| 1435 | if (get_user(ax->msg_prio, u_msg_prio)) { | ||
| 1436 | kfree(ax); | ||
| 1437 | return -EFAULT; | ||
| 1438 | } | ||
| 1439 | } else | ||
| 1440 | ax->msg_prio = 0; | ||
| 1441 | |||
| 1442 | if (u_abs_timeout != NULL) { | ||
| 1443 | if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) { | ||
| 1444 | kfree(ax); | ||
| 1445 | return -EFAULT; | ||
| 1446 | } | ||
| 1447 | } else | ||
| 1448 | memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout)); | ||
| 1449 | |||
| 1450 | ax->mqdes = mqdes; | ||
| 1451 | ax->msg_len = msg_len; | ||
| 1452 | |||
| 1453 | ax->d.type = AUDIT_MQ_SENDRECV; | ||
| 1454 | ax->d.next = context->aux; | ||
| 1455 | context->aux = (void *)ax; | ||
| 1456 | return 0; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | /** | ||
| 1460 | * __audit_mq_notify - record audit data for a POSIX MQ notify | ||
| 1461 | * @mqdes: MQ descriptor | ||
| 1462 | * @u_notification: Notification event | ||
| 1463 | * | ||
| 1464 | * Returns 0 for success or NULL context or < 0 on error. | ||
| 1465 | */ | ||
| 1466 | |||
| 1467 | int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) | ||
| 1468 | { | ||
| 1469 | struct audit_aux_data_mq_notify *ax; | ||
| 1470 | struct audit_context *context = current->audit_context; | ||
| 1471 | |||
| 1472 | if (!audit_enabled) | ||
| 1473 | return 0; | ||
| 1474 | |||
| 1475 | if (likely(!context)) | ||
| 1476 | return 0; | ||
| 1477 | |||
| 1478 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
| 1479 | if (!ax) | ||
| 1480 | return -ENOMEM; | ||
| 1481 | |||
| 1482 | if (u_notification != NULL) { | ||
| 1483 | if (copy_from_user(&ax->notification, u_notification, sizeof(ax->notification))) { | ||
| 1484 | kfree(ax); | ||
| 1485 | return -EFAULT; | ||
| 1486 | } | ||
| 1487 | } else | ||
| 1488 | memset(&ax->notification, 0, sizeof(ax->notification)); | ||
| 1489 | |||
| 1490 | ax->mqdes = mqdes; | ||
| 1491 | |||
| 1492 | ax->d.type = AUDIT_MQ_NOTIFY; | ||
| 1493 | ax->d.next = context->aux; | ||
| 1494 | context->aux = (void *)ax; | ||
| 1495 | return 0; | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | /** | ||
| 1499 | * __audit_mq_getsetattr - record audit data for a POSIX MQ get/set attribute | ||
| 1500 | * @mqdes: MQ descriptor | ||
| 1501 | * @mqstat: MQ flags | ||
| 1502 | * | ||
| 1503 | * Returns 0 for success or NULL context or < 0 on error. | ||
| 1504 | */ | ||
| 1505 | int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) | ||
| 1506 | { | ||
| 1507 | struct audit_aux_data_mq_getsetattr *ax; | ||
| 1181 | struct audit_context *context = current->audit_context; | 1508 | struct audit_context *context = current->audit_context; |
| 1182 | 1509 | ||
| 1510 | if (!audit_enabled) | ||
| 1511 | return 0; | ||
| 1512 | |||
| 1183 | if (likely(!context)) | 1513 | if (likely(!context)) |
| 1184 | return 0; | 1514 | return 0; |
| 1185 | 1515 | ||
| @@ -1187,6 +1517,30 @@ int audit_ipc_obj(struct kern_ipc_perm *ipcp) | |||
| 1187 | if (!ax) | 1517 | if (!ax) |
| 1188 | return -ENOMEM; | 1518 | return -ENOMEM; |
| 1189 | 1519 | ||
| 1520 | ax->mqdes = mqdes; | ||
| 1521 | ax->mqstat = *mqstat; | ||
| 1522 | |||
| 1523 | ax->d.type = AUDIT_MQ_GETSETATTR; | ||
| 1524 | ax->d.next = context->aux; | ||
| 1525 | context->aux = (void *)ax; | ||
| 1526 | return 0; | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | /** | ||
| 1530 | * audit_ipc_obj - record audit data for ipc object | ||
| 1531 | * @ipcp: ipc permissions | ||
| 1532 | * | ||
| 1533 | * Returns 0 for success or NULL context or < 0 on error. | ||
| 1534 | */ | ||
| 1535 | int __audit_ipc_obj(struct kern_ipc_perm *ipcp) | ||
| 1536 | { | ||
| 1537 | struct audit_aux_data_ipcctl *ax; | ||
| 1538 | struct audit_context *context = current->audit_context; | ||
| 1539 | |||
| 1540 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
| 1541 | if (!ax) | ||
| 1542 | return -ENOMEM; | ||
| 1543 | |||
| 1190 | ax->uid = ipcp->uid; | 1544 | ax->uid = ipcp->uid; |
| 1191 | ax->gid = ipcp->gid; | 1545 | ax->gid = ipcp->gid; |
| 1192 | ax->mode = ipcp->mode; | 1546 | ax->mode = ipcp->mode; |
| @@ -1204,17 +1558,15 @@ int audit_ipc_obj(struct kern_ipc_perm *ipcp) | |||
| 1204 | * @uid: msgq user id | 1558 | * @uid: msgq user id |
| 1205 | * @gid: msgq group id | 1559 | * @gid: msgq group id |
| 1206 | * @mode: msgq mode (permissions) | 1560 | * @mode: msgq mode (permissions) |
| 1561 | * @ipcp: in-kernel IPC permissions | ||
| 1207 | * | 1562 | * |
| 1208 | * Returns 0 for success or NULL context or < 0 on error. | 1563 | * Returns 0 for success or NULL context or < 0 on error. |
| 1209 | */ | 1564 | */ |
| 1210 | int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp) | 1565 | int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) |
| 1211 | { | 1566 | { |
| 1212 | struct audit_aux_data_ipcctl *ax; | 1567 | struct audit_aux_data_ipcctl *ax; |
| 1213 | struct audit_context *context = current->audit_context; | 1568 | struct audit_context *context = current->audit_context; |
| 1214 | 1569 | ||
| 1215 | if (likely(!context)) | ||
| 1216 | return 0; | ||
| 1217 | |||
| 1218 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | 1570 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); |
| 1219 | if (!ax) | 1571 | if (!ax) |
| 1220 | return -ENOMEM; | 1572 | return -ENOMEM; |
| @@ -1223,7 +1575,6 @@ int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, | |||
| 1223 | ax->uid = uid; | 1575 | ax->uid = uid; |
| 1224 | ax->gid = gid; | 1576 | ax->gid = gid; |
| 1225 | ax->mode = mode; | 1577 | ax->mode = mode; |
| 1226 | selinux_get_ipc_sid(ipcp, &ax->osid); | ||
| 1227 | 1578 | ||
| 1228 | ax->d.type = AUDIT_IPC_SET_PERM; | 1579 | ax->d.type = AUDIT_IPC_SET_PERM; |
| 1229 | ax->d.next = context->aux; | 1580 | ax->d.next = context->aux; |
| @@ -1231,6 +1582,39 @@ int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, | |||
| 1231 | return 0; | 1582 | return 0; |
| 1232 | } | 1583 | } |
| 1233 | 1584 | ||
| 1585 | int audit_bprm(struct linux_binprm *bprm) | ||
| 1586 | { | ||
| 1587 | struct audit_aux_data_execve *ax; | ||
| 1588 | struct audit_context *context = current->audit_context; | ||
| 1589 | unsigned long p, next; | ||
| 1590 | void *to; | ||
| 1591 | |||
| 1592 | if (likely(!audit_enabled || !context)) | ||
| 1593 | return 0; | ||
| 1594 | |||
| 1595 | ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p, | ||
| 1596 | GFP_KERNEL); | ||
| 1597 | if (!ax) | ||
| 1598 | return -ENOMEM; | ||
| 1599 | |||
| 1600 | ax->argc = bprm->argc; | ||
| 1601 | ax->envc = bprm->envc; | ||
| 1602 | for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) { | ||
| 1603 | struct page *page = bprm->page[p / PAGE_SIZE]; | ||
| 1604 | void *kaddr = kmap(page); | ||
| 1605 | next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1); | ||
| 1606 | memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p); | ||
| 1607 | to += next - p; | ||
| 1608 | kunmap(page); | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | ax->d.type = AUDIT_EXECVE; | ||
| 1612 | ax->d.next = context->aux; | ||
| 1613 | context->aux = (void *)ax; | ||
| 1614 | return 0; | ||
| 1615 | } | ||
| 1616 | |||
| 1617 | |||
| 1234 | /** | 1618 | /** |
| 1235 | * audit_socketcall - record audit data for sys_socketcall | 1619 | * audit_socketcall - record audit data for sys_socketcall |
| 1236 | * @nargs: number of args | 1620 | * @nargs: number of args |
| @@ -1325,19 +1709,20 @@ int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt) | |||
| 1325 | * If the audit subsystem is being terminated, record the task (pid) | 1709 | * If the audit subsystem is being terminated, record the task (pid) |
| 1326 | * and uid that is doing that. | 1710 | * and uid that is doing that. |
| 1327 | */ | 1711 | */ |
| 1328 | void audit_signal_info(int sig, struct task_struct *t) | 1712 | void __audit_signal_info(int sig, struct task_struct *t) |
| 1329 | { | 1713 | { |
| 1330 | extern pid_t audit_sig_pid; | 1714 | extern pid_t audit_sig_pid; |
| 1331 | extern uid_t audit_sig_uid; | 1715 | extern uid_t audit_sig_uid; |
| 1332 | 1716 | extern u32 audit_sig_sid; | |
| 1333 | if (unlikely(audit_pid && t->tgid == audit_pid)) { | 1717 | |
| 1334 | if (sig == SIGTERM || sig == SIGHUP) { | 1718 | if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) { |
| 1335 | struct audit_context *ctx = current->audit_context; | 1719 | struct task_struct *tsk = current; |
| 1336 | audit_sig_pid = current->pid; | 1720 | struct audit_context *ctx = tsk->audit_context; |
| 1337 | if (ctx) | 1721 | audit_sig_pid = tsk->pid; |
| 1338 | audit_sig_uid = ctx->loginuid; | 1722 | if (ctx) |
| 1339 | else | 1723 | audit_sig_uid = ctx->loginuid; |
| 1340 | audit_sig_uid = current->uid; | 1724 | else |
| 1341 | } | 1725 | audit_sig_uid = tsk->uid; |
| 1726 | selinux_get_task_sid(tsk, &audit_sig_sid); | ||
| 1342 | } | 1727 | } |
| 1343 | } | 1728 | } |
