aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 20:01:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 20:01:41 -0400
commit48aab2f79dfc1357c48ce22ff5c989b52a590069 (patch)
tree7f690fe147bccc24b7a017845dbe9a99d7978b5f /security
parentf7493e5d9cc10ac97cf1f1579fdc14117460b40b (diff)
security: optimize avc_audit() common path
avc_audit() did a lot of jumping around and had a big stack frame, all for the uncommon case. Split up the uncommon case (which we really can't make go fast anyway) into its own slow function, and mark the conditional branches appropriately for the common likely case. This causes avc_audit() to no longer show up as one of the hottest functions on the branch profiles (the new "perf -b" thing), and makes the cycle profiles look really nice and dense too. The whole audit path is still annoyingly very much one of the biggest costs of name lookup, so these things are worth optimizing for. I wish we could just tell people to turn it off, but realistically we do need it: we just need to make sure that the overhead of the necessary evil is as low as possible. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/avc.c70
1 files changed, 41 insertions, 29 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index dca1c22d9276..6989472d0957 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -457,6 +457,42 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
457 ad->selinux_audit_data.tclass); 457 ad->selinux_audit_data.tclass);
458} 458}
459 459
460/* This is the slow part of avc audit with big stack footprint */
461static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
462 u32 requested, u32 audited, u32 denied,
463 struct av_decision *avd, struct common_audit_data *a,
464 unsigned flags)
465{
466 struct common_audit_data stack_data;
467
468 if (!a) {
469 a = &stack_data;
470 COMMON_AUDIT_DATA_INIT(a, NONE);
471 }
472
473 /*
474 * When in a RCU walk do the audit on the RCU retry. This is because
475 * the collection of the dname in an inode audit message is not RCU
476 * safe. Note this may drop some audits when the situation changes
477 * during retry. However this is logically just as if the operation
478 * happened a little later.
479 */
480 if ((a->type == LSM_AUDIT_DATA_INODE) &&
481 (flags & MAY_NOT_BLOCK))
482 return -ECHILD;
483
484 a->selinux_audit_data.tclass = tclass;
485 a->selinux_audit_data.requested = requested;
486 a->selinux_audit_data.ssid = ssid;
487 a->selinux_audit_data.tsid = tsid;
488 a->selinux_audit_data.audited = audited;
489 a->selinux_audit_data.denied = denied;
490 a->lsm_pre_audit = avc_audit_pre_callback;
491 a->lsm_post_audit = avc_audit_post_callback;
492 common_lsm_audit(a);
493 return 0;
494}
495
460/** 496/**
461 * avc_audit - Audit the granting or denial of permissions. 497 * avc_audit - Audit the granting or denial of permissions.
462 * @ssid: source security identifier 498 * @ssid: source security identifier
@@ -482,10 +518,9 @@ int avc_audit(u32 ssid, u32 tsid,
482 struct av_decision *avd, int result, struct common_audit_data *a, 518 struct av_decision *avd, int result, struct common_audit_data *a,
483 unsigned flags) 519 unsigned flags)
484{ 520{
485 struct common_audit_data stack_data;
486 u32 denied, audited; 521 u32 denied, audited;
487 denied = requested & ~avd->allowed; 522 denied = requested & ~avd->allowed;
488 if (denied) { 523 if (unlikely(denied)) {
489 audited = denied & avd->auditdeny; 524 audited = denied & avd->auditdeny;
490 /* 525 /*
491 * a->selinux_audit_data.auditdeny is TRICKY! Setting a bit in 526 * a->selinux_audit_data.auditdeny is TRICKY! Setting a bit in
@@ -511,35 +546,12 @@ int avc_audit(u32 ssid, u32 tsid,
511 audited = denied = requested; 546 audited = denied = requested;
512 else 547 else
513 audited = requested & avd->auditallow; 548 audited = requested & avd->auditallow;
514 if (!audited) 549 if (likely(!audited))
515 return 0; 550 return 0;
516 551
517 if (!a) { 552 return slow_avc_audit(ssid, tsid, tclass,
518 a = &stack_data; 553 requested, audited, denied,
519 COMMON_AUDIT_DATA_INIT(a, NONE); 554 avd, a, flags);
520 }
521
522 /*
523 * When in a RCU walk do the audit on the RCU retry. This is because
524 * the collection of the dname in an inode audit message is not RCU
525 * safe. Note this may drop some audits when the situation changes
526 * during retry. However this is logically just as if the operation
527 * happened a little later.
528 */
529 if ((a->type == LSM_AUDIT_DATA_INODE) &&
530 (flags & MAY_NOT_BLOCK))
531 return -ECHILD;
532
533 a->selinux_audit_data.tclass = tclass;
534 a->selinux_audit_data.requested = requested;
535 a->selinux_audit_data.ssid = ssid;
536 a->selinux_audit_data.tsid = tsid;
537 a->selinux_audit_data.audited = audited;
538 a->selinux_audit_data.denied = denied;
539 a->lsm_pre_audit = avc_audit_pre_callback;
540 a->lsm_post_audit = avc_audit_post_callback;
541 common_lsm_audit(a);
542 return 0;
543} 555}
544 556
545/** 557/**