xref: /openbmc/linux/security/smack/smack_access.c (revision bc05aa6e)
1 /*
2  * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
3  *
4  *      This program is free software; you can redistribute it and/or modify
5  *      it under the terms of the GNU General Public License as published by
6  *      the Free Software Foundation, version 2.
7  *
8  * Author:
9  *      Casey Schaufler <casey@schaufler-ca.com>
10  *
11  */
12 
13 #include <linux/types.h>
14 #include <linux/slab.h>
15 #include <linux/fs.h>
16 #include <linux/sched.h>
17 #include "smack.h"
18 
19 struct smack_known smack_known_huh = {
20 	.smk_known	= "?",
21 	.smk_secid	= 2,
22 };
23 
24 struct smack_known smack_known_hat = {
25 	.smk_known	= "^",
26 	.smk_secid	= 3,
27 };
28 
29 struct smack_known smack_known_star = {
30 	.smk_known	= "*",
31 	.smk_secid	= 4,
32 };
33 
34 struct smack_known smack_known_floor = {
35 	.smk_known	= "_",
36 	.smk_secid	= 5,
37 };
38 
39 struct smack_known smack_known_web = {
40 	.smk_known	= "@",
41 	.smk_secid	= 7,
42 };
43 
44 LIST_HEAD(smack_known_list);
45 
46 /*
47  * The initial value needs to be bigger than any of the
48  * known values above.
49  */
50 static u32 smack_next_secid = 10;
51 
52 /*
53  * what events do we log
54  * can be overwritten at run-time by /smack/logging
55  */
56 int log_policy = SMACK_AUDIT_DENIED;
57 
58 /**
59  * smk_access_entry - look up matching access rule
60  * @subject_label: a pointer to the subject's Smack label
61  * @object_label: a pointer to the object's Smack label
62  * @rule_list: the list of rules to search
63  *
64  * This function looks up the subject/object pair in the
65  * access rule list and returns the access mode. If no
66  * entry is found returns -ENOENT.
67  *
68  * NOTE:
69  *
70  * Earlier versions of this function allowed for labels that
71  * were not on the label list. This was done to allow for
72  * labels to come over the network that had never been seen
73  * before on this host. Unless the receiving socket has the
74  * star label this will always result in a failure check. The
75  * star labeled socket case is now handled in the networking
76  * hooks so there is no case where the label is not on the
77  * label list. Checking to see if the address of two labels
78  * is the same is now a reliable test.
79  *
80  * Do the object check first because that is more
81  * likely to differ.
82  *
83  * Allowing write access implies allowing locking.
84  */
85 int smk_access_entry(char *subject_label, char *object_label,
86 			struct list_head *rule_list)
87 {
88 	int may = -ENOENT;
89 	struct smack_rule *srp;
90 
91 	list_for_each_entry_rcu(srp, rule_list, list) {
92 		if (srp->smk_object->smk_known == object_label &&
93 		    srp->smk_subject->smk_known == subject_label) {
94 			may = srp->smk_access;
95 			break;
96 		}
97 	}
98 
99 	/*
100 	 * MAY_WRITE implies MAY_LOCK.
101 	 */
102 	if ((may & MAY_WRITE) == MAY_WRITE)
103 		may |= MAY_LOCK;
104 	return may;
105 }
106 
107 /**
108  * smk_access - determine if a subject has a specific access to an object
109  * @subject: a pointer to the subject's Smack label entry
110  * @object: a pointer to the object's Smack label entry
111  * @request: the access requested, in "MAY" format
112  * @a : a pointer to the audit data
113  *
114  * This function looks up the subject/object pair in the
115  * access rule list and returns 0 if the access is permitted,
116  * non zero otherwise.
117  *
118  * Smack labels are shared on smack_list
119  */
120 int smk_access(struct smack_known *subject, struct smack_known *object,
121 	       int request, struct smk_audit_info *a)
122 {
123 	int may = MAY_NOT;
124 	int rc = 0;
125 
126 	/*
127 	 * Hardcoded comparisons.
128 	 */
129 	/*
130 	 * A star subject can't access any object.
131 	 */
132 	if (subject == &smack_known_star) {
133 		rc = -EACCES;
134 		goto out_audit;
135 	}
136 	/*
137 	 * An internet object can be accessed by any subject.
138 	 * Tasks cannot be assigned the internet label.
139 	 * An internet subject can access any object.
140 	 */
141 	if (object == &smack_known_web || subject == &smack_known_web)
142 		goto out_audit;
143 	/*
144 	 * A star object can be accessed by any subject.
145 	 */
146 	if (object == &smack_known_star)
147 		goto out_audit;
148 	/*
149 	 * An object can be accessed in any way by a subject
150 	 * with the same label.
151 	 */
152 	if (subject->smk_known == object->smk_known)
153 		goto out_audit;
154 	/*
155 	 * A hat subject can read or lock any object.
156 	 * A floor object can be read or locked by any subject.
157 	 */
158 	if ((request & MAY_ANYREAD) == request ||
159 	    (request & MAY_LOCK) == request) {
160 		if (object == &smack_known_floor)
161 			goto out_audit;
162 		if (subject == &smack_known_hat)
163 			goto out_audit;
164 	}
165 	/*
166 	 * Beyond here an explicit relationship is required.
167 	 * If the requested access is contained in the available
168 	 * access (e.g. read is included in readwrite) it's
169 	 * good. A negative response from smk_access_entry()
170 	 * indicates there is no entry for this pair.
171 	 */
172 	rcu_read_lock();
173 	may = smk_access_entry(subject->smk_known, object->smk_known,
174 			       &subject->smk_rules);
175 	rcu_read_unlock();
176 
177 	if (may <= 0 || (request & may) != request) {
178 		rc = -EACCES;
179 		goto out_audit;
180 	}
181 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
182 	/*
183 	 * Return a positive value if using bringup mode.
184 	 * This allows the hooks to identify checks that
185 	 * succeed because of "b" rules.
186 	 */
187 	if (may & MAY_BRINGUP)
188 		rc = SMACK_BRINGUP_ALLOW;
189 #endif
190 
191 out_audit:
192 
193 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
194 	if (rc < 0) {
195 		if (object == smack_unconfined)
196 			rc = SMACK_UNCONFINED_OBJECT;
197 		if (subject == smack_unconfined)
198 			rc = SMACK_UNCONFINED_SUBJECT;
199 	}
200 #endif
201 
202 #ifdef CONFIG_AUDIT
203 	if (a)
204 		smack_log(subject->smk_known, object->smk_known,
205 			  request, rc, a);
206 #endif
207 
208 	return rc;
209 }
210 
211 /**
212  * smk_tskacc - determine if a task has a specific access to an object
213  * @tsp: a pointer to the subject's task
214  * @obj_known: a pointer to the object's label entry
215  * @mode: the access requested, in "MAY" format
216  * @a : common audit data
217  *
218  * This function checks the subject task's label/object label pair
219  * in the access rule list and returns 0 if the access is permitted,
220  * non zero otherwise. It allows that the task may have the capability
221  * to override the rules.
222  */
223 int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
224 	       u32 mode, struct smk_audit_info *a)
225 {
226 	struct smack_known *sbj_known = smk_of_task(tsp);
227 	int may;
228 	int rc;
229 
230 	/*
231 	 * Check the global rule list
232 	 */
233 	rc = smk_access(sbj_known, obj_known, mode, NULL);
234 	if (rc >= 0) {
235 		/*
236 		 * If there is an entry in the task's rule list
237 		 * it can further restrict access.
238 		 */
239 		may = smk_access_entry(sbj_known->smk_known,
240 				       obj_known->smk_known,
241 				       &tsp->smk_rules);
242 		if (may < 0)
243 			goto out_audit;
244 		if ((mode & may) == mode)
245 			goto out_audit;
246 		rc = -EACCES;
247 	}
248 
249 	/*
250 	 * Allow for priviliged to override policy.
251 	 */
252 	if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE))
253 		rc = 0;
254 
255 out_audit:
256 #ifdef CONFIG_AUDIT
257 	if (a)
258 		smack_log(sbj_known->smk_known, obj_known->smk_known,
259 			  mode, rc, a);
260 #endif
261 	return rc;
262 }
263 
264 /**
265  * smk_curacc - determine if current has a specific access to an object
266  * @obj_known: a pointer to the object's Smack label entry
267  * @mode: the access requested, in "MAY" format
268  * @a : common audit data
269  *
270  * This function checks the current subject label/object label pair
271  * in the access rule list and returns 0 if the access is permitted,
272  * non zero otherwise. It allows that current may have the capability
273  * to override the rules.
274  */
275 int smk_curacc(struct smack_known *obj_known,
276 	       u32 mode, struct smk_audit_info *a)
277 {
278 	struct task_smack *tsp = current_security();
279 
280 	return smk_tskacc(tsp, obj_known, mode, a);
281 }
282 
283 #ifdef CONFIG_AUDIT
284 /**
285  * smack_str_from_perm : helper to transalate an int to a
286  * readable string
287  * @string : the string to fill
288  * @access : the int
289  *
290  */
291 static inline void smack_str_from_perm(char *string, int access)
292 {
293 	int i = 0;
294 
295 	if (access & MAY_READ)
296 		string[i++] = 'r';
297 	if (access & MAY_WRITE)
298 		string[i++] = 'w';
299 	if (access & MAY_EXEC)
300 		string[i++] = 'x';
301 	if (access & MAY_APPEND)
302 		string[i++] = 'a';
303 	if (access & MAY_TRANSMUTE)
304 		string[i++] = 't';
305 	if (access & MAY_LOCK)
306 		string[i++] = 'l';
307 	string[i] = '\0';
308 }
309 /**
310  * smack_log_callback - SMACK specific information
311  * will be called by generic audit code
312  * @ab : the audit_buffer
313  * @a  : audit_data
314  *
315  */
316 static void smack_log_callback(struct audit_buffer *ab, void *a)
317 {
318 	struct common_audit_data *ad = a;
319 	struct smack_audit_data *sad = ad->smack_audit_data;
320 	audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
321 			 ad->smack_audit_data->function,
322 			 sad->result ? "denied" : "granted");
323 	audit_log_format(ab, " subject=");
324 	audit_log_untrustedstring(ab, sad->subject);
325 	audit_log_format(ab, " object=");
326 	audit_log_untrustedstring(ab, sad->object);
327 	if (sad->request[0] == '\0')
328 		audit_log_format(ab, " labels_differ");
329 	else
330 		audit_log_format(ab, " requested=%s", sad->request);
331 }
332 
333 /**
334  *  smack_log - Audit the granting or denial of permissions.
335  *  @subject_label : smack label of the requester
336  *  @object_label  : smack label of the object being accessed
337  *  @request: requested permissions
338  *  @result: result from smk_access
339  *  @a:  auxiliary audit data
340  *
341  * Audit the granting or denial of permissions in accordance
342  * with the policy.
343  */
344 void smack_log(char *subject_label, char *object_label, int request,
345 	       int result, struct smk_audit_info *ad)
346 {
347 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
348 	char request_buffer[SMK_NUM_ACCESS_TYPE + 5];
349 #else
350 	char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
351 #endif
352 	struct smack_audit_data *sad;
353 	struct common_audit_data *a = &ad->a;
354 
355 	/* check if we have to log the current event */
356 	if (result < 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
357 		return;
358 	if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
359 		return;
360 
361 	sad = a->smack_audit_data;
362 
363 	if (sad->function == NULL)
364 		sad->function = "unknown";
365 
366 	/* end preparing the audit data */
367 	smack_str_from_perm(request_buffer, request);
368 	sad->subject = subject_label;
369 	sad->object  = object_label;
370 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
371 	/*
372 	 * The result may be positive in bringup mode.
373 	 * A positive result is an allow, but not for normal reasons.
374 	 * Mark it as successful, but don't filter it out even if
375 	 * the logging policy says to do so.
376 	 */
377 	if (result == SMACK_UNCONFINED_SUBJECT)
378 		strcat(request_buffer, "(US)");
379 	else if (result == SMACK_UNCONFINED_OBJECT)
380 		strcat(request_buffer, "(UO)");
381 
382 	if (result > 0)
383 		result = 0;
384 #endif
385 	sad->request = request_buffer;
386 	sad->result  = result;
387 
388 	common_lsm_audit(a, smack_log_callback, NULL);
389 }
390 #else /* #ifdef CONFIG_AUDIT */
391 void smack_log(char *subject_label, char *object_label, int request,
392                int result, struct smk_audit_info *ad)
393 {
394 }
395 #endif
396 
397 DEFINE_MUTEX(smack_known_lock);
398 
399 struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
400 
401 /**
402  * smk_insert_entry - insert a smack label into a hash map,
403  *
404  * this function must be called under smack_known_lock
405  */
406 void smk_insert_entry(struct smack_known *skp)
407 {
408 	unsigned int hash;
409 	struct hlist_head *head;
410 
411 	hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
412 	head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
413 
414 	hlist_add_head_rcu(&skp->smk_hashed, head);
415 	list_add_rcu(&skp->list, &smack_known_list);
416 }
417 
418 /**
419  * smk_find_entry - find a label on the list, return the list entry
420  * @string: a text string that might be a Smack label
421  *
422  * Returns a pointer to the entry in the label list that
423  * matches the passed string or NULL if not found.
424  */
425 struct smack_known *smk_find_entry(const char *string)
426 {
427 	unsigned int hash;
428 	struct hlist_head *head;
429 	struct smack_known *skp;
430 
431 	hash = full_name_hash(NULL, string, strlen(string));
432 	head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
433 
434 	hlist_for_each_entry_rcu(skp, head, smk_hashed)
435 		if (strcmp(skp->smk_known, string) == 0)
436 			return skp;
437 
438 	return NULL;
439 }
440 
441 /**
442  * smk_parse_smack - parse smack label from a text string
443  * @string: a text string that might contain a Smack label
444  * @len: the maximum size, or zero if it is NULL terminated.
445  *
446  * Returns a pointer to the clean label or an error code.
447  */
448 char *smk_parse_smack(const char *string, int len)
449 {
450 	char *smack;
451 	int i;
452 
453 	if (len <= 0)
454 		len = strlen(string) + 1;
455 
456 	/*
457 	 * Reserve a leading '-' as an indicator that
458 	 * this isn't a label, but an option to interfaces
459 	 * including /smack/cipso and /smack/cipso2
460 	 */
461 	if (string[0] == '-')
462 		return ERR_PTR(-EINVAL);
463 
464 	for (i = 0; i < len; i++)
465 		if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
466 		    string[i] == '"' || string[i] == '\\' || string[i] == '\'')
467 			break;
468 
469 	if (i == 0 || i >= SMK_LONGLABEL)
470 		return ERR_PTR(-EINVAL);
471 
472 	smack = kzalloc(i + 1, GFP_KERNEL);
473 	if (smack == NULL)
474 		return ERR_PTR(-ENOMEM);
475 
476 	strncpy(smack, string, i);
477 
478 	return smack;
479 }
480 
481 /**
482  * smk_netlbl_mls - convert a catset to netlabel mls categories
483  * @catset: the Smack categories
484  * @sap: where to put the netlabel categories
485  *
486  * Allocates and fills attr.mls
487  * Returns 0 on success, error code on failure.
488  */
489 int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
490 			int len)
491 {
492 	unsigned char *cp;
493 	unsigned char m;
494 	int cat;
495 	int rc;
496 	int byte;
497 
498 	sap->flags |= NETLBL_SECATTR_MLS_CAT;
499 	sap->attr.mls.lvl = level;
500 	sap->attr.mls.cat = NULL;
501 
502 	for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
503 		for (m = 0x80; m != 0; m >>= 1, cat++) {
504 			if ((m & *cp) == 0)
505 				continue;
506 			rc = netlbl_catmap_setbit(&sap->attr.mls.cat,
507 						  cat, GFP_KERNEL);
508 			if (rc < 0) {
509 				netlbl_catmap_free(sap->attr.mls.cat);
510 				return rc;
511 			}
512 		}
513 
514 	return 0;
515 }
516 
517 /**
518  * smk_import_entry - import a label, return the list entry
519  * @string: a text string that might be a Smack label
520  * @len: the maximum size, or zero if it is NULL terminated.
521  *
522  * Returns a pointer to the entry in the label list that
523  * matches the passed string, adding it if necessary,
524  * or an error code.
525  */
526 struct smack_known *smk_import_entry(const char *string, int len)
527 {
528 	struct smack_known *skp;
529 	char *smack;
530 	int slen;
531 	int rc;
532 
533 	smack = smk_parse_smack(string, len);
534 	if (IS_ERR(smack))
535 		return ERR_CAST(smack);
536 
537 	mutex_lock(&smack_known_lock);
538 
539 	skp = smk_find_entry(smack);
540 	if (skp != NULL)
541 		goto freeout;
542 
543 	skp = kzalloc(sizeof(*skp), GFP_KERNEL);
544 	if (skp == NULL) {
545 		skp = ERR_PTR(-ENOMEM);
546 		goto freeout;
547 	}
548 
549 	skp->smk_known = smack;
550 	skp->smk_secid = smack_next_secid++;
551 	skp->smk_netlabel.domain = skp->smk_known;
552 	skp->smk_netlabel.flags =
553 		NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
554 	/*
555 	 * If direct labeling works use it.
556 	 * Otherwise use mapped labeling.
557 	 */
558 	slen = strlen(smack);
559 	if (slen < SMK_CIPSOLEN)
560 		rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
561 			       &skp->smk_netlabel, slen);
562 	else
563 		rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
564 			       &skp->smk_netlabel, sizeof(skp->smk_secid));
565 
566 	if (rc >= 0) {
567 		INIT_LIST_HEAD(&skp->smk_rules);
568 		mutex_init(&skp->smk_rules_lock);
569 		/*
570 		 * Make sure that the entry is actually
571 		 * filled before putting it on the list.
572 		 */
573 		smk_insert_entry(skp);
574 		goto unlockout;
575 	}
576 	/*
577 	 * smk_netlbl_mls failed.
578 	 */
579 	kfree(skp);
580 	skp = ERR_PTR(rc);
581 freeout:
582 	kfree(smack);
583 unlockout:
584 	mutex_unlock(&smack_known_lock);
585 
586 	return skp;
587 }
588 
589 /**
590  * smack_from_secid - find the Smack label associated with a secid
591  * @secid: an integer that might be associated with a Smack label
592  *
593  * Returns a pointer to the appropriate Smack label entry if there is one,
594  * otherwise a pointer to the invalid Smack label.
595  */
596 struct smack_known *smack_from_secid(const u32 secid)
597 {
598 	struct smack_known *skp;
599 
600 	rcu_read_lock();
601 	list_for_each_entry_rcu(skp, &smack_known_list, list) {
602 		if (skp->smk_secid == secid) {
603 			rcu_read_unlock();
604 			return skp;
605 		}
606 	}
607 
608 	/*
609 	 * If we got this far someone asked for the translation
610 	 * of a secid that is not on the list.
611 	 */
612 	rcu_read_unlock();
613 	return &smack_known_huh;
614 }
615 
616 /*
617  * Unless a process is running with one of these labels
618  * even having CAP_MAC_OVERRIDE isn't enough to grant
619  * privilege to violate MAC policy. If no labels are
620  * designated (the empty list case) capabilities apply to
621  * everyone.
622  */
623 LIST_HEAD(smack_onlycap_list);
624 DEFINE_MUTEX(smack_onlycap_lock);
625 
626 /**
627  * smack_privileged_cred - are all privilege requirements met by cred
628  * @cap: The requested capability
629  * @cred: the credential to use
630  *
631  * Is the task privileged and allowed to be privileged
632  * by the onlycap rule.
633  *
634  * Returns true if the task is allowed to be privileged, false if it's not.
635  */
636 bool smack_privileged_cred(int cap, const struct cred *cred)
637 {
638 	struct task_smack *tsp = cred->security;
639 	struct smack_known *skp = tsp->smk_task;
640 	struct smack_known_list_elem *sklep;
641 	int rc;
642 
643 	rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT);
644 	if (rc)
645 		return false;
646 
647 	rcu_read_lock();
648 	if (list_empty(&smack_onlycap_list)) {
649 		rcu_read_unlock();
650 		return true;
651 	}
652 
653 	list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
654 		if (sklep->smk_label == skp) {
655 			rcu_read_unlock();
656 			return true;
657 		}
658 	}
659 	rcu_read_unlock();
660 
661 	return false;
662 }
663 
664 /**
665  * smack_privileged - are all privilege requirements met
666  * @cap: The requested capability
667  *
668  * Is the task privileged and allowed to be privileged
669  * by the onlycap rule.
670  *
671  * Returns true if the task is allowed to be privileged, false if it's not.
672  */
673 bool smack_privileged(int cap)
674 {
675 	/*
676 	 * All kernel tasks are privileged
677 	 */
678 	if (unlikely(current->flags & PF_KTHREAD))
679 		return true;
680 
681 	return smack_privileged_cred(cap, current_cred());
682 }
683