diff options
Diffstat (limited to 'security/smack/smack_access.c')
-rw-r--r-- | security/smack/smack_access.c | 113 |
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 | */ |
89 | int smk_access_entry(char *subject_label, char *object_label, | 94 | int 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 | */ |
129 | int smk_access(char *subject_label, char *object_label, int request, | 124 | int 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, | |||
344 | static DEFINE_MUTEX(smack_known_lock); | 334 | static 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 | */ | ||
343 | struct 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 | */ |
495 | void smack_from_cipso(u32 level, char *cp, char *result) | 493 | char *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 | /** |