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/auditsc.c | |
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/auditsc.c')
-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); |