xref: /linux/security/selinux/ss/mls.c (revision 7420ed23)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Implementation of the multi-level security (MLS) policy.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds /*
71da177e4SLinus Torvalds  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *	Support for enhanced MLS infrastructure.
101da177e4SLinus Torvalds  *
11376bd9cbSDarrel Goeddel  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
121da177e4SLinus Torvalds  */
13*7420ed23SVenkat Yekkirala /*
14*7420ed23SVenkat Yekkirala  * Updated: Hewlett-Packard <paul.moore@hp.com>
15*7420ed23SVenkat Yekkirala  *
16*7420ed23SVenkat Yekkirala  *      Added support to import/export the MLS label
17*7420ed23SVenkat Yekkirala  *
18*7420ed23SVenkat Yekkirala  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
19*7420ed23SVenkat Yekkirala  */
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #include <linux/kernel.h>
221da177e4SLinus Torvalds #include <linux/slab.h>
231da177e4SLinus Torvalds #include <linux/string.h>
241da177e4SLinus Torvalds #include <linux/errno.h>
25f5c1d5b2SJames Morris #include "sidtab.h"
261da177e4SLinus Torvalds #include "mls.h"
271da177e4SLinus Torvalds #include "policydb.h"
281da177e4SLinus Torvalds #include "services.h"
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /*
311da177e4SLinus Torvalds  * Return the length in bytes for the MLS fields of the
321da177e4SLinus Torvalds  * security context string representation of `context'.
331da177e4SLinus Torvalds  */
341da177e4SLinus Torvalds int mls_compute_context_len(struct context * context)
351da177e4SLinus Torvalds {
361da177e4SLinus Torvalds 	int i, l, len, range;
37782ebb99SStephen Smalley 	struct ebitmap_node *node;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
401da177e4SLinus Torvalds 		return 0;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	len = 1; /* for the beginning ":" */
431da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
441da177e4SLinus Torvalds 		range = 0;
451da177e4SLinus Torvalds 		len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
461da177e4SLinus Torvalds 
47782ebb99SStephen Smalley 		ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
48782ebb99SStephen Smalley 			if (ebitmap_node_get_bit(node, i)) {
491da177e4SLinus Torvalds 				if (range) {
501da177e4SLinus Torvalds 					range++;
511da177e4SLinus Torvalds 					continue;
521da177e4SLinus Torvalds 				}
531da177e4SLinus Torvalds 
54782ebb99SStephen Smalley 				len += strlen(policydb.p_cat_val_to_name[i]) + 1;
551da177e4SLinus Torvalds 				range++;
561da177e4SLinus Torvalds 			} else {
571da177e4SLinus Torvalds 				if (range > 1)
58782ebb99SStephen Smalley 					len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
591da177e4SLinus Torvalds 				range = 0;
601da177e4SLinus Torvalds 			}
611da177e4SLinus Torvalds 		}
621da177e4SLinus Torvalds 		/* Handle case where last category is the end of range */
631da177e4SLinus Torvalds 		if (range > 1)
64782ebb99SStephen Smalley 			len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 		if (l == 0) {
671da177e4SLinus Torvalds 			if (mls_level_eq(&context->range.level[0],
681da177e4SLinus Torvalds 			                 &context->range.level[1]))
691da177e4SLinus Torvalds 				break;
701da177e4SLinus Torvalds 			else
711da177e4SLinus Torvalds 				len++;
721da177e4SLinus Torvalds 		}
731da177e4SLinus Torvalds 	}
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	return len;
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds /*
791da177e4SLinus Torvalds  * Write the security context string representation of
801da177e4SLinus Torvalds  * the MLS fields of `context' into the string `*scontext'.
811da177e4SLinus Torvalds  * Update `*scontext' to point to the end of the MLS fields.
821da177e4SLinus Torvalds  */
831da177e4SLinus Torvalds void mls_sid_to_context(struct context *context,
841da177e4SLinus Torvalds                         char **scontext)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	char *scontextp;
871da177e4SLinus Torvalds 	int i, l, range, wrote_sep;
88782ebb99SStephen Smalley 	struct ebitmap_node *node;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
911da177e4SLinus Torvalds 		return;
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	scontextp = *scontext;
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds 	*scontextp = ':';
961da177e4SLinus Torvalds 	scontextp++;
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
991da177e4SLinus Torvalds 		range = 0;
1001da177e4SLinus Torvalds 		wrote_sep = 0;
1011da177e4SLinus Torvalds 		strcpy(scontextp,
1021da177e4SLinus Torvalds 		       policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
1031da177e4SLinus Torvalds 		scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 		/* categories */
106782ebb99SStephen Smalley 		ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
107782ebb99SStephen Smalley 			if (ebitmap_node_get_bit(node, i)) {
1081da177e4SLinus Torvalds 				if (range) {
1091da177e4SLinus Torvalds 					range++;
1101da177e4SLinus Torvalds 					continue;
1111da177e4SLinus Torvalds 				}
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 				if (!wrote_sep) {
1141da177e4SLinus Torvalds 					*scontextp++ = ':';
1151da177e4SLinus Torvalds 					wrote_sep = 1;
1161da177e4SLinus Torvalds 				} else
1171da177e4SLinus Torvalds 					*scontextp++ = ',';
118782ebb99SStephen Smalley 				strcpy(scontextp, policydb.p_cat_val_to_name[i]);
119782ebb99SStephen Smalley 				scontextp += strlen(policydb.p_cat_val_to_name[i]);
1201da177e4SLinus Torvalds 				range++;
1211da177e4SLinus Torvalds 			} else {
1221da177e4SLinus Torvalds 				if (range > 1) {
1231da177e4SLinus Torvalds 					if (range > 2)
1241da177e4SLinus Torvalds 						*scontextp++ = '.';
1251da177e4SLinus Torvalds 					else
1261da177e4SLinus Torvalds 						*scontextp++ = ',';
1271da177e4SLinus Torvalds 
128782ebb99SStephen Smalley 					strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
129782ebb99SStephen Smalley 					scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
1301da177e4SLinus Torvalds 				}
1311da177e4SLinus Torvalds 				range = 0;
1321da177e4SLinus Torvalds 			}
1331da177e4SLinus Torvalds 		}
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 		/* Handle case where last category is the end of range */
1361da177e4SLinus Torvalds 		if (range > 1) {
1371da177e4SLinus Torvalds 			if (range > 2)
1381da177e4SLinus Torvalds 				*scontextp++ = '.';
1391da177e4SLinus Torvalds 			else
1401da177e4SLinus Torvalds 				*scontextp++ = ',';
1411da177e4SLinus Torvalds 
142782ebb99SStephen Smalley 			strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
143782ebb99SStephen Smalley 			scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
1441da177e4SLinus Torvalds 		}
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds 		if (l == 0) {
1471da177e4SLinus Torvalds 			if (mls_level_eq(&context->range.level[0],
1481da177e4SLinus Torvalds 			                 &context->range.level[1]))
1491da177e4SLinus Torvalds 				break;
1501da177e4SLinus Torvalds 			else {
1511da177e4SLinus Torvalds 				*scontextp = '-';
1521da177e4SLinus Torvalds 				scontextp++;
1531da177e4SLinus Torvalds 			}
1541da177e4SLinus Torvalds 		}
1551da177e4SLinus Torvalds 	}
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	*scontext = scontextp;
1581da177e4SLinus Torvalds 	return;
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds /*
1621da177e4SLinus Torvalds  * Return 1 if the MLS fields in the security context
1631da177e4SLinus Torvalds  * structure `c' are valid.  Return 0 otherwise.
1641da177e4SLinus Torvalds  */
1651da177e4SLinus Torvalds int mls_context_isvalid(struct policydb *p, struct context *c)
1661da177e4SLinus Torvalds {
1671da177e4SLinus Torvalds 	struct level_datum *levdatum;
1681da177e4SLinus Torvalds 	struct user_datum *usrdatum;
169782ebb99SStephen Smalley 	struct ebitmap_node *node;
1701da177e4SLinus Torvalds 	int i, l;
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
1731da177e4SLinus Torvalds 		return 1;
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	/*
1761da177e4SLinus Torvalds 	 * MLS range validity checks: high must dominate low, low level must
1771da177e4SLinus Torvalds 	 * be valid (category set <-> sensitivity check), and high level must
1781da177e4SLinus Torvalds 	 * be valid (category set <-> sensitivity check)
1791da177e4SLinus Torvalds 	 */
1801da177e4SLinus Torvalds 	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
1811da177e4SLinus Torvalds 		/* High does not dominate low. */
1821da177e4SLinus Torvalds 		return 0;
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
1851da177e4SLinus Torvalds 		if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
1861da177e4SLinus Torvalds 			return 0;
1871da177e4SLinus Torvalds 		levdatum = hashtab_search(p->p_levels.table,
1881da177e4SLinus Torvalds 			p->p_sens_val_to_name[c->range.level[l].sens - 1]);
1891da177e4SLinus Torvalds 		if (!levdatum)
1901da177e4SLinus Torvalds 			return 0;
1911da177e4SLinus Torvalds 
192782ebb99SStephen Smalley 		ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
193782ebb99SStephen Smalley 			if (ebitmap_node_get_bit(node, i)) {
1941da177e4SLinus Torvalds 				if (i > p->p_cats.nprim)
1951da177e4SLinus Torvalds 					return 0;
196782ebb99SStephen Smalley 				if (!ebitmap_get_bit(&levdatum->level->cat, i))
1971da177e4SLinus Torvalds 					/*
1981da177e4SLinus Torvalds 					 * Category may not be associated with
1991da177e4SLinus Torvalds 					 * sensitivity in low level.
2001da177e4SLinus Torvalds 					 */
2011da177e4SLinus Torvalds 					return 0;
2021da177e4SLinus Torvalds 			}
2031da177e4SLinus Torvalds 		}
2041da177e4SLinus Torvalds 	}
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	if (c->role == OBJECT_R_VAL)
2071da177e4SLinus Torvalds 		return 1;
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	/*
2101da177e4SLinus Torvalds 	 * User must be authorized for the MLS range.
2111da177e4SLinus Torvalds 	 */
2121da177e4SLinus Torvalds 	if (!c->user || c->user > p->p_users.nprim)
2131da177e4SLinus Torvalds 		return 0;
2141da177e4SLinus Torvalds 	usrdatum = p->user_val_to_struct[c->user - 1];
2151da177e4SLinus Torvalds 	if (!mls_range_contains(usrdatum->range, c->range))
2161da177e4SLinus Torvalds 		return 0; /* user may not be associated with range */
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds 	return 1;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds /*
2221da177e4SLinus Torvalds  * Set the MLS fields in the security context structure
2231da177e4SLinus Torvalds  * `context' based on the string representation in
2241da177e4SLinus Torvalds  * the string `*scontext'.  Update `*scontext' to
2251da177e4SLinus Torvalds  * point to the end of the string representation of
2261da177e4SLinus Torvalds  * the MLS fields.
2271da177e4SLinus Torvalds  *
2281da177e4SLinus Torvalds  * This function modifies the string in place, inserting
2291da177e4SLinus Torvalds  * NULL characters to terminate the MLS fields.
230f5c1d5b2SJames Morris  *
231f5c1d5b2SJames Morris  * If a def_sid is provided and no MLS field is present,
232f5c1d5b2SJames Morris  * copy the MLS field of the associated default context.
233f5c1d5b2SJames Morris  * Used for upgraded to MLS systems where objects may lack
234f5c1d5b2SJames Morris  * MLS fields.
235f5c1d5b2SJames Morris  *
236f5c1d5b2SJames Morris  * Policy read-lock must be held for sidtab lookup.
237f5c1d5b2SJames Morris  *
2381da177e4SLinus Torvalds  */
2391da177e4SLinus Torvalds int mls_context_to_sid(char oldc,
2401da177e4SLinus Torvalds 		       char **scontext,
241f5c1d5b2SJames Morris 		       struct context *context,
242f5c1d5b2SJames Morris 		       struct sidtab *s,
243f5c1d5b2SJames Morris 		       u32 def_sid)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 	char delim;
2471da177e4SLinus Torvalds 	char *scontextp, *p, *rngptr;
2481da177e4SLinus Torvalds 	struct level_datum *levdatum;
2491da177e4SLinus Torvalds 	struct cat_datum *catdatum, *rngdatum;
2501da177e4SLinus Torvalds 	int l, rc = -EINVAL;
2511da177e4SLinus Torvalds 
252e517a0cdSStephen Smalley 	if (!selinux_mls_enabled) {
253e517a0cdSStephen Smalley 		if (def_sid != SECSID_NULL && oldc)
254ab5703b3SRon Yorston 			*scontext += strlen(*scontext)+1;
2551da177e4SLinus Torvalds 		return 0;
256e517a0cdSStephen Smalley 	}
2571da177e4SLinus Torvalds 
258f5c1d5b2SJames Morris 	/*
259f5c1d5b2SJames Morris 	 * No MLS component to the security context, try and map to
260f5c1d5b2SJames Morris 	 * default if provided.
261f5c1d5b2SJames Morris 	 */
262f5c1d5b2SJames Morris 	if (!oldc) {
263f5c1d5b2SJames Morris 		struct context *defcon;
264f5c1d5b2SJames Morris 
265f5c1d5b2SJames Morris 		if (def_sid == SECSID_NULL)
2661da177e4SLinus Torvalds 			goto out;
2671da177e4SLinus Torvalds 
268f5c1d5b2SJames Morris 		defcon = sidtab_search(s, def_sid);
269f5c1d5b2SJames Morris 		if (!defcon)
270f5c1d5b2SJames Morris 			goto out;
271f5c1d5b2SJames Morris 
272f5c1d5b2SJames Morris 		rc = mls_copy_context(context, defcon);
273f5c1d5b2SJames Morris 		goto out;
274f5c1d5b2SJames Morris 	}
275f5c1d5b2SJames Morris 
2761da177e4SLinus Torvalds 	/* Extract low sensitivity. */
2771da177e4SLinus Torvalds 	scontextp = p = *scontext;
2781da177e4SLinus Torvalds 	while (*p && *p != ':' && *p != '-')
2791da177e4SLinus Torvalds 		p++;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	delim = *p;
2821da177e4SLinus Torvalds 	if (delim != 0)
2831da177e4SLinus Torvalds 		*p++ = 0;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
2861da177e4SLinus Torvalds 		levdatum = hashtab_search(policydb.p_levels.table, scontextp);
2871da177e4SLinus Torvalds 		if (!levdatum) {
2881da177e4SLinus Torvalds 			rc = -EINVAL;
2891da177e4SLinus Torvalds 			goto out;
2901da177e4SLinus Torvalds 		}
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 		context->range.level[l].sens = levdatum->level->sens;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 		if (delim == ':') {
2951da177e4SLinus Torvalds 			/* Extract category set. */
2961da177e4SLinus Torvalds 			while (1) {
2971da177e4SLinus Torvalds 				scontextp = p;
2981da177e4SLinus Torvalds 				while (*p && *p != ',' && *p != '-')
2991da177e4SLinus Torvalds 					p++;
3001da177e4SLinus Torvalds 				delim = *p;
3011da177e4SLinus Torvalds 				if (delim != 0)
3021da177e4SLinus Torvalds 					*p++ = 0;
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 				/* Separate into range if exists */
3051da177e4SLinus Torvalds 				if ((rngptr = strchr(scontextp, '.')) != NULL) {
3061da177e4SLinus Torvalds 					/* Remove '.' */
3071da177e4SLinus Torvalds 					*rngptr++ = 0;
3081da177e4SLinus Torvalds 				}
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 				catdatum = hashtab_search(policydb.p_cats.table,
3111da177e4SLinus Torvalds 				                          scontextp);
3121da177e4SLinus Torvalds 				if (!catdatum) {
3131da177e4SLinus Torvalds 					rc = -EINVAL;
3141da177e4SLinus Torvalds 					goto out;
3151da177e4SLinus Torvalds 				}
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 				rc = ebitmap_set_bit(&context->range.level[l].cat,
3181da177e4SLinus Torvalds 				                     catdatum->value - 1, 1);
3191da177e4SLinus Torvalds 				if (rc)
3201da177e4SLinus Torvalds 					goto out;
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 				/* If range, set all categories in range */
3231da177e4SLinus Torvalds 				if (rngptr) {
3241da177e4SLinus Torvalds 					int i;
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 					rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
3271da177e4SLinus Torvalds 					if (!rngdatum) {
3281da177e4SLinus Torvalds 						rc = -EINVAL;
3291da177e4SLinus Torvalds 						goto out;
3301da177e4SLinus Torvalds 					}
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds 					if (catdatum->value >= rngdatum->value) {
3331da177e4SLinus Torvalds 						rc = -EINVAL;
3341da177e4SLinus Torvalds 						goto out;
3351da177e4SLinus Torvalds 					}
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 					for (i = catdatum->value; i < rngdatum->value; i++) {
3381da177e4SLinus Torvalds 						rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
3391da177e4SLinus Torvalds 						if (rc)
3401da177e4SLinus Torvalds 							goto out;
3411da177e4SLinus Torvalds 					}
3421da177e4SLinus Torvalds 				}
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 				if (delim != ',')
3451da177e4SLinus Torvalds 					break;
3461da177e4SLinus Torvalds 			}
3471da177e4SLinus Torvalds 		}
3481da177e4SLinus Torvalds 		if (delim == '-') {
3491da177e4SLinus Torvalds 			/* Extract high sensitivity. */
3501da177e4SLinus Torvalds 			scontextp = p;
3511da177e4SLinus Torvalds 			while (*p && *p != ':')
3521da177e4SLinus Torvalds 				p++;
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 			delim = *p;
3551da177e4SLinus Torvalds 			if (delim != 0)
3561da177e4SLinus Torvalds 				*p++ = 0;
3571da177e4SLinus Torvalds 		} else
3581da177e4SLinus Torvalds 			break;
3591da177e4SLinus Torvalds 	}
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 	if (l == 0) {
3621da177e4SLinus Torvalds 		context->range.level[1].sens = context->range.level[0].sens;
3631da177e4SLinus Torvalds 		rc = ebitmap_cpy(&context->range.level[1].cat,
3641da177e4SLinus Torvalds 				 &context->range.level[0].cat);
3651da177e4SLinus Torvalds 		if (rc)
3661da177e4SLinus Torvalds 			goto out;
3671da177e4SLinus Torvalds 	}
3681da177e4SLinus Torvalds 	*scontext = ++p;
3691da177e4SLinus Torvalds 	rc = 0;
3701da177e4SLinus Torvalds out:
3711da177e4SLinus Torvalds 	return rc;
3721da177e4SLinus Torvalds }
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds /*
375376bd9cbSDarrel Goeddel  * Set the MLS fields in the security context structure
376376bd9cbSDarrel Goeddel  * `context' based on the string representation in
377376bd9cbSDarrel Goeddel  * the string `str'.  This function will allocate temporary memory with the
378376bd9cbSDarrel Goeddel  * given constraints of gfp_mask.
379376bd9cbSDarrel Goeddel  */
380376bd9cbSDarrel Goeddel int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
381376bd9cbSDarrel Goeddel {
382376bd9cbSDarrel Goeddel 	char *tmpstr, *freestr;
383376bd9cbSDarrel Goeddel 	int rc;
384376bd9cbSDarrel Goeddel 
385376bd9cbSDarrel Goeddel 	if (!selinux_mls_enabled)
386376bd9cbSDarrel Goeddel 		return -EINVAL;
387376bd9cbSDarrel Goeddel 
388376bd9cbSDarrel Goeddel 	/* we need freestr because mls_context_to_sid will change
389376bd9cbSDarrel Goeddel 	   the value of tmpstr */
390376bd9cbSDarrel Goeddel 	tmpstr = freestr = kstrdup(str, gfp_mask);
391376bd9cbSDarrel Goeddel 	if (!tmpstr) {
392376bd9cbSDarrel Goeddel 		rc = -ENOMEM;
393376bd9cbSDarrel Goeddel 	} else {
394376bd9cbSDarrel Goeddel 		rc = mls_context_to_sid(':', &tmpstr, context,
395376bd9cbSDarrel Goeddel 		                        NULL, SECSID_NULL);
396376bd9cbSDarrel Goeddel 		kfree(freestr);
397376bd9cbSDarrel Goeddel 	}
398376bd9cbSDarrel Goeddel 
399376bd9cbSDarrel Goeddel 	return rc;
400376bd9cbSDarrel Goeddel }
401376bd9cbSDarrel Goeddel 
402376bd9cbSDarrel Goeddel /*
4031da177e4SLinus Torvalds  * Copies the effective MLS range from `src' into `dst'.
4041da177e4SLinus Torvalds  */
4051da177e4SLinus Torvalds static inline int mls_scopy_context(struct context *dst,
4061da177e4SLinus Torvalds                                     struct context *src)
4071da177e4SLinus Torvalds {
4081da177e4SLinus Torvalds 	int l, rc = 0;
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 	/* Copy the MLS range from the source context */
4111da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
4121da177e4SLinus Torvalds 		dst->range.level[l].sens = src->range.level[0].sens;
4131da177e4SLinus Torvalds 		rc = ebitmap_cpy(&dst->range.level[l].cat,
4141da177e4SLinus Torvalds 				 &src->range.level[0].cat);
4151da177e4SLinus Torvalds 		if (rc)
4161da177e4SLinus Torvalds 			break;
4171da177e4SLinus Torvalds 	}
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	return rc;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds /*
4231da177e4SLinus Torvalds  * Copies the MLS range `range' into `context'.
4241da177e4SLinus Torvalds  */
4251da177e4SLinus Torvalds static inline int mls_range_set(struct context *context,
4261da177e4SLinus Torvalds                                 struct mls_range *range)
4271da177e4SLinus Torvalds {
4281da177e4SLinus Torvalds 	int l, rc = 0;
4291da177e4SLinus Torvalds 
4301da177e4SLinus Torvalds 	/* Copy the MLS range into the  context */
4311da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
4321da177e4SLinus Torvalds 		context->range.level[l].sens = range->level[l].sens;
4331da177e4SLinus Torvalds 		rc = ebitmap_cpy(&context->range.level[l].cat,
4341da177e4SLinus Torvalds 				 &range->level[l].cat);
4351da177e4SLinus Torvalds 		if (rc)
4361da177e4SLinus Torvalds 			break;
4371da177e4SLinus Torvalds 	}
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 	return rc;
4401da177e4SLinus Torvalds }
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
4431da177e4SLinus Torvalds                          struct context *usercon)
4441da177e4SLinus Torvalds {
4451da177e4SLinus Torvalds 	if (selinux_mls_enabled) {
4461da177e4SLinus Torvalds 		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
4471da177e4SLinus Torvalds 		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
4481da177e4SLinus Torvalds 		struct mls_level *user_low = &(user->range.level[0]);
4491da177e4SLinus Torvalds 		struct mls_level *user_clr = &(user->range.level[1]);
4501da177e4SLinus Torvalds 		struct mls_level *user_def = &(user->dfltlevel);
4511da177e4SLinus Torvalds 		struct mls_level *usercon_sen = &(usercon->range.level[0]);
4521da177e4SLinus Torvalds 		struct mls_level *usercon_clr = &(usercon->range.level[1]);
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 		/* Honor the user's default level if we can */
4551da177e4SLinus Torvalds 		if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
4561da177e4SLinus Torvalds 			*usercon_sen = *user_def;
4571da177e4SLinus Torvalds 		} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
4581da177e4SLinus Torvalds 			*usercon_sen = *fromcon_sen;
4591da177e4SLinus Torvalds 		} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
4601da177e4SLinus Torvalds 			*usercon_sen = *user_low;
4611da177e4SLinus Torvalds 		} else
4621da177e4SLinus Torvalds 			return -EINVAL;
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 		/* Lower the clearance of available contexts
4651da177e4SLinus Torvalds 		   if the clearance of "fromcon" is lower than
4661da177e4SLinus Torvalds 		   that of the user's default clearance (but
4671da177e4SLinus Torvalds 		   only if the "fromcon" clearance dominates
4681da177e4SLinus Torvalds 		   the user's computed sensitivity level) */
4691da177e4SLinus Torvalds 		if (mls_level_dom(user_clr, fromcon_clr)) {
4701da177e4SLinus Torvalds 			*usercon_clr = *fromcon_clr;
4711da177e4SLinus Torvalds 		} else if (mls_level_dom(fromcon_clr, user_clr)) {
4721da177e4SLinus Torvalds 			*usercon_clr = *user_clr;
4731da177e4SLinus Torvalds 		} else
4741da177e4SLinus Torvalds 			return -EINVAL;
4751da177e4SLinus Torvalds 	}
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	return 0;
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds /*
4811da177e4SLinus Torvalds  * Convert the MLS fields in the security context
4821da177e4SLinus Torvalds  * structure `c' from the values specified in the
4831da177e4SLinus Torvalds  * policy `oldp' to the values specified in the policy `newp'.
4841da177e4SLinus Torvalds  */
4851da177e4SLinus Torvalds int mls_convert_context(struct policydb *oldp,
4861da177e4SLinus Torvalds 			struct policydb *newp,
4871da177e4SLinus Torvalds 			struct context *c)
4881da177e4SLinus Torvalds {
4891da177e4SLinus Torvalds 	struct level_datum *levdatum;
4901da177e4SLinus Torvalds 	struct cat_datum *catdatum;
4911da177e4SLinus Torvalds 	struct ebitmap bitmap;
492782ebb99SStephen Smalley 	struct ebitmap_node *node;
4931da177e4SLinus Torvalds 	int l, i;
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
4961da177e4SLinus Torvalds 		return 0;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
4991da177e4SLinus Torvalds 		levdatum = hashtab_search(newp->p_levels.table,
5001da177e4SLinus Torvalds 			oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 		if (!levdatum)
5031da177e4SLinus Torvalds 			return -EINVAL;
5041da177e4SLinus Torvalds 		c->range.level[l].sens = levdatum->level->sens;
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 		ebitmap_init(&bitmap);
507782ebb99SStephen Smalley 		ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
508782ebb99SStephen Smalley 			if (ebitmap_node_get_bit(node, i)) {
5091da177e4SLinus Torvalds 				int rc;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 				catdatum = hashtab_search(newp->p_cats.table,
512782ebb99SStephen Smalley 				         	oldp->p_cat_val_to_name[i]);
5131da177e4SLinus Torvalds 				if (!catdatum)
5141da177e4SLinus Torvalds 					return -EINVAL;
5151da177e4SLinus Torvalds 				rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
5161da177e4SLinus Torvalds 				if (rc)
5171da177e4SLinus Torvalds 					return rc;
5181da177e4SLinus Torvalds 			}
5191da177e4SLinus Torvalds 		}
5201da177e4SLinus Torvalds 		ebitmap_destroy(&c->range.level[l].cat);
5211da177e4SLinus Torvalds 		c->range.level[l].cat = bitmap;
5221da177e4SLinus Torvalds 	}
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	return 0;
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds int mls_compute_sid(struct context *scontext,
5281da177e4SLinus Torvalds 		    struct context *tcontext,
5291da177e4SLinus Torvalds 		    u16 tclass,
5301da177e4SLinus Torvalds 		    u32 specified,
5311da177e4SLinus Torvalds 		    struct context *newcontext)
5321da177e4SLinus Torvalds {
5331da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
5341da177e4SLinus Torvalds 		return 0;
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	switch (specified) {
5371da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
5381da177e4SLinus Torvalds 		if (tclass == SECCLASS_PROCESS) {
5391da177e4SLinus Torvalds 			struct range_trans *rangetr;
5401da177e4SLinus Torvalds 			/* Look for a range transition rule. */
5411da177e4SLinus Torvalds 			for (rangetr = policydb.range_tr; rangetr;
5421da177e4SLinus Torvalds 			     rangetr = rangetr->next) {
5431da177e4SLinus Torvalds 				if (rangetr->dom == scontext->type &&
5441da177e4SLinus Torvalds 				    rangetr->type == tcontext->type) {
5451da177e4SLinus Torvalds 					/* Set the range from the rule */
5461da177e4SLinus Torvalds 					return mls_range_set(newcontext,
5471da177e4SLinus Torvalds 					                     &rangetr->range);
5481da177e4SLinus Torvalds 				}
5491da177e4SLinus Torvalds 			}
5501da177e4SLinus Torvalds 		}
5511da177e4SLinus Torvalds 		/* Fallthrough */
5521da177e4SLinus Torvalds 	case AVTAB_CHANGE:
5531da177e4SLinus Torvalds 		if (tclass == SECCLASS_PROCESS)
5541da177e4SLinus Torvalds 			/* Use the process MLS attributes. */
5551da177e4SLinus Torvalds 			return mls_copy_context(newcontext, scontext);
5561da177e4SLinus Torvalds 		else
5571da177e4SLinus Torvalds 			/* Use the process effective MLS attributes. */
5581da177e4SLinus Torvalds 			return mls_scopy_context(newcontext, scontext);
5591da177e4SLinus Torvalds 	case AVTAB_MEMBER:
5601da177e4SLinus Torvalds 		/* Only polyinstantiate the MLS attributes if
5611da177e4SLinus Torvalds 		   the type is being polyinstantiated */
5621da177e4SLinus Torvalds 		if (newcontext->type != tcontext->type) {
5631da177e4SLinus Torvalds 			/* Use the process effective MLS attributes. */
5641da177e4SLinus Torvalds 			return mls_scopy_context(newcontext, scontext);
5651da177e4SLinus Torvalds 		} else {
5661da177e4SLinus Torvalds 			/* Use the related object MLS attributes. */
5671da177e4SLinus Torvalds 			return mls_copy_context(newcontext, tcontext);
5681da177e4SLinus Torvalds 		}
5691da177e4SLinus Torvalds 	default:
5701da177e4SLinus Torvalds 		return -EINVAL;
5711da177e4SLinus Torvalds 	}
5721da177e4SLinus Torvalds 	return -EINVAL;
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds 
575*7420ed23SVenkat Yekkirala /**
576*7420ed23SVenkat Yekkirala  * mls_export_lvl - Export the MLS sensitivity levels
577*7420ed23SVenkat Yekkirala  * @context: the security context
578*7420ed23SVenkat Yekkirala  * @low: the low sensitivity level
579*7420ed23SVenkat Yekkirala  * @high: the high sensitivity level
580*7420ed23SVenkat Yekkirala  *
581*7420ed23SVenkat Yekkirala  * Description:
582*7420ed23SVenkat Yekkirala  * Given the security context copy the low MLS sensitivity level into lvl_low
583*7420ed23SVenkat Yekkirala  * and the high sensitivity level in lvl_high.  The MLS levels are only
584*7420ed23SVenkat Yekkirala  * exported if the pointers are not NULL, if they are NULL then that level is
585*7420ed23SVenkat Yekkirala  * not exported.
586*7420ed23SVenkat Yekkirala  *
587*7420ed23SVenkat Yekkirala  */
588*7420ed23SVenkat Yekkirala void mls_export_lvl(const struct context *context, u32 *low, u32 *high)
589*7420ed23SVenkat Yekkirala {
590*7420ed23SVenkat Yekkirala 	if (!selinux_mls_enabled)
591*7420ed23SVenkat Yekkirala 		return;
592*7420ed23SVenkat Yekkirala 
593*7420ed23SVenkat Yekkirala 	if (low != NULL)
594*7420ed23SVenkat Yekkirala 		*low = context->range.level[0].sens - 1;
595*7420ed23SVenkat Yekkirala 	if (high != NULL)
596*7420ed23SVenkat Yekkirala 		*high = context->range.level[1].sens - 1;
597*7420ed23SVenkat Yekkirala }
598*7420ed23SVenkat Yekkirala 
599*7420ed23SVenkat Yekkirala /**
600*7420ed23SVenkat Yekkirala  * mls_import_lvl - Import the MLS sensitivity levels
601*7420ed23SVenkat Yekkirala  * @context: the security context
602*7420ed23SVenkat Yekkirala  * @low: the low sensitivity level
603*7420ed23SVenkat Yekkirala  * @high: the high sensitivity level
604*7420ed23SVenkat Yekkirala  *
605*7420ed23SVenkat Yekkirala  * Description:
606*7420ed23SVenkat Yekkirala  * Given the security context and the two sensitivty levels, set the MLS levels
607*7420ed23SVenkat Yekkirala  * in the context according the two given as parameters.  Returns zero on
608*7420ed23SVenkat Yekkirala  * success, negative values on failure.
609*7420ed23SVenkat Yekkirala  *
610*7420ed23SVenkat Yekkirala  */
611*7420ed23SVenkat Yekkirala void mls_import_lvl(struct context *context, u32 low, u32 high)
612*7420ed23SVenkat Yekkirala {
613*7420ed23SVenkat Yekkirala 	if (!selinux_mls_enabled)
614*7420ed23SVenkat Yekkirala 		return;
615*7420ed23SVenkat Yekkirala 
616*7420ed23SVenkat Yekkirala 	context->range.level[0].sens = low + 1;
617*7420ed23SVenkat Yekkirala 	context->range.level[1].sens = high + 1;
618*7420ed23SVenkat Yekkirala }
619*7420ed23SVenkat Yekkirala 
620*7420ed23SVenkat Yekkirala /**
621*7420ed23SVenkat Yekkirala  * mls_export_cat - Export the MLS categories
622*7420ed23SVenkat Yekkirala  * @context: the security context
623*7420ed23SVenkat Yekkirala  * @low: the low category
624*7420ed23SVenkat Yekkirala  * @low_len: length of the cat_low bitmap in bytes
625*7420ed23SVenkat Yekkirala  * @high: the high category
626*7420ed23SVenkat Yekkirala  * @high_len: length of the cat_high bitmap in bytes
627*7420ed23SVenkat Yekkirala  *
628*7420ed23SVenkat Yekkirala  * Description:
629*7420ed23SVenkat Yekkirala  * Given the security context export the low MLS category bitmap into cat_low
630*7420ed23SVenkat Yekkirala  * and the high category bitmap into cat_high.  The MLS categories are only
631*7420ed23SVenkat Yekkirala  * exported if the pointers are not NULL, if they are NULL then that level is
632*7420ed23SVenkat Yekkirala  * not exported.  The caller is responsibile for freeing the memory when
633*7420ed23SVenkat Yekkirala  * finished.  Returns zero on success, negative values on failure.
634*7420ed23SVenkat Yekkirala  *
635*7420ed23SVenkat Yekkirala  */
636*7420ed23SVenkat Yekkirala int mls_export_cat(const struct context *context,
637*7420ed23SVenkat Yekkirala 		   unsigned char **low,
638*7420ed23SVenkat Yekkirala 		   size_t *low_len,
639*7420ed23SVenkat Yekkirala 		   unsigned char **high,
640*7420ed23SVenkat Yekkirala 		   size_t *high_len)
641*7420ed23SVenkat Yekkirala {
642*7420ed23SVenkat Yekkirala 	int rc = -EPERM;
643*7420ed23SVenkat Yekkirala 
644*7420ed23SVenkat Yekkirala 	if (!selinux_mls_enabled)
645*7420ed23SVenkat Yekkirala 		return 0;
646*7420ed23SVenkat Yekkirala 
647*7420ed23SVenkat Yekkirala 	if (low != NULL) {
648*7420ed23SVenkat Yekkirala 		rc = ebitmap_export(&context->range.level[0].cat,
649*7420ed23SVenkat Yekkirala 				    low,
650*7420ed23SVenkat Yekkirala 				    low_len);
651*7420ed23SVenkat Yekkirala 		if (rc != 0)
652*7420ed23SVenkat Yekkirala 			goto export_cat_failure;
653*7420ed23SVenkat Yekkirala 	}
654*7420ed23SVenkat Yekkirala 	if (high != NULL) {
655*7420ed23SVenkat Yekkirala 		rc = ebitmap_export(&context->range.level[1].cat,
656*7420ed23SVenkat Yekkirala 				    high,
657*7420ed23SVenkat Yekkirala 				    high_len);
658*7420ed23SVenkat Yekkirala 		if (rc != 0)
659*7420ed23SVenkat Yekkirala 			goto export_cat_failure;
660*7420ed23SVenkat Yekkirala 	}
661*7420ed23SVenkat Yekkirala 
662*7420ed23SVenkat Yekkirala 	return 0;
663*7420ed23SVenkat Yekkirala 
664*7420ed23SVenkat Yekkirala export_cat_failure:
665*7420ed23SVenkat Yekkirala 	if (low != NULL)
666*7420ed23SVenkat Yekkirala 		kfree(*low);
667*7420ed23SVenkat Yekkirala 	if (high != NULL)
668*7420ed23SVenkat Yekkirala 		kfree(*high);
669*7420ed23SVenkat Yekkirala 	return rc;
670*7420ed23SVenkat Yekkirala }
671*7420ed23SVenkat Yekkirala 
672*7420ed23SVenkat Yekkirala /**
673*7420ed23SVenkat Yekkirala  * mls_import_cat - Import the MLS categories
674*7420ed23SVenkat Yekkirala  * @context: the security context
675*7420ed23SVenkat Yekkirala  * @low: the low category
676*7420ed23SVenkat Yekkirala  * @low_len: length of the cat_low bitmap in bytes
677*7420ed23SVenkat Yekkirala  * @high: the high category
678*7420ed23SVenkat Yekkirala  * @high_len: length of the cat_high bitmap in bytes
679*7420ed23SVenkat Yekkirala  *
680*7420ed23SVenkat Yekkirala  * Description:
681*7420ed23SVenkat Yekkirala  * Given the security context and the two category bitmap strings import the
682*7420ed23SVenkat Yekkirala  * categories into the security context.  The MLS categories are only imported
683*7420ed23SVenkat Yekkirala  * if the pointers are not NULL, if they are NULL they are skipped.  Returns
684*7420ed23SVenkat Yekkirala  * zero on success, negative values on failure.
685*7420ed23SVenkat Yekkirala  *
686*7420ed23SVenkat Yekkirala  */
687*7420ed23SVenkat Yekkirala int mls_import_cat(struct context *context,
688*7420ed23SVenkat Yekkirala 		   const unsigned char *low,
689*7420ed23SVenkat Yekkirala 		   size_t low_len,
690*7420ed23SVenkat Yekkirala 		   const unsigned char *high,
691*7420ed23SVenkat Yekkirala 		   size_t high_len)
692*7420ed23SVenkat Yekkirala {
693*7420ed23SVenkat Yekkirala 	int rc = -EPERM;
694*7420ed23SVenkat Yekkirala 
695*7420ed23SVenkat Yekkirala 	if (!selinux_mls_enabled)
696*7420ed23SVenkat Yekkirala 		return 0;
697*7420ed23SVenkat Yekkirala 
698*7420ed23SVenkat Yekkirala 	if (low != NULL) {
699*7420ed23SVenkat Yekkirala 		rc = ebitmap_import(low,
700*7420ed23SVenkat Yekkirala 				    low_len,
701*7420ed23SVenkat Yekkirala 				    &context->range.level[0].cat);
702*7420ed23SVenkat Yekkirala 		if (rc != 0)
703*7420ed23SVenkat Yekkirala 			goto import_cat_failure;
704*7420ed23SVenkat Yekkirala 	}
705*7420ed23SVenkat Yekkirala 	if (high != NULL) {
706*7420ed23SVenkat Yekkirala 		if (high == low)
707*7420ed23SVenkat Yekkirala 			rc = ebitmap_cpy(&context->range.level[1].cat,
708*7420ed23SVenkat Yekkirala 					 &context->range.level[0].cat);
709*7420ed23SVenkat Yekkirala 		else
710*7420ed23SVenkat Yekkirala 			rc = ebitmap_import(high,
711*7420ed23SVenkat Yekkirala 					    high_len,
712*7420ed23SVenkat Yekkirala 					    &context->range.level[1].cat);
713*7420ed23SVenkat Yekkirala 		if (rc != 0)
714*7420ed23SVenkat Yekkirala 			goto import_cat_failure;
715*7420ed23SVenkat Yekkirala 	}
716*7420ed23SVenkat Yekkirala 
717*7420ed23SVenkat Yekkirala 	return 0;
718*7420ed23SVenkat Yekkirala 
719*7420ed23SVenkat Yekkirala import_cat_failure:
720*7420ed23SVenkat Yekkirala 	ebitmap_destroy(&context->range.level[0].cat);
721*7420ed23SVenkat Yekkirala 	ebitmap_destroy(&context->range.level[1].cat);
722*7420ed23SVenkat Yekkirala 	return rc;
723*7420ed23SVenkat Yekkirala }
724