Commit f562988350361bf4118dd3c3e192dff763b493d9
Committed by
Jiri Kosina
1 parent
80e8ff562a
Exists in
master
and in
20 other branches
audit: acquire creds selectively to reduce atomic op overhead
Commit c69e8d9c01db ("CRED: Use RCU to access another task's creds and to release a task's own creds") added calls to get_task_cred and put_cred in audit_filter_rules. Profiling with a large number of audit rules active on the exit chain shows that we are spending upto 48% in this routine for syscall intensive tests, most of which is in the atomic ops. 1. The code should be accessing tsk->cred rather than tsk->real_cred. 2. Since tsk is current (or tsk is being created by copy_process) access to tsk->cred without rcu read lock is possible. At the request of the audit maintainer, a new flag has been added to audit_filter_rules in order to make this explicit and guide future code. Signed-off-by: Tony Jones <tonyj@suse.de> Acked-by: Eric Paris <eparis@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Showing 1 changed file with 17 additions and 10 deletions Side-by-side Diff
kernel/auditsc.c
| ... | ... | @@ -443,17 +443,25 @@ |
| 443 | 443 | |
| 444 | 444 | /* Determine if any context name data matches a rule's watch data */ |
| 445 | 445 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 |
| 446 | - * otherwise. */ | |
| 446 | + * otherwise. | |
| 447 | + * | |
| 448 | + * If task_creation is true, this is an explicit indication that we are | |
| 449 | + * filtering a task rule at task creation time. This and tsk == current are | |
| 450 | + * the only situations where tsk->cred may be accessed without an rcu read lock. | |
| 451 | + */ | |
| 447 | 452 | static int audit_filter_rules(struct task_struct *tsk, |
| 448 | 453 | struct audit_krule *rule, |
| 449 | 454 | struct audit_context *ctx, |
| 450 | 455 | struct audit_names *name, |
| 451 | - enum audit_state *state) | |
| 456 | + enum audit_state *state, | |
| 457 | + bool task_creation) | |
| 452 | 458 | { |
| 453 | - const struct cred *cred = get_task_cred(tsk); | |
| 459 | + const struct cred *cred; | |
| 454 | 460 | int i, j, need_sid = 1; |
| 455 | 461 | u32 sid; |
| 456 | 462 | |
| 463 | + cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); | |
| 464 | + | |
| 457 | 465 | for (i = 0; i < rule->field_count; i++) { |
| 458 | 466 | struct audit_field *f = &rule->fields[i]; |
| 459 | 467 | int result = 0; |
| 460 | 468 | |
| ... | ... | @@ -637,10 +645,8 @@ |
| 637 | 645 | break; |
| 638 | 646 | } |
| 639 | 647 | |
| 640 | - if (!result) { | |
| 641 | - put_cred(cred); | |
| 648 | + if (!result) | |
| 642 | 649 | return 0; |
| 643 | - } | |
| 644 | 650 | } |
| 645 | 651 | |
| 646 | 652 | if (ctx) { |
| ... | ... | @@ -656,7 +662,6 @@ |
| 656 | 662 | case AUDIT_NEVER: *state = AUDIT_DISABLED; break; |
| 657 | 663 | case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; |
| 658 | 664 | } |
| 659 | - put_cred(cred); | |
| 660 | 665 | return 1; |
| 661 | 666 | } |
| 662 | 667 | |
| ... | ... | @@ -671,7 +676,8 @@ |
| 671 | 676 | |
| 672 | 677 | rcu_read_lock(); |
| 673 | 678 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { |
| 674 | - if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) { | |
| 679 | + if (audit_filter_rules(tsk, &e->rule, NULL, NULL, | |
| 680 | + &state, true)) { | |
| 675 | 681 | if (state == AUDIT_RECORD_CONTEXT) |
| 676 | 682 | *key = kstrdup(e->rule.filterkey, GFP_ATOMIC); |
| 677 | 683 | rcu_read_unlock(); |
| ... | ... | @@ -705,7 +711,7 @@ |
| 705 | 711 | list_for_each_entry_rcu(e, list, list) { |
| 706 | 712 | if ((e->rule.mask[word] & bit) == bit && |
| 707 | 713 | audit_filter_rules(tsk, &e->rule, ctx, NULL, |
| 708 | - &state)) { | |
| 714 | + &state, false)) { | |
| 709 | 715 | rcu_read_unlock(); |
| 710 | 716 | ctx->current_state = state; |
| 711 | 717 | return state; |
| ... | ... | @@ -743,7 +749,8 @@ |
| 743 | 749 | |
| 744 | 750 | list_for_each_entry_rcu(e, list, list) { |
| 745 | 751 | if ((e->rule.mask[word] & bit) == bit && |
| 746 | - audit_filter_rules(tsk, &e->rule, ctx, n, &state)) { | |
| 752 | + audit_filter_rules(tsk, &e->rule, ctx, n, | |
| 753 | + &state, false)) { | |
| 747 | 754 | rcu_read_unlock(); |
| 748 | 755 | ctx->current_state = state; |
| 749 | 756 | return; |