xref: /linux/security/selinux/ss/mls.c (revision f3d9478b2ce468c3115b02ecae7e975990697f15)
1 /*
2  * Implementation of the multi-level security (MLS) policy.
3  *
4  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5  */
6 /*
7  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8  *
9  *	Support for enhanced MLS infrastructure.
10  *
11  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/string.h>
17 #include <linux/errno.h>
18 #include "sidtab.h"
19 #include "mls.h"
20 #include "policydb.h"
21 #include "services.h"
22 
23 /*
24  * Return the length in bytes for the MLS fields of the
25  * security context string representation of `context'.
26  */
27 int mls_compute_context_len(struct context * context)
28 {
29 	int i, l, len, range;
30 	struct ebitmap_node *node;
31 
32 	if (!selinux_mls_enabled)
33 		return 0;
34 
35 	len = 1; /* for the beginning ":" */
36 	for (l = 0; l < 2; l++) {
37 		range = 0;
38 		len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
39 
40 		ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
41 			if (ebitmap_node_get_bit(node, i)) {
42 				if (range) {
43 					range++;
44 					continue;
45 				}
46 
47 				len += strlen(policydb.p_cat_val_to_name[i]) + 1;
48 				range++;
49 			} else {
50 				if (range > 1)
51 					len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
52 				range = 0;
53 			}
54 		}
55 		/* Handle case where last category is the end of range */
56 		if (range > 1)
57 			len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
58 
59 		if (l == 0) {
60 			if (mls_level_eq(&context->range.level[0],
61 			                 &context->range.level[1]))
62 				break;
63 			else
64 				len++;
65 		}
66 	}
67 
68 	return len;
69 }
70 
71 /*
72  * Write the security context string representation of
73  * the MLS fields of `context' into the string `*scontext'.
74  * Update `*scontext' to point to the end of the MLS fields.
75  */
76 void mls_sid_to_context(struct context *context,
77                         char **scontext)
78 {
79 	char *scontextp;
80 	int i, l, range, wrote_sep;
81 	struct ebitmap_node *node;
82 
83 	if (!selinux_mls_enabled)
84 		return;
85 
86 	scontextp = *scontext;
87 
88 	*scontextp = ':';
89 	scontextp++;
90 
91 	for (l = 0; l < 2; l++) {
92 		range = 0;
93 		wrote_sep = 0;
94 		strcpy(scontextp,
95 		       policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
96 		scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
97 
98 		/* categories */
99 		ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
100 			if (ebitmap_node_get_bit(node, i)) {
101 				if (range) {
102 					range++;
103 					continue;
104 				}
105 
106 				if (!wrote_sep) {
107 					*scontextp++ = ':';
108 					wrote_sep = 1;
109 				} else
110 					*scontextp++ = ',';
111 				strcpy(scontextp, policydb.p_cat_val_to_name[i]);
112 				scontextp += strlen(policydb.p_cat_val_to_name[i]);
113 				range++;
114 			} else {
115 				if (range > 1) {
116 					if (range > 2)
117 						*scontextp++ = '.';
118 					else
119 						*scontextp++ = ',';
120 
121 					strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
122 					scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
123 				}
124 				range = 0;
125 			}
126 		}
127 
128 		/* Handle case where last category is the end of range */
129 		if (range > 1) {
130 			if (range > 2)
131 				*scontextp++ = '.';
132 			else
133 				*scontextp++ = ',';
134 
135 			strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
136 			scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
137 		}
138 
139 		if (l == 0) {
140 			if (mls_level_eq(&context->range.level[0],
141 			                 &context->range.level[1]))
142 				break;
143 			else {
144 				*scontextp = '-';
145 				scontextp++;
146 			}
147 		}
148 	}
149 
150 	*scontext = scontextp;
151 	return;
152 }
153 
154 /*
155  * Return 1 if the MLS fields in the security context
156  * structure `c' are valid.  Return 0 otherwise.
157  */
158 int mls_context_isvalid(struct policydb *p, struct context *c)
159 {
160 	struct level_datum *levdatum;
161 	struct user_datum *usrdatum;
162 	struct ebitmap_node *node;
163 	int i, l;
164 
165 	if (!selinux_mls_enabled)
166 		return 1;
167 
168 	/*
169 	 * MLS range validity checks: high must dominate low, low level must
170 	 * be valid (category set <-> sensitivity check), and high level must
171 	 * be valid (category set <-> sensitivity check)
172 	 */
173 	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
174 		/* High does not dominate low. */
175 		return 0;
176 
177 	for (l = 0; l < 2; l++) {
178 		if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
179 			return 0;
180 		levdatum = hashtab_search(p->p_levels.table,
181 			p->p_sens_val_to_name[c->range.level[l].sens - 1]);
182 		if (!levdatum)
183 			return 0;
184 
185 		ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
186 			if (ebitmap_node_get_bit(node, i)) {
187 				if (i > p->p_cats.nprim)
188 					return 0;
189 				if (!ebitmap_get_bit(&levdatum->level->cat, i))
190 					/*
191 					 * Category may not be associated with
192 					 * sensitivity in low level.
193 					 */
194 					return 0;
195 			}
196 		}
197 	}
198 
199 	if (c->role == OBJECT_R_VAL)
200 		return 1;
201 
202 	/*
203 	 * User must be authorized for the MLS range.
204 	 */
205 	if (!c->user || c->user > p->p_users.nprim)
206 		return 0;
207 	usrdatum = p->user_val_to_struct[c->user - 1];
208 	if (!mls_range_contains(usrdatum->range, c->range))
209 		return 0; /* user may not be associated with range */
210 
211 	return 1;
212 }
213 
214 /*
215  * Copies the MLS range from `src' into `dst'.
216  */
217 static inline int mls_copy_context(struct context *dst,
218 				   struct context *src)
219 {
220 	int l, rc = 0;
221 
222 	/* Copy the MLS range from the source context */
223 	for (l = 0; l < 2; l++) {
224 		dst->range.level[l].sens = src->range.level[l].sens;
225 		rc = ebitmap_cpy(&dst->range.level[l].cat,
226 				 &src->range.level[l].cat);
227 		if (rc)
228 			break;
229 	}
230 
231 	return rc;
232 }
233 
234 /*
235  * Set the MLS fields in the security context structure
236  * `context' based on the string representation in
237  * the string `*scontext'.  Update `*scontext' to
238  * point to the end of the string representation of
239  * the MLS fields.
240  *
241  * This function modifies the string in place, inserting
242  * NULL characters to terminate the MLS fields.
243  *
244  * If a def_sid is provided and no MLS field is present,
245  * copy the MLS field of the associated default context.
246  * Used for upgraded to MLS systems where objects may lack
247  * MLS fields.
248  *
249  * Policy read-lock must be held for sidtab lookup.
250  *
251  */
252 int mls_context_to_sid(char oldc,
253 		       char **scontext,
254 		       struct context *context,
255 		       struct sidtab *s,
256 		       u32 def_sid)
257 {
258 
259 	char delim;
260 	char *scontextp, *p, *rngptr;
261 	struct level_datum *levdatum;
262 	struct cat_datum *catdatum, *rngdatum;
263 	int l, rc = -EINVAL;
264 
265 	if (!selinux_mls_enabled) {
266 		if (def_sid != SECSID_NULL && oldc)
267 			*scontext += strlen(*scontext)+1;
268 		return 0;
269 	}
270 
271 	/*
272 	 * No MLS component to the security context, try and map to
273 	 * default if provided.
274 	 */
275 	if (!oldc) {
276 		struct context *defcon;
277 
278 		if (def_sid == SECSID_NULL)
279 			goto out;
280 
281 		defcon = sidtab_search(s, def_sid);
282 		if (!defcon)
283 			goto out;
284 
285 		rc = mls_copy_context(context, defcon);
286 		goto out;
287 	}
288 
289 	/* Extract low sensitivity. */
290 	scontextp = p = *scontext;
291 	while (*p && *p != ':' && *p != '-')
292 		p++;
293 
294 	delim = *p;
295 	if (delim != 0)
296 		*p++ = 0;
297 
298 	for (l = 0; l < 2; l++) {
299 		levdatum = hashtab_search(policydb.p_levels.table, scontextp);
300 		if (!levdatum) {
301 			rc = -EINVAL;
302 			goto out;
303 		}
304 
305 		context->range.level[l].sens = levdatum->level->sens;
306 
307 		if (delim == ':') {
308 			/* Extract category set. */
309 			while (1) {
310 				scontextp = p;
311 				while (*p && *p != ',' && *p != '-')
312 					p++;
313 				delim = *p;
314 				if (delim != 0)
315 					*p++ = 0;
316 
317 				/* Separate into range if exists */
318 				if ((rngptr = strchr(scontextp, '.')) != NULL) {
319 					/* Remove '.' */
320 					*rngptr++ = 0;
321 				}
322 
323 				catdatum = hashtab_search(policydb.p_cats.table,
324 				                          scontextp);
325 				if (!catdatum) {
326 					rc = -EINVAL;
327 					goto out;
328 				}
329 
330 				rc = ebitmap_set_bit(&context->range.level[l].cat,
331 				                     catdatum->value - 1, 1);
332 				if (rc)
333 					goto out;
334 
335 				/* If range, set all categories in range */
336 				if (rngptr) {
337 					int i;
338 
339 					rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
340 					if (!rngdatum) {
341 						rc = -EINVAL;
342 						goto out;
343 					}
344 
345 					if (catdatum->value >= rngdatum->value) {
346 						rc = -EINVAL;
347 						goto out;
348 					}
349 
350 					for (i = catdatum->value; i < rngdatum->value; i++) {
351 						rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
352 						if (rc)
353 							goto out;
354 					}
355 				}
356 
357 				if (delim != ',')
358 					break;
359 			}
360 		}
361 		if (delim == '-') {
362 			/* Extract high sensitivity. */
363 			scontextp = p;
364 			while (*p && *p != ':')
365 				p++;
366 
367 			delim = *p;
368 			if (delim != 0)
369 				*p++ = 0;
370 		} else
371 			break;
372 	}
373 
374 	if (l == 0) {
375 		context->range.level[1].sens = context->range.level[0].sens;
376 		rc = ebitmap_cpy(&context->range.level[1].cat,
377 				 &context->range.level[0].cat);
378 		if (rc)
379 			goto out;
380 	}
381 	*scontext = ++p;
382 	rc = 0;
383 out:
384 	return rc;
385 }
386 
387 /*
388  * Set the MLS fields in the security context structure
389  * `context' based on the string representation in
390  * the string `str'.  This function will allocate temporary memory with the
391  * given constraints of gfp_mask.
392  */
393 int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
394 {
395 	char *tmpstr, *freestr;
396 	int rc;
397 
398 	if (!selinux_mls_enabled)
399 		return -EINVAL;
400 
401 	/* we need freestr because mls_context_to_sid will change
402 	   the value of tmpstr */
403 	tmpstr = freestr = kstrdup(str, gfp_mask);
404 	if (!tmpstr) {
405 		rc = -ENOMEM;
406 	} else {
407 		rc = mls_context_to_sid(':', &tmpstr, context,
408 		                        NULL, SECSID_NULL);
409 		kfree(freestr);
410 	}
411 
412 	return rc;
413 }
414 
415 /*
416  * Copies the effective MLS range from `src' into `dst'.
417  */
418 static inline int mls_scopy_context(struct context *dst,
419                                     struct context *src)
420 {
421 	int l, rc = 0;
422 
423 	/* Copy the MLS range from the source context */
424 	for (l = 0; l < 2; l++) {
425 		dst->range.level[l].sens = src->range.level[0].sens;
426 		rc = ebitmap_cpy(&dst->range.level[l].cat,
427 				 &src->range.level[0].cat);
428 		if (rc)
429 			break;
430 	}
431 
432 	return rc;
433 }
434 
435 /*
436  * Copies the MLS range `range' into `context'.
437  */
438 static inline int mls_range_set(struct context *context,
439                                 struct mls_range *range)
440 {
441 	int l, rc = 0;
442 
443 	/* Copy the MLS range into the  context */
444 	for (l = 0; l < 2; l++) {
445 		context->range.level[l].sens = range->level[l].sens;
446 		rc = ebitmap_cpy(&context->range.level[l].cat,
447 				 &range->level[l].cat);
448 		if (rc)
449 			break;
450 	}
451 
452 	return rc;
453 }
454 
455 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
456                          struct context *usercon)
457 {
458 	if (selinux_mls_enabled) {
459 		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
460 		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
461 		struct mls_level *user_low = &(user->range.level[0]);
462 		struct mls_level *user_clr = &(user->range.level[1]);
463 		struct mls_level *user_def = &(user->dfltlevel);
464 		struct mls_level *usercon_sen = &(usercon->range.level[0]);
465 		struct mls_level *usercon_clr = &(usercon->range.level[1]);
466 
467 		/* Honor the user's default level if we can */
468 		if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
469 			*usercon_sen = *user_def;
470 		} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
471 			*usercon_sen = *fromcon_sen;
472 		} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
473 			*usercon_sen = *user_low;
474 		} else
475 			return -EINVAL;
476 
477 		/* Lower the clearance of available contexts
478 		   if the clearance of "fromcon" is lower than
479 		   that of the user's default clearance (but
480 		   only if the "fromcon" clearance dominates
481 		   the user's computed sensitivity level) */
482 		if (mls_level_dom(user_clr, fromcon_clr)) {
483 			*usercon_clr = *fromcon_clr;
484 		} else if (mls_level_dom(fromcon_clr, user_clr)) {
485 			*usercon_clr = *user_clr;
486 		} else
487 			return -EINVAL;
488 	}
489 
490 	return 0;
491 }
492 
493 /*
494  * Convert the MLS fields in the security context
495  * structure `c' from the values specified in the
496  * policy `oldp' to the values specified in the policy `newp'.
497  */
498 int mls_convert_context(struct policydb *oldp,
499 			struct policydb *newp,
500 			struct context *c)
501 {
502 	struct level_datum *levdatum;
503 	struct cat_datum *catdatum;
504 	struct ebitmap bitmap;
505 	struct ebitmap_node *node;
506 	int l, i;
507 
508 	if (!selinux_mls_enabled)
509 		return 0;
510 
511 	for (l = 0; l < 2; l++) {
512 		levdatum = hashtab_search(newp->p_levels.table,
513 			oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
514 
515 		if (!levdatum)
516 			return -EINVAL;
517 		c->range.level[l].sens = levdatum->level->sens;
518 
519 		ebitmap_init(&bitmap);
520 		ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
521 			if (ebitmap_node_get_bit(node, i)) {
522 				int rc;
523 
524 				catdatum = hashtab_search(newp->p_cats.table,
525 				         	oldp->p_cat_val_to_name[i]);
526 				if (!catdatum)
527 					return -EINVAL;
528 				rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
529 				if (rc)
530 					return rc;
531 			}
532 		}
533 		ebitmap_destroy(&c->range.level[l].cat);
534 		c->range.level[l].cat = bitmap;
535 	}
536 
537 	return 0;
538 }
539 
540 int mls_compute_sid(struct context *scontext,
541 		    struct context *tcontext,
542 		    u16 tclass,
543 		    u32 specified,
544 		    struct context *newcontext)
545 {
546 	if (!selinux_mls_enabled)
547 		return 0;
548 
549 	switch (specified) {
550 	case AVTAB_TRANSITION:
551 		if (tclass == SECCLASS_PROCESS) {
552 			struct range_trans *rangetr;
553 			/* Look for a range transition rule. */
554 			for (rangetr = policydb.range_tr; rangetr;
555 			     rangetr = rangetr->next) {
556 				if (rangetr->dom == scontext->type &&
557 				    rangetr->type == tcontext->type) {
558 					/* Set the range from the rule */
559 					return mls_range_set(newcontext,
560 					                     &rangetr->range);
561 				}
562 			}
563 		}
564 		/* Fallthrough */
565 	case AVTAB_CHANGE:
566 		if (tclass == SECCLASS_PROCESS)
567 			/* Use the process MLS attributes. */
568 			return mls_copy_context(newcontext, scontext);
569 		else
570 			/* Use the process effective MLS attributes. */
571 			return mls_scopy_context(newcontext, scontext);
572 	case AVTAB_MEMBER:
573 		/* Only polyinstantiate the MLS attributes if
574 		   the type is being polyinstantiated */
575 		if (newcontext->type != tcontext->type) {
576 			/* Use the process effective MLS attributes. */
577 			return mls_scopy_context(newcontext, scontext);
578 		} else {
579 			/* Use the related object MLS attributes. */
580 			return mls_copy_context(newcontext, tcontext);
581 		}
582 	default:
583 		return -EINVAL;
584 	}
585 	return -EINVAL;
586 }
587 
588