aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2012-04-04 15:01:42 -0400
committerEric Paris <eparis@redhat.com>2012-04-09 12:22:59 -0400
commit2e33405785d3eaec303c54b4a10afdebf3729da7 (patch)
treef4c0d114503796e9f958341393e336f76a7eb6dd /security/selinux
parent154c50ca4eb9ae472f50b6a481213e21ead4457d (diff)
SELinux: delay initialization of audit data in selinux_inode_permission
We pay a rather large overhead initializing the common_audit_data. Since we only need this information if we actually emit an audit message there is little need to set it up in the hot path. This patch splits the functionality of avc_has_perm() into avc_has_perm_noaudit(), avc_audit_required() and slow_avc_audit(). But we take care of setting up to audit between required() and the actual audit call. Thus saving measurable time in a hot path. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/avc.c63
-rw-r--r--security/selinux/hooks.c30
-rw-r--r--security/selinux/include/avc.h82
3 files changed, 105 insertions, 70 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 8ee42b2a5f19..1a04247e3a17 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -458,7 +458,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
458} 458}
459 459
460/* This is the slow part of avc audit with big stack footprint */ 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, 461noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
462 u32 requested, u32 audited, u32 denied, 462 u32 requested, u32 audited, u32 denied,
463 struct common_audit_data *a, 463 struct common_audit_data *a,
464 unsigned flags) 464 unsigned flags)
@@ -497,67 +497,6 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
497} 497}
498 498
499/** 499/**
500 * avc_audit - Audit the granting or denial of permissions.
501 * @ssid: source security identifier
502 * @tsid: target security identifier
503 * @tclass: target security class
504 * @requested: requested permissions
505 * @avd: access vector decisions
506 * @result: result from avc_has_perm_noaudit
507 * @a: auxiliary audit data
508 * @flags: VFS walk flags
509 *
510 * Audit the granting or denial of permissions in accordance
511 * with the policy. This function is typically called by
512 * avc_has_perm() after a permission check, but can also be
513 * called directly by callers who use avc_has_perm_noaudit()
514 * in order to separate the permission check from the auditing.
515 * For example, this separation is useful when the permission check must
516 * be performed under a lock, to allow the lock to be released
517 * before calling the auditing code.
518 */
519inline int avc_audit(u32 ssid, u32 tsid,
520 u16 tclass, u32 requested,
521 struct av_decision *avd, int result, struct common_audit_data *a,
522 unsigned flags)
523{
524 u32 denied, audited;
525 denied = requested & ~avd->allowed;
526 if (unlikely(denied)) {
527 audited = denied & avd->auditdeny;
528 /*
529 * a->selinux_audit_data->auditdeny is TRICKY! Setting a bit in
530 * this field means that ANY denials should NOT be audited if
531 * the policy contains an explicit dontaudit rule for that
532 * permission. Take notice that this is unrelated to the
533 * actual permissions that were denied. As an example lets
534 * assume:
535 *
536 * denied == READ
537 * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
538 * selinux_audit_data->auditdeny & ACCESS == 1
539 *
540 * We will NOT audit the denial even though the denied
541 * permission was READ and the auditdeny checks were for
542 * ACCESS
543 */
544 if (a &&
545 a->selinux_audit_data->auditdeny &&
546 !(a->selinux_audit_data->auditdeny & avd->auditdeny))
547 audited = 0;
548 } else if (result)
549 audited = denied = requested;
550 else
551 audited = requested & avd->auditallow;
552 if (likely(!audited))
553 return 0;
554
555 return slow_avc_audit(ssid, tsid, tclass,
556 requested, audited, denied,
557 a, flags);
558}
559
560/**
561 * avc_add_callback - Register a callback for security events. 500 * avc_add_callback - Register a callback for security events.
562 * @callback: callback function 501 * @callback: callback function
563 * @events: security events 502 * @events: security events
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c3ee902306d8..c99027dc0b36 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2684,6 +2684,11 @@ static int selinux_inode_permission(struct inode *inode, int mask)
2684 u32 perms; 2684 u32 perms;
2685 bool from_access; 2685 bool from_access;
2686 unsigned flags = mask & MAY_NOT_BLOCK; 2686 unsigned flags = mask & MAY_NOT_BLOCK;
2687 struct inode_security_struct *isec;
2688 u32 sid;
2689 struct av_decision avd;
2690 int rc, rc2;
2691 u32 audited, denied;
2687 2692
2688 from_access = mask & MAY_ACCESS; 2693 from_access = mask & MAY_ACCESS;
2689 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); 2694 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
@@ -2692,6 +2697,23 @@ static int selinux_inode_permission(struct inode *inode, int mask)
2692 if (!mask) 2697 if (!mask)
2693 return 0; 2698 return 0;
2694 2699
2700 validate_creds(cred);
2701
2702 if (unlikely(IS_PRIVATE(inode)))
2703 return 0;
2704
2705 perms = file_mask_to_av(inode->i_mode, mask);
2706
2707 sid = cred_sid(cred);
2708 isec = inode->i_security;
2709
2710 rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
2711 audited = avc_audit_required(perms, &avd, rc,
2712 from_access ? FILE__AUDIT_ACCESS : 0,
2713 &denied);
2714 if (likely(!audited))
2715 return rc;
2716
2695 COMMON_AUDIT_DATA_INIT(&ad, INODE); 2717 COMMON_AUDIT_DATA_INIT(&ad, INODE);
2696 ad.selinux_audit_data = &sad; 2718 ad.selinux_audit_data = &sad;
2697 ad.u.inode = inode; 2719 ad.u.inode = inode;
@@ -2699,9 +2721,11 @@ static int selinux_inode_permission(struct inode *inode, int mask)
2699 if (from_access) 2721 if (from_access)
2700 ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS; 2722 ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
2701 2723
2702 perms = file_mask_to_av(inode->i_mode, mask); 2724 rc2 = slow_avc_audit(sid, isec->sid, isec->sclass, perms,
2703 2725 audited, denied, &ad, flags);
2704 return inode_has_perm(cred, inode, perms, &ad, flags); 2726 if (rc2)
2727 return rc2;
2728 return rc;
2705} 2729}
2706 2730
2707static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) 2731static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 1931370233d7..e4e50bb218ee 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -77,11 +77,83 @@ struct selinux_audit_data {
77 77
78void __init avc_init(void); 78void __init avc_init(void);
79 79
80int avc_audit(u32 ssid, u32 tsid, 80static inline u32 avc_audit_required(u32 requested,
81 u16 tclass, u32 requested, 81 struct av_decision *avd,
82 struct av_decision *avd, 82 int result,
83 int result, 83 u32 auditdeny,
84 struct common_audit_data *a, unsigned flags); 84 u32 *deniedp)
85{
86 u32 denied, audited;
87 denied = requested & ~avd->allowed;
88 if (unlikely(denied)) {
89 audited = denied & avd->auditdeny;
90 /*
91 * auditdeny is TRICKY! Setting a bit in
92 * this field means that ANY denials should NOT be audited if
93 * the policy contains an explicit dontaudit rule for that
94 * permission. Take notice that this is unrelated to the
95 * actual permissions that were denied. As an example lets
96 * assume:
97 *
98 * denied == READ
99 * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
100 * auditdeny & ACCESS == 1
101 *
102 * We will NOT audit the denial even though the denied
103 * permission was READ and the auditdeny checks were for
104 * ACCESS
105 */
106 if (auditdeny && !(auditdeny & avd->auditdeny))
107 audited = 0;
108 } else if (result)
109 audited = denied = requested;
110 else
111 audited = requested & avd->auditallow;
112 *deniedp = denied;
113 return audited;
114}
115
116int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
117 u32 requested, u32 audited, u32 denied,
118 struct common_audit_data *a,
119 unsigned flags);
120
121/**
122 * avc_audit - Audit the granting or denial of permissions.
123 * @ssid: source security identifier
124 * @tsid: target security identifier
125 * @tclass: target security class
126 * @requested: requested permissions
127 * @avd: access vector decisions
128 * @result: result from avc_has_perm_noaudit
129 * @a: auxiliary audit data
130 * @flags: VFS walk flags
131 *
132 * Audit the granting or denial of permissions in accordance
133 * with the policy. This function is typically called by
134 * avc_has_perm() after a permission check, but can also be
135 * called directly by callers who use avc_has_perm_noaudit()
136 * in order to separate the permission check from the auditing.
137 * For example, this separation is useful when the permission check must
138 * be performed under a lock, to allow the lock to be released
139 * before calling the auditing code.
140 */
141static inline int avc_audit(u32 ssid, u32 tsid,
142 u16 tclass, u32 requested,
143 struct av_decision *avd,
144 int result,
145 struct common_audit_data *a, unsigned flags)
146{
147 u32 audited, denied;
148 audited = avc_audit_required(requested, avd, result,
149 a ? a->selinux_audit_data->auditdeny : 0,
150 &denied);
151 if (likely(!audited))
152 return 0;
153 return slow_avc_audit(ssid, tsid, tclass,
154 requested, audited, denied,
155 a, flags);
156}
85 157
86#define AVC_STRICT 1 /* Ignore permissive mode. */ 158#define AVC_STRICT 1 /* Ignore permissive mode. */
87int avc_has_perm_noaudit(u32 ssid, u32 tsid, 159int avc_has_perm_noaudit(u32 ssid, u32 tsid,