diff options
| author | Eric Paris <eparis@redhat.com> | 2012-01-03 14:23:05 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-01-17 16:16:54 -0500 |
| commit | 5195d8e217a78697152d64fc09a16e063a022465 (patch) | |
| tree | 6d8d980037d95740d0f64ba9491c0e5a38f31ea3 /kernel | |
| parent | 5ef30ee53b187786e64bdc1f8109e39d17f2ce58 (diff) | |
audit: dynamically allocate audit_names when not enough space is in the names array
This patch does 2 things. First it reduces the number of audit_names
allocated in every audit context from 20 to 5. 5 should be enough for all
'normal' syscalls (rename being the worst). Some syscalls can still touch
more the 5 inodes such as mount. When rpc filesystem is mounted it will
create inodes and those can exceed 5. To handle that problem this patch will
dynamically allocate audit_names if it needs more than 5. This should
decrease the typicall memory usage while still supporting all the possible
kernel operations.
Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/auditsc.c | 403 |
1 files changed, 215 insertions, 188 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index a09c50317059..1a92d61ddd27 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -71,8 +71,9 @@ | |||
| 71 | #include "audit.h" | 71 | #include "audit.h" |
| 72 | 72 | ||
| 73 | /* AUDIT_NAMES is the number of slots we reserve in the audit_context | 73 | /* AUDIT_NAMES is the number of slots we reserve in the audit_context |
| 74 | * for saving names from getname(). */ | 74 | * for saving names from getname(). If we get more names we will allocate |
| 75 | #define AUDIT_NAMES 20 | 75 | * a name dynamically and also add those to the list anchored by names_list. */ |
| 76 | #define AUDIT_NAMES 5 | ||
| 76 | 77 | ||
| 77 | /* Indicates that audit should log the full pathname. */ | 78 | /* Indicates that audit should log the full pathname. */ |
| 78 | #define AUDIT_NAME_FULL -1 | 79 | #define AUDIT_NAME_FULL -1 |
| @@ -101,9 +102,8 @@ struct audit_cap_data { | |||
| 101 | * | 102 | * |
| 102 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ | 103 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ |
| 103 | struct audit_names { | 104 | struct audit_names { |
| 105 | struct list_head list; /* audit_context->names_list */ | ||
| 104 | const char *name; | 106 | const char *name; |
| 105 | int name_len; /* number of name's characters to log */ | ||
| 106 | unsigned name_put; /* call __putname() for this name */ | ||
| 107 | unsigned long ino; | 107 | unsigned long ino; |
| 108 | dev_t dev; | 108 | dev_t dev; |
| 109 | umode_t mode; | 109 | umode_t mode; |
| @@ -113,6 +113,14 @@ struct audit_names { | |||
| 113 | u32 osid; | 113 | u32 osid; |
| 114 | struct audit_cap_data fcap; | 114 | struct audit_cap_data fcap; |
| 115 | unsigned int fcap_ver; | 115 | unsigned int fcap_ver; |
| 116 | int name_len; /* number of name's characters to log */ | ||
| 117 | bool name_put; /* call __putname() for this name */ | ||
| 118 | /* | ||
| 119 | * This was an allocated audit_names and not from the array of | ||
| 120 | * names allocated in the task audit context. Thus this name | ||
| 121 | * should be freed on syscall exit | ||
| 122 | */ | ||
| 123 | bool should_free; | ||
| 116 | }; | 124 | }; |
| 117 | 125 | ||
| 118 | struct audit_aux_data { | 126 | struct audit_aux_data { |
| @@ -174,8 +182,17 @@ struct audit_context { | |||
| 174 | long return_code;/* syscall return code */ | 182 | long return_code;/* syscall return code */ |
| 175 | u64 prio; | 183 | u64 prio; |
| 176 | int return_valid; /* return code is valid */ | 184 | int return_valid; /* return code is valid */ |
| 177 | int name_count; | 185 | /* |
| 178 | struct audit_names names[AUDIT_NAMES]; | 186 | * The names_list is the list of all audit_names collected during this |
| 187 | * syscall. The first AUDIT_NAMES entries in the names_list will | ||
| 188 | * actually be from the preallocated_names array for performance | ||
| 189 | * reasons. Except during allocation they should never be referenced | ||
| 190 | * through the preallocated_names array and should only be found/used | ||
| 191 | * by running the names_list. | ||
| 192 | */ | ||
| 193 | struct audit_names preallocated_names[AUDIT_NAMES]; | ||
| 194 | int name_count; /* total records in names_list */ | ||
| 195 | struct list_head names_list; /* anchor for struct audit_names->list */ | ||
| 179 | char * filterkey; /* key for rule that triggered record */ | 196 | char * filterkey; /* key for rule that triggered record */ |
| 180 | struct path pwd; | 197 | struct path pwd; |
| 181 | struct audit_context *previous; /* For nested syscalls */ | 198 | struct audit_context *previous; /* For nested syscalls */ |
| @@ -307,17 +324,18 @@ static int audit_match_perm(struct audit_context *ctx, int mask) | |||
| 307 | 324 | ||
| 308 | static int audit_match_filetype(struct audit_context *ctx, int val) | 325 | static int audit_match_filetype(struct audit_context *ctx, int val) |
| 309 | { | 326 | { |
| 310 | int index; | 327 | struct audit_names *n; |
| 311 | umode_t mode = (umode_t)val; | 328 | umode_t mode = (umode_t)val; |
| 312 | 329 | ||
| 313 | if (unlikely(!ctx)) | 330 | if (unlikely(!ctx)) |
| 314 | return 0; | 331 | return 0; |
| 315 | 332 | ||
| 316 | for (index = 0; index < ctx->name_count; index++) { | 333 | list_for_each_entry(n, &ctx->names_list, list) { |
| 317 | if ((ctx->names[index].ino != -1) && | 334 | if ((n->ino != -1) && |
| 318 | ((ctx->names[index].mode & S_IFMT) == mode)) | 335 | ((n->mode & S_IFMT) == mode)) |
| 319 | return 1; | 336 | return 1; |
| 320 | } | 337 | } |
| 338 | |||
| 321 | return 0; | 339 | return 0; |
| 322 | } | 340 | } |
| 323 | 341 | ||
| @@ -456,13 +474,14 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 456 | bool task_creation) | 474 | bool task_creation) |
| 457 | { | 475 | { |
| 458 | const struct cred *cred; | 476 | const struct cred *cred; |
| 459 | int i, j, need_sid = 1; | 477 | int i, need_sid = 1; |
| 460 | u32 sid; | 478 | u32 sid; |
| 461 | 479 | ||
| 462 | cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); | 480 | cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); |
| 463 | 481 | ||
| 464 | for (i = 0; i < rule->field_count; i++) { | 482 | for (i = 0; i < rule->field_count; i++) { |
| 465 | struct audit_field *f = &rule->fields[i]; | 483 | struct audit_field *f = &rule->fields[i]; |
| 484 | struct audit_names *n; | ||
| 466 | int result = 0; | 485 | int result = 0; |
| 467 | 486 | ||
| 468 | switch (f->type) { | 487 | switch (f->type) { |
| @@ -525,8 +544,8 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 525 | result = audit_comparator(MAJOR(name->dev), | 544 | result = audit_comparator(MAJOR(name->dev), |
| 526 | f->op, f->val); | 545 | f->op, f->val); |
| 527 | else if (ctx) { | 546 | else if (ctx) { |
| 528 | for (j = 0; j < ctx->name_count; j++) { | 547 | list_for_each_entry(n, &ctx->names_list, list) { |
| 529 | if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { | 548 | if (audit_comparator(MAJOR(n->dev), f->op, f->val)) { |
| 530 | ++result; | 549 | ++result; |
| 531 | break; | 550 | break; |
| 532 | } | 551 | } |
| @@ -538,8 +557,8 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 538 | result = audit_comparator(MINOR(name->dev), | 557 | result = audit_comparator(MINOR(name->dev), |
| 539 | f->op, f->val); | 558 | f->op, f->val); |
| 540 | else if (ctx) { | 559 | else if (ctx) { |
| 541 | for (j = 0; j < ctx->name_count; j++) { | 560 | list_for_each_entry(n, &ctx->names_list, list) { |
| 542 | if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { | 561 | if (audit_comparator(MINOR(n->dev), f->op, f->val)) { |
| 543 | ++result; | 562 | ++result; |
| 544 | break; | 563 | break; |
| 545 | } | 564 | } |
| @@ -550,8 +569,8 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 550 | if (name) | 569 | if (name) |
| 551 | result = (name->ino == f->val); | 570 | result = (name->ino == f->val); |
| 552 | else if (ctx) { | 571 | else if (ctx) { |
| 553 | for (j = 0; j < ctx->name_count; j++) { | 572 | list_for_each_entry(n, &ctx->names_list, list) { |
| 554 | if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { | 573 | if (audit_comparator(n->ino, f->op, f->val)) { |
| 555 | ++result; | 574 | ++result; |
| 556 | break; | 575 | break; |
| 557 | } | 576 | } |
| @@ -606,11 +625,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
| 606 | name->osid, f->type, f->op, | 625 | name->osid, f->type, f->op, |
| 607 | f->lsm_rule, ctx); | 626 | f->lsm_rule, ctx); |
| 608 | } else if (ctx) { | 627 | } else if (ctx) { |
| 609 | for (j = 0; j < ctx->name_count; j++) { | 628 | list_for_each_entry(n, &ctx->names_list, list) { |
| 610 | if (security_audit_rule_match( | 629 | if (security_audit_rule_match(n->osid, f->type, |
| 611 | ctx->names[j].osid, | 630 | f->op, f->lsm_rule, |
| 612 | f->type, f->op, | 631 | ctx)) { |
| 613 | f->lsm_rule, ctx)) { | ||
| 614 | ++result; | 632 | ++result; |
| 615 | break; | 633 | break; |
| 616 | } | 634 | } |
| @@ -721,40 +739,53 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, | |||
| 721 | return AUDIT_BUILD_CONTEXT; | 739 | return AUDIT_BUILD_CONTEXT; |
| 722 | } | 740 | } |
| 723 | 741 | ||
| 724 | /* At syscall exit time, this filter is called if any audit_names[] have been | 742 | /* |
| 743 | * Given an audit_name check the inode hash table to see if they match. | ||
| 744 | * Called holding the rcu read lock to protect the use of audit_inode_hash | ||
| 745 | */ | ||
| 746 | static int audit_filter_inode_name(struct task_struct *tsk, | ||
| 747 | struct audit_names *n, | ||
| 748 | struct audit_context *ctx) { | ||
| 749 | int word, bit; | ||
| 750 | int h = audit_hash_ino((u32)n->ino); | ||
| 751 | struct list_head *list = &audit_inode_hash[h]; | ||
| 752 | struct audit_entry *e; | ||
| 753 | enum audit_state state; | ||
| 754 | |||
| 755 | word = AUDIT_WORD(ctx->major); | ||
| 756 | bit = AUDIT_BIT(ctx->major); | ||
| 757 | |||
| 758 | if (list_empty(list)) | ||
| 759 | return 0; | ||
| 760 | |||
| 761 | list_for_each_entry_rcu(e, list, list) { | ||
| 762 | if ((e->rule.mask[word] & bit) == bit && | ||
| 763 | audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) { | ||
| 764 | ctx->current_state = state; | ||
| 765 | return 1; | ||
| 766 | } | ||
| 767 | } | ||
| 768 | |||
| 769 | return 0; | ||
| 770 | } | ||
| 771 | |||
| 772 | /* At syscall exit time, this filter is called if any audit_names have been | ||
| 725 | * collected during syscall processing. We only check rules in sublists at hash | 773 | * collected during syscall processing. We only check rules in sublists at hash |
| 726 | * buckets applicable to the inode numbers in audit_names[]. | 774 | * buckets applicable to the inode numbers in audit_names. |
| 727 | * Regarding audit_state, same rules apply as for audit_filter_syscall(). | 775 | * Regarding audit_state, same rules apply as for audit_filter_syscall(). |
| 728 | */ | 776 | */ |
| 729 | void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx) | 777 | void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx) |
| 730 | { | 778 | { |
| 731 | int i; | 779 | struct audit_names *n; |
| 732 | struct audit_entry *e; | ||
| 733 | enum audit_state state; | ||
| 734 | 780 | ||
| 735 | if (audit_pid && tsk->tgid == audit_pid) | 781 | if (audit_pid && tsk->tgid == audit_pid) |
| 736 | return; | 782 | return; |
| 737 | 783 | ||
| 738 | rcu_read_lock(); | 784 | rcu_read_lock(); |
| 739 | for (i = 0; i < ctx->name_count; i++) { | ||
| 740 | int word = AUDIT_WORD(ctx->major); | ||
| 741 | int bit = AUDIT_BIT(ctx->major); | ||
| 742 | struct audit_names *n = &ctx->names[i]; | ||
| 743 | int h = audit_hash_ino((u32)n->ino); | ||
| 744 | struct list_head *list = &audit_inode_hash[h]; | ||
| 745 | 785 | ||
| 746 | if (list_empty(list)) | 786 | list_for_each_entry(n, &ctx->names_list, list) { |
| 747 | continue; | 787 | if (audit_filter_inode_name(tsk, n, ctx)) |
| 748 | 788 | break; | |
| 749 | list_for_each_entry_rcu(e, list, list) { | ||
| 750 | if ((e->rule.mask[word] & bit) == bit && | ||
| 751 | audit_filter_rules(tsk, &e->rule, ctx, n, | ||
| 752 | &state, false)) { | ||
| 753 | rcu_read_unlock(); | ||
| 754 | ctx->current_state = state; | ||
| 755 | return; | ||
| 756 | } | ||
| 757 | } | ||
| 758 | } | 789 | } |
| 759 | rcu_read_unlock(); | 790 | rcu_read_unlock(); |
| 760 | } | 791 | } |
| @@ -798,7 +829,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, | |||
| 798 | 829 | ||
| 799 | static inline void audit_free_names(struct audit_context *context) | 830 | static inline void audit_free_names(struct audit_context *context) |
| 800 | { | 831 | { |
| 801 | int i; | 832 | struct audit_names *n, *next; |
| 802 | 833 | ||
| 803 | #if AUDIT_DEBUG == 2 | 834 | #if AUDIT_DEBUG == 2 |
| 804 | if (context->put_count + context->ino_count != context->name_count) { | 835 | if (context->put_count + context->ino_count != context->name_count) { |
| @@ -809,10 +840,9 @@ static inline void audit_free_names(struct audit_context *context) | |||
| 809 | context->serial, context->major, context->in_syscall, | 840 | context->serial, context->major, context->in_syscall, |
| 810 | context->name_count, context->put_count, | 841 | context->name_count, context->put_count, |
| 811 | context->ino_count); | 842 | context->ino_count); |
| 812 | for (i = 0; i < context->name_count; i++) { | 843 | list_for_each_entry(n, &context->names_list, list) { |
| 813 | printk(KERN_ERR "names[%d] = %p = %s\n", i, | 844 | printk(KERN_ERR "names[%d] = %p = %s\n", i, |
| 814 | context->names[i].name, | 845 | n->name, n->name ?: "(null)"); |
| 815 | context->names[i].name ?: "(null)"); | ||
| 816 | } | 846 | } |
| 817 | dump_stack(); | 847 | dump_stack(); |
| 818 | return; | 848 | return; |
| @@ -823,9 +853,12 @@ static inline void audit_free_names(struct audit_context *context) | |||
| 823 | context->ino_count = 0; | 853 | context->ino_count = 0; |
| 824 | #endif | 854 | #endif |
| 825 | 855 | ||
| 826 | for (i = 0; i < context->name_count; i++) { | 856 | list_for_each_entry_safe(n, next, &context->names_list, list) { |
| 827 | if (context->names[i].name && context->names[i].name_put) | 857 | list_del(&n->list); |
| 828 | __putname(context->names[i].name); | 858 | if (n->name && n->name_put) |
| 859 | __putname(n->name); | ||
| 860 | if (n->should_free) | ||
| 861 | kfree(n); | ||
| 829 | } | 862 | } |
| 830 | context->name_count = 0; | 863 | context->name_count = 0; |
| 831 | path_put(&context->pwd); | 864 | path_put(&context->pwd); |
| @@ -863,6 +896,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) | |||
| 863 | return NULL; | 896 | return NULL; |
| 864 | audit_zero_context(context, state); | 897 | audit_zero_context(context, state); |
| 865 | INIT_LIST_HEAD(&context->killed_trees); | 898 | INIT_LIST_HEAD(&context->killed_trees); |
| 899 | INIT_LIST_HEAD(&context->names_list); | ||
| 866 | return context; | 900 | return context; |
| 867 | } | 901 | } |
| 868 | 902 | ||
| @@ -1323,6 +1357,68 @@ static void show_special(struct audit_context *context, int *call_panic) | |||
| 1323 | audit_log_end(ab); | 1357 | audit_log_end(ab); |
| 1324 | } | 1358 | } |
| 1325 | 1359 | ||
| 1360 | static void audit_log_name(struct audit_context *context, struct audit_names *n, | ||
| 1361 | int record_num, int *call_panic) | ||
| 1362 | { | ||
| 1363 | struct audit_buffer *ab; | ||
| 1364 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | ||
| 1365 | if (!ab) | ||
| 1366 | return; /* audit_panic has been called */ | ||
| 1367 | |||
| 1368 | audit_log_format(ab, "item=%d", record_num); | ||
| 1369 | |||
| 1370 | if (n->name) { | ||
| 1371 | switch (n->name_len) { | ||
| 1372 | case AUDIT_NAME_FULL: | ||
| 1373 | /* log the full path */ | ||
| 1374 | audit_log_format(ab, " name="); | ||
| 1375 | audit_log_untrustedstring(ab, n->name); | ||
| 1376 | break; | ||
| 1377 | case 0: | ||
| 1378 | /* name was specified as a relative path and the | ||
| 1379 | * directory component is the cwd */ | ||
| 1380 | audit_log_d_path(ab, "name=", &context->pwd); | ||
| 1381 | break; | ||
| 1382 | default: | ||
| 1383 | /* log the name's directory component */ | ||
| 1384 | audit_log_format(ab, " name="); | ||
| 1385 | audit_log_n_untrustedstring(ab, n->name, | ||
| 1386 | n->name_len); | ||
| 1387 | } | ||
| 1388 | } else | ||
| 1389 | audit_log_format(ab, " name=(null)"); | ||
| 1390 | |||
| 1391 | if (n->ino != (unsigned long)-1) { | ||
| 1392 | audit_log_format(ab, " inode=%lu" | ||
| 1393 | " dev=%02x:%02x mode=%#ho" | ||
| 1394 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
| 1395 | n->ino, | ||
| 1396 | MAJOR(n->dev), | ||
| 1397 | MINOR(n->dev), | ||
| 1398 | n->mode, | ||
| 1399 | n->uid, | ||
| 1400 | n->gid, | ||
| 1401 | MAJOR(n->rdev), | ||
| 1402 | MINOR(n->rdev)); | ||
| 1403 | } | ||
| 1404 | if (n->osid != 0) { | ||
| 1405 | char *ctx = NULL; | ||
| 1406 | u32 len; | ||
| 1407 | if (security_secid_to_secctx( | ||
| 1408 | n->osid, &ctx, &len)) { | ||
| 1409 | audit_log_format(ab, " osid=%u", n->osid); | ||
| 1410 | *call_panic = 2; | ||
| 1411 | } else { | ||
| 1412 | audit_log_format(ab, " obj=%s", ctx); | ||
| 1413 | security_release_secctx(ctx, len); | ||
| 1414 | } | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | audit_log_fcaps(ab, n); | ||
| 1418 | |||
| 1419 | audit_log_end(ab); | ||
| 1420 | } | ||
| 1421 | |||
| 1326 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) | 1422 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) |
| 1327 | { | 1423 | { |
| 1328 | const struct cred *cred; | 1424 | const struct cred *cred; |
| @@ -1330,6 +1426,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 1330 | struct audit_buffer *ab; | 1426 | struct audit_buffer *ab; |
| 1331 | struct audit_aux_data *aux; | 1427 | struct audit_aux_data *aux; |
| 1332 | const char *tty; | 1428 | const char *tty; |
| 1429 | struct audit_names *n; | ||
| 1333 | 1430 | ||
| 1334 | /* tsk == current */ | 1431 | /* tsk == current */ |
| 1335 | context->pid = tsk->pid; | 1432 | context->pid = tsk->pid; |
| @@ -1469,66 +1566,10 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 1469 | audit_log_end(ab); | 1566 | audit_log_end(ab); |
| 1470 | } | 1567 | } |
| 1471 | } | 1568 | } |
| 1472 | for (i = 0; i < context->name_count; i++) { | ||
| 1473 | struct audit_names *n = &context->names[i]; | ||
| 1474 | |||
| 1475 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | ||
| 1476 | if (!ab) | ||
| 1477 | continue; /* audit_panic has been called */ | ||
| 1478 | |||
| 1479 | audit_log_format(ab, "item=%d", i); | ||
| 1480 | |||
| 1481 | if (n->name) { | ||
| 1482 | switch(n->name_len) { | ||
| 1483 | case AUDIT_NAME_FULL: | ||
| 1484 | /* log the full path */ | ||
| 1485 | audit_log_format(ab, " name="); | ||
| 1486 | audit_log_untrustedstring(ab, n->name); | ||
| 1487 | break; | ||
| 1488 | case 0: | ||
| 1489 | /* name was specified as a relative path and the | ||
| 1490 | * directory component is the cwd */ | ||
| 1491 | audit_log_d_path(ab, "name=", &context->pwd); | ||
| 1492 | break; | ||
| 1493 | default: | ||
| 1494 | /* log the name's directory component */ | ||
| 1495 | audit_log_format(ab, " name="); | ||
| 1496 | audit_log_n_untrustedstring(ab, n->name, | ||
| 1497 | n->name_len); | ||
| 1498 | } | ||
| 1499 | } else | ||
| 1500 | audit_log_format(ab, " name=(null)"); | ||
| 1501 | |||
| 1502 | if (n->ino != (unsigned long)-1) { | ||
| 1503 | audit_log_format(ab, " inode=%lu" | ||
| 1504 | " dev=%02x:%02x mode=%#ho" | ||
| 1505 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
| 1506 | n->ino, | ||
| 1507 | MAJOR(n->dev), | ||
| 1508 | MINOR(n->dev), | ||
| 1509 | n->mode, | ||
| 1510 | n->uid, | ||
| 1511 | n->gid, | ||
| 1512 | MAJOR(n->rdev), | ||
| 1513 | MINOR(n->rdev)); | ||
| 1514 | } | ||
| 1515 | if (n->osid != 0) { | ||
| 1516 | char *ctx = NULL; | ||
| 1517 | u32 len; | ||
| 1518 | if (security_secid_to_secctx( | ||
| 1519 | n->osid, &ctx, &len)) { | ||
| 1520 | audit_log_format(ab, " osid=%u", n->osid); | ||
| 1521 | call_panic = 2; | ||
| 1522 | } else { | ||
| 1523 | audit_log_format(ab, " obj=%s", ctx); | ||
| 1524 | security_release_secctx(ctx, len); | ||
| 1525 | } | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | audit_log_fcaps(ab, n); | ||
| 1529 | 1569 | ||
| 1530 | audit_log_end(ab); | 1570 | i = 0; |
| 1531 | } | 1571 | list_for_each_entry(n, &context->names_list, list) |
| 1572 | audit_log_name(context, n, i++, &call_panic); | ||
| 1532 | 1573 | ||
| 1533 | /* Send end of event record to help user space know we are finished */ | 1574 | /* Send end of event record to help user space know we are finished */ |
| 1534 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); | 1575 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); |
| @@ -1820,6 +1861,30 @@ retry: | |||
| 1820 | #endif | 1861 | #endif |
| 1821 | } | 1862 | } |
| 1822 | 1863 | ||
| 1864 | static struct audit_names *audit_alloc_name(struct audit_context *context) | ||
| 1865 | { | ||
| 1866 | struct audit_names *aname; | ||
| 1867 | |||
| 1868 | if (context->name_count < AUDIT_NAMES) { | ||
| 1869 | aname = &context->preallocated_names[context->name_count]; | ||
| 1870 | memset(aname, 0, sizeof(*aname)); | ||
| 1871 | } else { | ||
| 1872 | aname = kzalloc(sizeof(*aname), GFP_NOFS); | ||
| 1873 | if (!aname) | ||
| 1874 | return NULL; | ||
| 1875 | aname->should_free = true; | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | aname->ino = (unsigned long)-1; | ||
| 1879 | list_add_tail(&aname->list, &context->names_list); | ||
| 1880 | |||
| 1881 | context->name_count++; | ||
| 1882 | #if AUDIT_DEBUG | ||
| 1883 | context->ino_count++; | ||
| 1884 | #endif | ||
| 1885 | return aname; | ||
| 1886 | } | ||
| 1887 | |||
| 1823 | /** | 1888 | /** |
| 1824 | * audit_getname - add a name to the list | 1889 | * audit_getname - add a name to the list |
| 1825 | * @name: name to add | 1890 | * @name: name to add |
| @@ -1830,6 +1895,7 @@ retry: | |||
| 1830 | void __audit_getname(const char *name) | 1895 | void __audit_getname(const char *name) |
| 1831 | { | 1896 | { |
| 1832 | struct audit_context *context = current->audit_context; | 1897 | struct audit_context *context = current->audit_context; |
| 1898 | struct audit_names *n; | ||
| 1833 | 1899 | ||
| 1834 | if (IS_ERR(name) || !name) | 1900 | if (IS_ERR(name) || !name) |
| 1835 | return; | 1901 | return; |
| @@ -1842,13 +1908,15 @@ void __audit_getname(const char *name) | |||
| 1842 | #endif | 1908 | #endif |
| 1843 | return; | 1909 | return; |
| 1844 | } | 1910 | } |
| 1845 | BUG_ON(context->name_count >= AUDIT_NAMES); | 1911 | |
| 1846 | context->names[context->name_count].name = name; | 1912 | n = audit_alloc_name(context); |
| 1847 | context->names[context->name_count].name_len = AUDIT_NAME_FULL; | 1913 | if (!n) |
| 1848 | context->names[context->name_count].name_put = 1; | 1914 | return; |
| 1849 | context->names[context->name_count].ino = (unsigned long)-1; | 1915 | |
| 1850 | context->names[context->name_count].osid = 0; | 1916 | n->name = name; |
| 1851 | ++context->name_count; | 1917 | n->name_len = AUDIT_NAME_FULL; |
| 1918 | n->name_put = true; | ||
| 1919 | |||
| 1852 | if (!context->pwd.dentry) | 1920 | if (!context->pwd.dentry) |
| 1853 | get_fs_pwd(current->fs, &context->pwd); | 1921 | get_fs_pwd(current->fs, &context->pwd); |
| 1854 | } | 1922 | } |
| @@ -1870,12 +1938,13 @@ void audit_putname(const char *name) | |||
| 1870 | printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", | 1938 | printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", |
| 1871 | __FILE__, __LINE__, context->serial, name); | 1939 | __FILE__, __LINE__, context->serial, name); |
| 1872 | if (context->name_count) { | 1940 | if (context->name_count) { |
| 1941 | struct audit_names *n; | ||
| 1873 | int i; | 1942 | int i; |
| 1874 | for (i = 0; i < context->name_count; i++) | 1943 | |
| 1944 | list_for_each_entry(n, &context->names_list, list) | ||
| 1875 | printk(KERN_ERR "name[%d] = %p = %s\n", i, | 1945 | printk(KERN_ERR "name[%d] = %p = %s\n", i, |
| 1876 | context->names[i].name, | 1946 | n->name, n->name ?: "(null)"); |
| 1877 | context->names[i].name ?: "(null)"); | 1947 | } |
| 1878 | } | ||
| 1879 | #endif | 1948 | #endif |
| 1880 | __putname(name); | 1949 | __putname(name); |
| 1881 | } | 1950 | } |
| @@ -1896,39 +1965,11 @@ void audit_putname(const char *name) | |||
| 1896 | #endif | 1965 | #endif |
| 1897 | } | 1966 | } |
| 1898 | 1967 | ||
| 1899 | static int audit_inc_name_count(struct audit_context *context, | ||
| 1900 | const struct inode *inode) | ||
| 1901 | { | ||
| 1902 | if (context->name_count >= AUDIT_NAMES) { | ||
| 1903 | if (inode) | ||
| 1904 | printk(KERN_DEBUG "audit: name_count maxed, losing inode data: " | ||
| 1905 | "dev=%02x:%02x, inode=%lu\n", | ||
| 1906 | MAJOR(inode->i_sb->s_dev), | ||
| 1907 | MINOR(inode->i_sb->s_dev), | ||
| 1908 | inode->i_ino); | ||
| 1909 | |||
| 1910 | else | ||
| 1911 | printk(KERN_DEBUG "name_count maxed, losing inode data\n"); | ||
| 1912 | return 1; | ||
| 1913 | } | ||
| 1914 | context->name_count++; | ||
| 1915 | #if AUDIT_DEBUG | ||
| 1916 | context->ino_count++; | ||
| 1917 | #endif | ||
| 1918 | return 0; | ||
| 1919 | } | ||
| 1920 | |||
| 1921 | |||
| 1922 | static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) | 1968 | static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) |
| 1923 | { | 1969 | { |
| 1924 | struct cpu_vfs_cap_data caps; | 1970 | struct cpu_vfs_cap_data caps; |
| 1925 | int rc; | 1971 | int rc; |
| 1926 | 1972 | ||
| 1927 | memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t)); | ||
| 1928 | memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t)); | ||
| 1929 | name->fcap.fE = 0; | ||
| 1930 | name->fcap_ver = 0; | ||
| 1931 | |||
| 1932 | if (!dentry) | 1973 | if (!dentry) |
| 1933 | return 0; | 1974 | return 0; |
| 1934 | 1975 | ||
| @@ -1968,30 +2009,25 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent | |||
| 1968 | */ | 2009 | */ |
| 1969 | void __audit_inode(const char *name, const struct dentry *dentry) | 2010 | void __audit_inode(const char *name, const struct dentry *dentry) |
| 1970 | { | 2011 | { |
| 1971 | int idx; | ||
| 1972 | struct audit_context *context = current->audit_context; | 2012 | struct audit_context *context = current->audit_context; |
| 1973 | const struct inode *inode = dentry->d_inode; | 2013 | const struct inode *inode = dentry->d_inode; |
| 2014 | struct audit_names *n; | ||
| 1974 | 2015 | ||
| 1975 | if (!context->in_syscall) | 2016 | if (!context->in_syscall) |
| 1976 | return; | 2017 | return; |
| 1977 | if (context->name_count | 2018 | |
| 1978 | && context->names[context->name_count-1].name | 2019 | list_for_each_entry_reverse(n, &context->names_list, list) { |
| 1979 | && context->names[context->name_count-1].name == name) | 2020 | if (n->name && (n->name == name)) |
| 1980 | idx = context->name_count - 1; | 2021 | goto out; |
| 1981 | else if (context->name_count > 1 | ||
| 1982 | && context->names[context->name_count-2].name | ||
| 1983 | && context->names[context->name_count-2].name == name) | ||
| 1984 | idx = context->name_count - 2; | ||
| 1985 | else { | ||
| 1986 | /* FIXME: how much do we care about inodes that have no | ||
| 1987 | * associated name? */ | ||
| 1988 | if (audit_inc_name_count(context, inode)) | ||
| 1989 | return; | ||
| 1990 | idx = context->name_count - 1; | ||
| 1991 | context->names[idx].name = NULL; | ||
| 1992 | } | 2022 | } |
| 2023 | |||
| 2024 | /* unable to find the name from a previous getname() */ | ||
| 2025 | n = audit_alloc_name(context); | ||
| 2026 | if (!n) | ||
| 2027 | return; | ||
| 2028 | out: | ||
| 1993 | handle_path(dentry); | 2029 | handle_path(dentry); |
| 1994 | audit_copy_inode(&context->names[idx], dentry, inode); | 2030 | audit_copy_inode(n, dentry, inode); |
| 1995 | } | 2031 | } |
| 1996 | 2032 | ||
| 1997 | /** | 2033 | /** |
| @@ -2010,11 +2046,11 @@ void __audit_inode(const char *name, const struct dentry *dentry) | |||
| 2010 | void __audit_inode_child(const struct dentry *dentry, | 2046 | void __audit_inode_child(const struct dentry *dentry, |
| 2011 | const struct inode *parent) | 2047 | const struct inode *parent) |
| 2012 | { | 2048 | { |
| 2013 | int idx; | ||
| 2014 | struct audit_context *context = current->audit_context; | 2049 | struct audit_context *context = current->audit_context; |
| 2015 | const char *found_parent = NULL, *found_child = NULL; | 2050 | const char *found_parent = NULL, *found_child = NULL; |
| 2016 | const struct inode *inode = dentry->d_inode; | 2051 | const struct inode *inode = dentry->d_inode; |
| 2017 | const char *dname = dentry->d_name.name; | 2052 | const char *dname = dentry->d_name.name; |
| 2053 | struct audit_names *n; | ||
| 2018 | int dirlen = 0; | 2054 | int dirlen = 0; |
| 2019 | 2055 | ||
| 2020 | if (!context->in_syscall) | 2056 | if (!context->in_syscall) |
| @@ -2024,9 +2060,7 @@ void __audit_inode_child(const struct dentry *dentry, | |||
| 2024 | handle_one(inode); | 2060 | handle_one(inode); |
| 2025 | 2061 | ||
| 2026 | /* parent is more likely, look for it first */ | 2062 | /* parent is more likely, look for it first */ |
| 2027 | for (idx = 0; idx < context->name_count; idx++) { | 2063 | list_for_each_entry(n, &context->names_list, list) { |
| 2028 | struct audit_names *n = &context->names[idx]; | ||
| 2029 | |||
| 2030 | if (!n->name) | 2064 | if (!n->name) |
| 2031 | continue; | 2065 | continue; |
| 2032 | 2066 | ||
| @@ -2039,9 +2073,7 @@ void __audit_inode_child(const struct dentry *dentry, | |||
| 2039 | } | 2073 | } |
| 2040 | 2074 | ||
| 2041 | /* no matching parent, look for matching child */ | 2075 | /* no matching parent, look for matching child */ |
| 2042 | for (idx = 0; idx < context->name_count; idx++) { | 2076 | list_for_each_entry(n, &context->names_list, list) { |
| 2043 | struct audit_names *n = &context->names[idx]; | ||
| 2044 | |||
| 2045 | if (!n->name) | 2077 | if (!n->name) |
| 2046 | continue; | 2078 | continue; |
| 2047 | 2079 | ||
| @@ -2059,34 +2091,29 @@ void __audit_inode_child(const struct dentry *dentry, | |||
| 2059 | 2091 | ||
| 2060 | add_names: | 2092 | add_names: |
| 2061 | if (!found_parent) { | 2093 | if (!found_parent) { |
| 2062 | if (audit_inc_name_count(context, parent)) | 2094 | n = audit_alloc_name(context); |
| 2095 | if (!n) | ||
| 2063 | return; | 2096 | return; |
| 2064 | idx = context->name_count - 1; | 2097 | audit_copy_inode(n, NULL, parent); |
| 2065 | context->names[idx].name = NULL; | ||
| 2066 | audit_copy_inode(&context->names[idx], NULL, parent); | ||
| 2067 | } | 2098 | } |
| 2068 | 2099 | ||
| 2069 | if (!found_child) { | 2100 | if (!found_child) { |
| 2070 | if (audit_inc_name_count(context, inode)) | 2101 | n = audit_alloc_name(context); |
| 2102 | if (!n) | ||
| 2071 | return; | 2103 | return; |
| 2072 | idx = context->name_count - 1; | ||
| 2073 | 2104 | ||
| 2074 | /* Re-use the name belonging to the slot for a matching parent | 2105 | /* Re-use the name belonging to the slot for a matching parent |
| 2075 | * directory. All names for this context are relinquished in | 2106 | * directory. All names for this context are relinquished in |
| 2076 | * audit_free_names() */ | 2107 | * audit_free_names() */ |
| 2077 | if (found_parent) { | 2108 | if (found_parent) { |
| 2078 | context->names[idx].name = found_parent; | 2109 | n->name = found_parent; |
| 2079 | context->names[idx].name_len = AUDIT_NAME_FULL; | 2110 | n->name_len = AUDIT_NAME_FULL; |
| 2080 | /* don't call __putname() */ | 2111 | /* don't call __putname() */ |
| 2081 | context->names[idx].name_put = 0; | 2112 | n->name_put = false; |
| 2082 | } else { | ||
| 2083 | context->names[idx].name = NULL; | ||
| 2084 | } | 2113 | } |
| 2085 | 2114 | ||
| 2086 | if (inode) | 2115 | if (inode) |
| 2087 | audit_copy_inode(&context->names[idx], NULL, inode); | 2116 | audit_copy_inode(n, NULL, inode); |
| 2088 | else | ||
| 2089 | context->names[idx].ino = (unsigned long)-1; | ||
| 2090 | } | 2117 | } |
| 2091 | } | 2118 | } |
| 2092 | EXPORT_SYMBOL_GPL(__audit_inode_child); | 2119 | EXPORT_SYMBOL_GPL(__audit_inode_child); |
