aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smack_access.c
diff options
context:
space:
mode:
authorCasey Schaufler <casey@schaufler-ca.com>2011-09-20 15:24:36 -0400
committerCasey Schaufler <cschaufler@cschaufler-intel.(none)>2011-10-12 17:23:13 -0400
commit272cd7a8c67dd40a31ecff76a503bbb84707f757 (patch)
tree467f83c94eb14f8f34508efe891c0dcc62a7ac24 /security/smack/smack_access.c
parent828716c28fe4aa232ea280ea8ed6fb103eefb6ac (diff)
Smack: Rule list lookup performance
This patch is targeted for the smack-next tree. Smack access checks suffer from two significant performance issues. In cases where there are large numbers of rules the search of the single list of rules is wasteful. Comparing the string values of the smack labels is less efficient than a numeric comparison would. These changes take advantage of the Smack label list, which maintains the mapping of Smack labels to secids and optional CIPSO labels. Because the labels are kept perpetually, an access check can be done strictly based on the address of the label in the list without ever looking at the label itself. Rather than keeping one global list of rules the rules with a particular subject label can be based off of that label list entry. The access check need never look at entries that do not use the current subject label. This requires that packets coming off the network with CIPSO direct Smack labels that have never been seen before be treated carefully. The only case where they could be delivered is where the receiving socket has an IPIN star label, so that case is explicitly addressed. On a system with 39,800 rules (200 labels in all permutations) a system with this patch runs an access speed test in 5% of the time of the old version. That should be a best case improvement. If all of the rules are associated with the same subject label and all of the accesses are for processes with that label (unlikely) the improvement is about 30%. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Diffstat (limited to 'security/smack/smack_access.c')
-rw-r--r--security/smack/smack_access.c113
1 files changed, 56 insertions, 57 deletions
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 9637e107f7e..a885f628f56 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -77,14 +77,19 @@ int log_policy = SMACK_AUDIT_DENIED;
77 * entry is found returns -ENOENT. 77 * entry is found returns -ENOENT.
78 * 78 *
79 * NOTE: 79 * NOTE:
80 * Even though Smack labels are usually shared on smack_list
81 * labels that come in off the network can't be imported
82 * and added to the list for locking reasons.
83 * 80 *
84 * Therefore, it is necessary to check the contents of the labels, 81 * Earlier versions of this function allowed for labels that
85 * not just the pointer values. Of course, in most cases the labels 82 * were not on the label list. This was done to allow for
86 * will be on the list, so checking the pointers may be a worthwhile 83 * labels to come over the network that had never been seen
87 * optimization. 84 * before on this host. Unless the receiving socket has the
85 * star label this will always result in a failure check. The
86 * star labeled socket case is now handled in the networking
87 * hooks so there is no case where the label is not on the
88 * label list. Checking to see if the address of two labels
89 * is the same is now a reliable test.
90 *
91 * Do the object check first because that is more
92 * likely to differ.
88 */ 93 */
89int smk_access_entry(char *subject_label, char *object_label, 94int smk_access_entry(char *subject_label, char *object_label,
90 struct list_head *rule_list) 95 struct list_head *rule_list)
@@ -93,13 +98,10 @@ int smk_access_entry(char *subject_label, char *object_label,
93 struct smack_rule *srp; 98 struct smack_rule *srp;
94 99
95 list_for_each_entry_rcu(srp, rule_list, list) { 100 list_for_each_entry_rcu(srp, rule_list, list) {
96 if (srp->smk_subject == subject_label || 101 if (srp->smk_object == object_label &&
97 strcmp(srp->smk_subject, subject_label) == 0) { 102 srp->smk_subject == subject_label) {
98 if (srp->smk_object == object_label || 103 may = srp->smk_access;
99 strcmp(srp->smk_object, object_label) == 0) { 104 break;
100 may = srp->smk_access;
101 break;
102 }
103 } 105 }
104 } 106 }
105 107
@@ -117,18 +119,12 @@ int smk_access_entry(char *subject_label, char *object_label,
117 * access rule list and returns 0 if the access is permitted, 119 * access rule list and returns 0 if the access is permitted,
118 * non zero otherwise. 120 * non zero otherwise.
119 * 121 *
120 * Even though Smack labels are usually shared on smack_list 122 * Smack labels are shared on smack_list
121 * labels that come in off the network can't be imported
122 * and added to the list for locking reasons.
123 *
124 * Therefore, it is necessary to check the contents of the labels,
125 * not just the pointer values. Of course, in most cases the labels
126 * will be on the list, so checking the pointers may be a worthwhile
127 * optimization.
128 */ 123 */
129int smk_access(char *subject_label, char *object_label, int request, 124int smk_access(char *subject_label, char *object_label, int request,
130 struct smk_audit_info *a) 125 struct smk_audit_info *a)
131{ 126{
127 struct smack_known *skp;
132 int may = MAY_NOT; 128 int may = MAY_NOT;
133 int rc = 0; 129 int rc = 0;
134 130
@@ -137,8 +133,7 @@ int smk_access(char *subject_label, char *object_label, int request,
137 * 133 *
138 * A star subject can't access any object. 134 * A star subject can't access any object.
139 */ 135 */
140 if (subject_label == smack_known_star.smk_known || 136 if (subject_label == smack_known_star.smk_known) {
141 strcmp(subject_label, smack_known_star.smk_known) == 0) {
142 rc = -EACCES; 137 rc = -EACCES;
143 goto out_audit; 138 goto out_audit;
144 } 139 }
@@ -148,33 +143,27 @@ int smk_access(char *subject_label, char *object_label, int request,
148 * An internet subject can access any object. 143 * An internet subject can access any object.
149 */ 144 */
150 if (object_label == smack_known_web.smk_known || 145 if (object_label == smack_known_web.smk_known ||
151 subject_label == smack_known_web.smk_known || 146 subject_label == smack_known_web.smk_known)
152 strcmp(object_label, smack_known_web.smk_known) == 0 ||
153 strcmp(subject_label, smack_known_web.smk_known) == 0)
154 goto out_audit; 147 goto out_audit;
155 /* 148 /*
156 * A star object can be accessed by any subject. 149 * A star object can be accessed by any subject.
157 */ 150 */
158 if (object_label == smack_known_star.smk_known || 151 if (object_label == smack_known_star.smk_known)
159 strcmp(object_label, smack_known_star.smk_known) == 0)
160 goto out_audit; 152 goto out_audit;
161 /* 153 /*
162 * An object can be accessed in any way by a subject 154 * An object can be accessed in any way by a subject
163 * with the same label. 155 * with the same label.
164 */ 156 */
165 if (subject_label == object_label || 157 if (subject_label == object_label)
166 strcmp(subject_label, object_label) == 0)
167 goto out_audit; 158 goto out_audit;
168 /* 159 /*
169 * A hat subject can read any object. 160 * A hat subject can read any object.
170 * A floor object can be read by any subject. 161 * A floor object can be read by any subject.
171 */ 162 */
172 if ((request & MAY_ANYREAD) == request) { 163 if ((request & MAY_ANYREAD) == request) {
173 if (object_label == smack_known_floor.smk_known || 164 if (object_label == smack_known_floor.smk_known)
174 strcmp(object_label, smack_known_floor.smk_known) == 0)
175 goto out_audit; 165 goto out_audit;
176 if (subject_label == smack_known_hat.smk_known || 166 if (subject_label == smack_known_hat.smk_known)
177 strcmp(subject_label, smack_known_hat.smk_known) == 0)
178 goto out_audit; 167 goto out_audit;
179 } 168 }
180 /* 169 /*
@@ -184,8 +173,9 @@ int smk_access(char *subject_label, char *object_label, int request,
184 * good. A negative response from smk_access_entry() 173 * good. A negative response from smk_access_entry()
185 * indicates there is no entry for this pair. 174 * indicates there is no entry for this pair.
186 */ 175 */
176 skp = smk_find_entry(subject_label);
187 rcu_read_lock(); 177 rcu_read_lock();
188 may = smk_access_entry(subject_label, object_label, &smack_rule_list); 178 may = smk_access_entry(subject_label, object_label, &skp->smk_rules);
189 rcu_read_unlock(); 179 rcu_read_unlock();
190 180
191 if (may > 0 && (request & may) == request) 181 if (may > 0 && (request & may) == request)
@@ -344,6 +334,25 @@ void smack_log(char *subject_label, char *object_label, int request,
344static DEFINE_MUTEX(smack_known_lock); 334static DEFINE_MUTEX(smack_known_lock);
345 335
346/** 336/**
337 * smk_find_entry - find a label on the list, return the list entry
338 * @string: a text string that might be a Smack label
339 *
340 * Returns a pointer to the entry in the label list that
341 * matches the passed string.
342 */
343struct smack_known *smk_find_entry(const char *string)
344{
345 struct smack_known *skp;
346
347 list_for_each_entry_rcu(skp, &smack_known_list, list) {
348 if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0)
349 return skp;
350 }
351
352 return NULL;
353}
354
355/**
347 * smk_import_entry - import a label, return the list entry 356 * smk_import_entry - import a label, return the list entry
348 * @string: a text string that might be a Smack label 357 * @string: a text string that might be a Smack label
349 * @len: the maximum size, or zero if it is NULL terminated. 358 * @len: the maximum size, or zero if it is NULL terminated.
@@ -378,21 +387,17 @@ struct smack_known *smk_import_entry(const char *string, int len)
378 387
379 mutex_lock(&smack_known_lock); 388 mutex_lock(&smack_known_lock);
380 389
381 found = 0; 390 skp = smk_find_entry(smack);
382 list_for_each_entry_rcu(skp, &smack_known_list, list) {
383 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
384 found = 1;
385 break;
386 }
387 }
388 391
389 if (found == 0) { 392 if (skp == NULL) {
390 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); 393 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
391 if (skp != NULL) { 394 if (skp != NULL) {
392 strncpy(skp->smk_known, smack, SMK_MAXLEN); 395 strncpy(skp->smk_known, smack, SMK_MAXLEN);
393 skp->smk_secid = smack_next_secid++; 396 skp->smk_secid = smack_next_secid++;
394 skp->smk_cipso = NULL; 397 skp->smk_cipso = NULL;
398 INIT_LIST_HEAD(&skp->smk_rules);
395 spin_lock_init(&skp->smk_cipsolock); 399 spin_lock_init(&skp->smk_cipsolock);
400 mutex_init(&skp->smk_rules_lock);
396 /* 401 /*
397 * Make sure that the entry is actually 402 * Make sure that the entry is actually
398 * filled before putting it on the list. 403 * filled before putting it on the list.
@@ -480,19 +485,12 @@ u32 smack_to_secid(const char *smack)
480 * smack_from_cipso - find the Smack label associated with a CIPSO option 485 * smack_from_cipso - find the Smack label associated with a CIPSO option
481 * @level: Bell & LaPadula level from the network 486 * @level: Bell & LaPadula level from the network
482 * @cp: Bell & LaPadula categories from the network 487 * @cp: Bell & LaPadula categories from the network
483 * @result: where to put the Smack value
484 * 488 *
485 * This is a simple lookup in the label table. 489 * This is a simple lookup in the label table.
486 * 490 *
487 * This is an odd duck as far as smack handling goes in that 491 * Return the matching label from the label list or NULL.
488 * it sends back a copy of the smack label rather than a pointer
489 * to the master list. This is done because it is possible for
490 * a foreign host to send a smack label that is new to this
491 * machine and hence not on the list. That would not be an
492 * issue except that adding an entry to the master list can't
493 * be done at that point.
494 */ 492 */
495void smack_from_cipso(u32 level, char *cp, char *result) 493char *smack_from_cipso(u32 level, char *cp)
496{ 494{
497 struct smack_known *kp; 495 struct smack_known *kp;
498 char *final = NULL; 496 char *final = NULL;
@@ -509,12 +507,13 @@ void smack_from_cipso(u32 level, char *cp, char *result)
509 final = kp->smk_known; 507 final = kp->smk_known;
510 508
511 spin_unlock_bh(&kp->smk_cipsolock); 509 spin_unlock_bh(&kp->smk_cipsolock);
510
511 if (final != NULL)
512 break;
512 } 513 }
513 rcu_read_unlock(); 514 rcu_read_unlock();
514 if (final == NULL) 515
515 final = smack_known_huh.smk_known; 516 return final;
516 strncpy(result, final, SMK_MAXLEN);
517 return;
518} 517}
519 518
520/** 519/**