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