xref: /openbmc/linux/security/selinux/ss/mls.c (revision f220d3eb)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Implementation of the multi-level security (MLS) policy.
4  *
5  * Author : Stephen Smalley, <sds@tycho.nsa.gov>
6  */
7 /*
8  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
9  *
10  *	Support for enhanced MLS infrastructure.
11  *
12  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
13  */
14 /*
15  * Updated: Hewlett-Packard <paul@paul-moore.com>
16  *
17  *      Added support to import/export the MLS label from NetLabel
18  *
19  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
20  */
21 
22 #include <linux/kernel.h>
23 #include <linux/slab.h>
24 #include <linux/string.h>
25 #include <linux/errno.h>
26 #include <net/netlabel.h>
27 #include "sidtab.h"
28 #include "mls.h"
29 #include "policydb.h"
30 #include "services.h"
31 
32 /*
33  * Return the length in bytes for the MLS fields of the
34  * security context string representation of `context'.
35  */
36 int mls_compute_context_len(struct policydb *p, struct context *context)
37 {
38 	int i, l, len, head, prev;
39 	char *nm;
40 	struct ebitmap *e;
41 	struct ebitmap_node *node;
42 
43 	if (!p->mls_enabled)
44 		return 0;
45 
46 	len = 1; /* for the beginning ":" */
47 	for (l = 0; l < 2; l++) {
48 		int index_sens = context->range.level[l].sens;
49 		len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
50 
51 		/* categories */
52 		head = -2;
53 		prev = -2;
54 		e = &context->range.level[l].cat;
55 		ebitmap_for_each_positive_bit(e, node, i) {
56 			if (i - prev > 1) {
57 				/* one or more negative bits are skipped */
58 				if (head != prev) {
59 					nm = sym_name(p, SYM_CATS, prev);
60 					len += strlen(nm) + 1;
61 				}
62 				nm = sym_name(p, SYM_CATS, i);
63 				len += strlen(nm) + 1;
64 				head = i;
65 			}
66 			prev = i;
67 		}
68 		if (prev != head) {
69 			nm = sym_name(p, SYM_CATS, prev);
70 			len += strlen(nm) + 1;
71 		}
72 		if (l == 0) {
73 			if (mls_level_eq(&context->range.level[0],
74 					 &context->range.level[1]))
75 				break;
76 			else
77 				len++;
78 		}
79 	}
80 
81 	return len;
82 }
83 
84 /*
85  * Write the security context string representation of
86  * the MLS fields of `context' into the string `*scontext'.
87  * Update `*scontext' to point to the end of the MLS fields.
88  */
89 void mls_sid_to_context(struct policydb *p,
90 			struct context *context,
91 			char **scontext)
92 {
93 	char *scontextp, *nm;
94 	int i, l, head, prev;
95 	struct ebitmap *e;
96 	struct ebitmap_node *node;
97 
98 	if (!p->mls_enabled)
99 		return;
100 
101 	scontextp = *scontext;
102 
103 	*scontextp = ':';
104 	scontextp++;
105 
106 	for (l = 0; l < 2; l++) {
107 		strcpy(scontextp, sym_name(p, SYM_LEVELS,
108 					   context->range.level[l].sens - 1));
109 		scontextp += strlen(scontextp);
110 
111 		/* categories */
112 		head = -2;
113 		prev = -2;
114 		e = &context->range.level[l].cat;
115 		ebitmap_for_each_positive_bit(e, node, i) {
116 			if (i - prev > 1) {
117 				/* one or more negative bits are skipped */
118 				if (prev != head) {
119 					if (prev - head > 1)
120 						*scontextp++ = '.';
121 					else
122 						*scontextp++ = ',';
123 					nm = sym_name(p, SYM_CATS, prev);
124 					strcpy(scontextp, nm);
125 					scontextp += strlen(nm);
126 				}
127 				if (prev < 0)
128 					*scontextp++ = ':';
129 				else
130 					*scontextp++ = ',';
131 				nm = sym_name(p, SYM_CATS, i);
132 				strcpy(scontextp, nm);
133 				scontextp += strlen(nm);
134 				head = i;
135 			}
136 			prev = i;
137 		}
138 
139 		if (prev != head) {
140 			if (prev - head > 1)
141 				*scontextp++ = '.';
142 			else
143 				*scontextp++ = ',';
144 			nm = sym_name(p, SYM_CATS, prev);
145 			strcpy(scontextp, nm);
146 			scontextp += strlen(nm);
147 		}
148 
149 		if (l == 0) {
150 			if (mls_level_eq(&context->range.level[0],
151 					 &context->range.level[1]))
152 				break;
153 			else
154 				*scontextp++ = '-';
155 		}
156 	}
157 
158 	*scontext = scontextp;
159 	return;
160 }
161 
162 int mls_level_isvalid(struct policydb *p, struct mls_level *l)
163 {
164 	struct level_datum *levdatum;
165 
166 	if (!l->sens || l->sens > p->p_levels.nprim)
167 		return 0;
168 	levdatum = hashtab_search(p->p_levels.table,
169 				  sym_name(p, SYM_LEVELS, l->sens - 1));
170 	if (!levdatum)
171 		return 0;
172 
173 	/*
174 	 * Return 1 iff all the bits set in l->cat are also be set in
175 	 * levdatum->level->cat and no bit in l->cat is larger than
176 	 * p->p_cats.nprim.
177 	 */
178 	return ebitmap_contains(&levdatum->level->cat, &l->cat,
179 				p->p_cats.nprim);
180 }
181 
182 int mls_range_isvalid(struct policydb *p, struct mls_range *r)
183 {
184 	return (mls_level_isvalid(p, &r->level[0]) &&
185 		mls_level_isvalid(p, &r->level[1]) &&
186 		mls_level_dom(&r->level[1], &r->level[0]));
187 }
188 
189 /*
190  * Return 1 if the MLS fields in the security context
191  * structure `c' are valid.  Return 0 otherwise.
192  */
193 int mls_context_isvalid(struct policydb *p, struct context *c)
194 {
195 	struct user_datum *usrdatum;
196 
197 	if (!p->mls_enabled)
198 		return 1;
199 
200 	if (!mls_range_isvalid(p, &c->range))
201 		return 0;
202 
203 	if (c->role == OBJECT_R_VAL)
204 		return 1;
205 
206 	/*
207 	 * User must be authorized for the MLS range.
208 	 */
209 	if (!c->user || c->user > p->p_users.nprim)
210 		return 0;
211 	usrdatum = p->user_val_to_struct[c->user - 1];
212 	if (!mls_range_contains(usrdatum->range, c->range))
213 		return 0; /* user may not be associated with range */
214 
215 	return 1;
216 }
217 
218 /*
219  * Set the MLS fields in the security context structure
220  * `context' based on the string representation in
221  * the string `*scontext'.  Update `*scontext' to
222  * point to the end of the string representation of
223  * the MLS fields.
224  *
225  * This function modifies the string in place, inserting
226  * NULL characters to terminate the MLS fields.
227  *
228  * If a def_sid is provided and no MLS field is present,
229  * copy the MLS field of the associated default context.
230  * Used for upgraded to MLS systems where objects may lack
231  * MLS fields.
232  *
233  * Policy read-lock must be held for sidtab lookup.
234  *
235  */
236 int mls_context_to_sid(struct policydb *pol,
237 		       char oldc,
238 		       char **scontext,
239 		       struct context *context,
240 		       struct sidtab *s,
241 		       u32 def_sid)
242 {
243 
244 	char delim;
245 	char *scontextp, *p, *rngptr;
246 	struct level_datum *levdatum;
247 	struct cat_datum *catdatum, *rngdatum;
248 	int l, rc = -EINVAL;
249 
250 	if (!pol->mls_enabled) {
251 		if (def_sid != SECSID_NULL && oldc)
252 			*scontext += strlen(*scontext) + 1;
253 		return 0;
254 	}
255 
256 	/*
257 	 * No MLS component to the security context, try and map to
258 	 * default if provided.
259 	 */
260 	if (!oldc) {
261 		struct context *defcon;
262 
263 		if (def_sid == SECSID_NULL)
264 			goto out;
265 
266 		defcon = sidtab_search(s, def_sid);
267 		if (!defcon)
268 			goto out;
269 
270 		rc = mls_context_cpy(context, defcon);
271 		goto out;
272 	}
273 
274 	/* Extract low sensitivity. */
275 	scontextp = p = *scontext;
276 	while (*p && *p != ':' && *p != '-')
277 		p++;
278 
279 	delim = *p;
280 	if (delim != '\0')
281 		*p++ = '\0';
282 
283 	for (l = 0; l < 2; l++) {
284 		levdatum = hashtab_search(pol->p_levels.table, scontextp);
285 		if (!levdatum) {
286 			rc = -EINVAL;
287 			goto out;
288 		}
289 
290 		context->range.level[l].sens = levdatum->level->sens;
291 
292 		if (delim == ':') {
293 			/* Extract category set. */
294 			while (1) {
295 				scontextp = p;
296 				while (*p && *p != ',' && *p != '-')
297 					p++;
298 				delim = *p;
299 				if (delim != '\0')
300 					*p++ = '\0';
301 
302 				/* Separate into range if exists */
303 				rngptr = strchr(scontextp, '.');
304 				if (rngptr != NULL) {
305 					/* Remove '.' */
306 					*rngptr++ = '\0';
307 				}
308 
309 				catdatum = hashtab_search(pol->p_cats.table,
310 							  scontextp);
311 				if (!catdatum) {
312 					rc = -EINVAL;
313 					goto out;
314 				}
315 
316 				rc = ebitmap_set_bit(&context->range.level[l].cat,
317 						     catdatum->value - 1, 1);
318 				if (rc)
319 					goto out;
320 
321 				/* If range, set all categories in range */
322 				if (rngptr) {
323 					int i;
324 
325 					rngdatum = hashtab_search(pol->p_cats.table, rngptr);
326 					if (!rngdatum) {
327 						rc = -EINVAL;
328 						goto out;
329 					}
330 
331 					if (catdatum->value >= rngdatum->value) {
332 						rc = -EINVAL;
333 						goto out;
334 					}
335 
336 					for (i = catdatum->value; i < rngdatum->value; i++) {
337 						rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
338 						if (rc)
339 							goto out;
340 					}
341 				}
342 
343 				if (delim != ',')
344 					break;
345 			}
346 		}
347 		if (delim == '-') {
348 			/* Extract high sensitivity. */
349 			scontextp = p;
350 			while (*p && *p != ':')
351 				p++;
352 
353 			delim = *p;
354 			if (delim != '\0')
355 				*p++ = '\0';
356 		} else
357 			break;
358 	}
359 
360 	if (l == 0) {
361 		context->range.level[1].sens = context->range.level[0].sens;
362 		rc = ebitmap_cpy(&context->range.level[1].cat,
363 				 &context->range.level[0].cat);
364 		if (rc)
365 			goto out;
366 	}
367 	*scontext = ++p;
368 	rc = 0;
369 out:
370 	return rc;
371 }
372 
373 /*
374  * Set the MLS fields in the security context structure
375  * `context' based on the string representation in
376  * the string `str'.  This function will allocate temporary memory with the
377  * given constraints of gfp_mask.
378  */
379 int mls_from_string(struct policydb *p, char *str, struct context *context,
380 		    gfp_t gfp_mask)
381 {
382 	char *tmpstr, *freestr;
383 	int rc;
384 
385 	if (!p->mls_enabled)
386 		return -EINVAL;
387 
388 	/* we need freestr because mls_context_to_sid will change
389 	   the value of tmpstr */
390 	tmpstr = freestr = kstrdup(str, gfp_mask);
391 	if (!tmpstr) {
392 		rc = -ENOMEM;
393 	} else {
394 		rc = mls_context_to_sid(p, ':', &tmpstr, context,
395 					NULL, SECSID_NULL);
396 		kfree(freestr);
397 	}
398 
399 	return rc;
400 }
401 
402 /*
403  * Copies the MLS range `range' into `context'.
404  */
405 int mls_range_set(struct context *context,
406 				struct mls_range *range)
407 {
408 	int l, rc = 0;
409 
410 	/* Copy the MLS range into the  context */
411 	for (l = 0; l < 2; l++) {
412 		context->range.level[l].sens = range->level[l].sens;
413 		rc = ebitmap_cpy(&context->range.level[l].cat,
414 				 &range->level[l].cat);
415 		if (rc)
416 			break;
417 	}
418 
419 	return rc;
420 }
421 
422 int mls_setup_user_range(struct policydb *p,
423 			 struct context *fromcon, struct user_datum *user,
424 			 struct context *usercon)
425 {
426 	if (p->mls_enabled) {
427 		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
428 		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
429 		struct mls_level *user_low = &(user->range.level[0]);
430 		struct mls_level *user_clr = &(user->range.level[1]);
431 		struct mls_level *user_def = &(user->dfltlevel);
432 		struct mls_level *usercon_sen = &(usercon->range.level[0]);
433 		struct mls_level *usercon_clr = &(usercon->range.level[1]);
434 
435 		/* Honor the user's default level if we can */
436 		if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
437 			*usercon_sen = *user_def;
438 		else if (mls_level_between(fromcon_sen, user_def, user_clr))
439 			*usercon_sen = *fromcon_sen;
440 		else if (mls_level_between(fromcon_clr, user_low, user_def))
441 			*usercon_sen = *user_low;
442 		else
443 			return -EINVAL;
444 
445 		/* Lower the clearance of available contexts
446 		   if the clearance of "fromcon" is lower than
447 		   that of the user's default clearance (but
448 		   only if the "fromcon" clearance dominates
449 		   the user's computed sensitivity level) */
450 		if (mls_level_dom(user_clr, fromcon_clr))
451 			*usercon_clr = *fromcon_clr;
452 		else if (mls_level_dom(fromcon_clr, user_clr))
453 			*usercon_clr = *user_clr;
454 		else
455 			return -EINVAL;
456 	}
457 
458 	return 0;
459 }
460 
461 /*
462  * Convert the MLS fields in the security context
463  * structure `c' from the values specified in the
464  * policy `oldp' to the values specified in the policy `newp'.
465  */
466 int mls_convert_context(struct policydb *oldp,
467 			struct policydb *newp,
468 			struct context *c)
469 {
470 	struct level_datum *levdatum;
471 	struct cat_datum *catdatum;
472 	struct ebitmap bitmap;
473 	struct ebitmap_node *node;
474 	int l, i;
475 
476 	if (!oldp->mls_enabled || !newp->mls_enabled)
477 		return 0;
478 
479 	for (l = 0; l < 2; l++) {
480 		levdatum = hashtab_search(newp->p_levels.table,
481 					  sym_name(oldp, SYM_LEVELS,
482 						   c->range.level[l].sens - 1));
483 
484 		if (!levdatum)
485 			return -EINVAL;
486 		c->range.level[l].sens = levdatum->level->sens;
487 
488 		ebitmap_init(&bitmap);
489 		ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
490 			int rc;
491 
492 			catdatum = hashtab_search(newp->p_cats.table,
493 						  sym_name(oldp, SYM_CATS, i));
494 			if (!catdatum)
495 				return -EINVAL;
496 			rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
497 			if (rc)
498 				return rc;
499 
500 			cond_resched();
501 		}
502 		ebitmap_destroy(&c->range.level[l].cat);
503 		c->range.level[l].cat = bitmap;
504 	}
505 
506 	return 0;
507 }
508 
509 int mls_compute_sid(struct policydb *p,
510 		    struct context *scontext,
511 		    struct context *tcontext,
512 		    u16 tclass,
513 		    u32 specified,
514 		    struct context *newcontext,
515 		    bool sock)
516 {
517 	struct range_trans rtr;
518 	struct mls_range *r;
519 	struct class_datum *cladatum;
520 	int default_range = 0;
521 
522 	if (!p->mls_enabled)
523 		return 0;
524 
525 	switch (specified) {
526 	case AVTAB_TRANSITION:
527 		/* Look for a range transition rule. */
528 		rtr.source_type = scontext->type;
529 		rtr.target_type = tcontext->type;
530 		rtr.target_class = tclass;
531 		r = hashtab_search(p->range_tr, &rtr);
532 		if (r)
533 			return mls_range_set(newcontext, r);
534 
535 		if (tclass && tclass <= p->p_classes.nprim) {
536 			cladatum = p->class_val_to_struct[tclass - 1];
537 			if (cladatum)
538 				default_range = cladatum->default_range;
539 		}
540 
541 		switch (default_range) {
542 		case DEFAULT_SOURCE_LOW:
543 			return mls_context_cpy_low(newcontext, scontext);
544 		case DEFAULT_SOURCE_HIGH:
545 			return mls_context_cpy_high(newcontext, scontext);
546 		case DEFAULT_SOURCE_LOW_HIGH:
547 			return mls_context_cpy(newcontext, scontext);
548 		case DEFAULT_TARGET_LOW:
549 			return mls_context_cpy_low(newcontext, tcontext);
550 		case DEFAULT_TARGET_HIGH:
551 			return mls_context_cpy_high(newcontext, tcontext);
552 		case DEFAULT_TARGET_LOW_HIGH:
553 			return mls_context_cpy(newcontext, tcontext);
554 		}
555 
556 		/* Fallthrough */
557 	case AVTAB_CHANGE:
558 		if ((tclass == p->process_class) || (sock == true))
559 			/* Use the process MLS attributes. */
560 			return mls_context_cpy(newcontext, scontext);
561 		else
562 			/* Use the process effective MLS attributes. */
563 			return mls_context_cpy_low(newcontext, scontext);
564 	case AVTAB_MEMBER:
565 		/* Use the process effective MLS attributes. */
566 		return mls_context_cpy_low(newcontext, scontext);
567 
568 	/* fall through */
569 	}
570 	return -EINVAL;
571 }
572 
573 #ifdef CONFIG_NETLABEL
574 /**
575  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
576  * @context: the security context
577  * @secattr: the NetLabel security attributes
578  *
579  * Description:
580  * Given the security context copy the low MLS sensitivity level into the
581  * NetLabel MLS sensitivity level field.
582  *
583  */
584 void mls_export_netlbl_lvl(struct policydb *p,
585 			   struct context *context,
586 			   struct netlbl_lsm_secattr *secattr)
587 {
588 	if (!p->mls_enabled)
589 		return;
590 
591 	secattr->attr.mls.lvl = context->range.level[0].sens - 1;
592 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
593 }
594 
595 /**
596  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
597  * @context: the security context
598  * @secattr: the NetLabel security attributes
599  *
600  * Description:
601  * Given the security context and the NetLabel security attributes, copy the
602  * NetLabel MLS sensitivity level into the context.
603  *
604  */
605 void mls_import_netlbl_lvl(struct policydb *p,
606 			   struct context *context,
607 			   struct netlbl_lsm_secattr *secattr)
608 {
609 	if (!p->mls_enabled)
610 		return;
611 
612 	context->range.level[0].sens = secattr->attr.mls.lvl + 1;
613 	context->range.level[1].sens = context->range.level[0].sens;
614 }
615 
616 /**
617  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
618  * @context: the security context
619  * @secattr: the NetLabel security attributes
620  *
621  * Description:
622  * Given the security context copy the low MLS categories into the NetLabel
623  * MLS category field.  Returns zero on success, negative values on failure.
624  *
625  */
626 int mls_export_netlbl_cat(struct policydb *p,
627 			  struct context *context,
628 			  struct netlbl_lsm_secattr *secattr)
629 {
630 	int rc;
631 
632 	if (!p->mls_enabled)
633 		return 0;
634 
635 	rc = ebitmap_netlbl_export(&context->range.level[0].cat,
636 				   &secattr->attr.mls.cat);
637 	if (rc == 0 && secattr->attr.mls.cat != NULL)
638 		secattr->flags |= NETLBL_SECATTR_MLS_CAT;
639 
640 	return rc;
641 }
642 
643 /**
644  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
645  * @context: the security context
646  * @secattr: the NetLabel security attributes
647  *
648  * Description:
649  * Copy the NetLabel security attributes into the SELinux context; since the
650  * NetLabel security attribute only contains a single MLS category use it for
651  * both the low and high categories of the context.  Returns zero on success,
652  * negative values on failure.
653  *
654  */
655 int mls_import_netlbl_cat(struct policydb *p,
656 			  struct context *context,
657 			  struct netlbl_lsm_secattr *secattr)
658 {
659 	int rc;
660 
661 	if (!p->mls_enabled)
662 		return 0;
663 
664 	rc = ebitmap_netlbl_import(&context->range.level[0].cat,
665 				   secattr->attr.mls.cat);
666 	if (rc)
667 		goto import_netlbl_cat_failure;
668 	memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
669 	       sizeof(context->range.level[0].cat));
670 
671 	return 0;
672 
673 import_netlbl_cat_failure:
674 	ebitmap_destroy(&context->range.level[0].cat);
675 	return rc;
676 }
677 #endif /* CONFIG_NETLABEL */
678