xref: /linux/security/selinux/ss/mls.c (revision f5269710)
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  */
137420ed23SVenkat Yekkirala /*
147420ed23SVenkat Yekkirala  * Updated: Hewlett-Packard <paul.moore@hp.com>
157420ed23SVenkat Yekkirala  *
1602752760SPaul Moore  *      Added support to import/export the MLS label from NetLabel
177420ed23SVenkat Yekkirala  *
187420ed23SVenkat Yekkirala  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
197420ed23SVenkat 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>
2502752760SPaul Moore #include <net/netlabel.h>
26f5c1d5b2SJames Morris #include "sidtab.h"
271da177e4SLinus Torvalds #include "mls.h"
281da177e4SLinus Torvalds #include "policydb.h"
291da177e4SLinus Torvalds #include "services.h"
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds /*
321da177e4SLinus Torvalds  * Return the length in bytes for the MLS fields of the
331da177e4SLinus Torvalds  * security context string representation of `context'.
341da177e4SLinus Torvalds  */
351da177e4SLinus Torvalds int mls_compute_context_len(struct context *context)
361da177e4SLinus Torvalds {
379fe79ad1SKaiGai Kohei 	int i, l, len, head, prev;
389fe79ad1SKaiGai Kohei 	char *nm;
399fe79ad1SKaiGai Kohei 	struct ebitmap *e;
40782ebb99SStephen Smalley 	struct ebitmap_node *node;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
431da177e4SLinus Torvalds 		return 0;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 	len = 1; /* for the beginning ":" */
461da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
479fe79ad1SKaiGai Kohei 		int index_sens = context->range.level[l].sens;
489fe79ad1SKaiGai Kohei 		len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
491da177e4SLinus Torvalds 
509fe79ad1SKaiGai Kohei 		/* categories */
519fe79ad1SKaiGai Kohei 		head = -2;
529fe79ad1SKaiGai Kohei 		prev = -2;
539fe79ad1SKaiGai Kohei 		e = &context->range.level[l].cat;
549fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(e, node, i) {
559fe79ad1SKaiGai Kohei 			if (i - prev > 1) {
569fe79ad1SKaiGai Kohei 				/* one or more negative bits are skipped */
579fe79ad1SKaiGai Kohei 				if (head != prev) {
589fe79ad1SKaiGai Kohei 					nm = policydb.p_cat_val_to_name[prev];
599fe79ad1SKaiGai Kohei 					len += strlen(nm) + 1;
601da177e4SLinus Torvalds 				}
619fe79ad1SKaiGai Kohei 				nm = policydb.p_cat_val_to_name[i];
629fe79ad1SKaiGai Kohei 				len += strlen(nm) + 1;
639fe79ad1SKaiGai Kohei 				head = i;
641da177e4SLinus Torvalds 			}
659fe79ad1SKaiGai Kohei 			prev = i;
661da177e4SLinus Torvalds 		}
679fe79ad1SKaiGai Kohei 		if (prev != head) {
689fe79ad1SKaiGai Kohei 			nm = policydb.p_cat_val_to_name[prev];
699fe79ad1SKaiGai Kohei 			len += strlen(nm) + 1;
709fe79ad1SKaiGai Kohei 		}
711da177e4SLinus Torvalds 		if (l == 0) {
721da177e4SLinus Torvalds 			if (mls_level_eq(&context->range.level[0],
731da177e4SLinus Torvalds 					 &context->range.level[1]))
741da177e4SLinus Torvalds 				break;
751da177e4SLinus Torvalds 			else
761da177e4SLinus Torvalds 				len++;
771da177e4SLinus Torvalds 		}
781da177e4SLinus Torvalds 	}
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 	return len;
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds /*
841da177e4SLinus Torvalds  * Write the security context string representation of
851da177e4SLinus Torvalds  * the MLS fields of `context' into the string `*scontext'.
861da177e4SLinus Torvalds  * Update `*scontext' to point to the end of the MLS fields.
871da177e4SLinus Torvalds  */
881da177e4SLinus Torvalds void mls_sid_to_context(struct context *context,
891da177e4SLinus Torvalds 			char **scontext)
901da177e4SLinus Torvalds {
919fe79ad1SKaiGai Kohei 	char *scontextp, *nm;
929fe79ad1SKaiGai Kohei 	int i, l, head, prev;
939fe79ad1SKaiGai Kohei 	struct ebitmap *e;
94782ebb99SStephen Smalley 	struct ebitmap_node *node;
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
971da177e4SLinus Torvalds 		return;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	scontextp = *scontext;
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	*scontextp = ':';
1021da177e4SLinus Torvalds 	scontextp++;
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
1051da177e4SLinus Torvalds 		strcpy(scontextp,
1061da177e4SLinus Torvalds 		       policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
1079fe79ad1SKaiGai Kohei 		scontextp += strlen(scontextp);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 		/* categories */
1109fe79ad1SKaiGai Kohei 		head = -2;
1119fe79ad1SKaiGai Kohei 		prev = -2;
1129fe79ad1SKaiGai Kohei 		e = &context->range.level[l].cat;
1139fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(e, node, i) {
1149fe79ad1SKaiGai Kohei 			if (i - prev > 1) {
1159fe79ad1SKaiGai Kohei 				/* one or more negative bits are skipped */
1169fe79ad1SKaiGai Kohei 				if (prev != head) {
1179fe79ad1SKaiGai Kohei 					if (prev - head > 1)
1189fe79ad1SKaiGai Kohei 						*scontextp++ = '.';
1199fe79ad1SKaiGai Kohei 					else
1209fe79ad1SKaiGai Kohei 						*scontextp++ = ',';
1219fe79ad1SKaiGai Kohei 					nm = policydb.p_cat_val_to_name[prev];
1229fe79ad1SKaiGai Kohei 					strcpy(scontextp, nm);
1239fe79ad1SKaiGai Kohei 					scontextp += strlen(nm);
1241da177e4SLinus Torvalds 				}
1259fe79ad1SKaiGai Kohei 				if (prev < 0)
1261da177e4SLinus Torvalds 					*scontextp++ = ':';
1279fe79ad1SKaiGai Kohei 				else
1281da177e4SLinus Torvalds 					*scontextp++ = ',';
1299fe79ad1SKaiGai Kohei 				nm = policydb.p_cat_val_to_name[i];
1309fe79ad1SKaiGai Kohei 				strcpy(scontextp, nm);
1319fe79ad1SKaiGai Kohei 				scontextp += strlen(nm);
1329fe79ad1SKaiGai Kohei 				head = i;
1339fe79ad1SKaiGai Kohei 			}
1349fe79ad1SKaiGai Kohei 			prev = i;
1359fe79ad1SKaiGai Kohei 		}
1369fe79ad1SKaiGai Kohei 
1379fe79ad1SKaiGai Kohei 		if (prev != head) {
1389fe79ad1SKaiGai Kohei 			if (prev - head > 1)
1391da177e4SLinus Torvalds 				*scontextp++ = '.';
1401da177e4SLinus Torvalds 			else
1411da177e4SLinus Torvalds 				*scontextp++ = ',';
1429fe79ad1SKaiGai Kohei 			nm = policydb.p_cat_val_to_name[prev];
1439fe79ad1SKaiGai Kohei 			strcpy(scontextp, nm);
1449fe79ad1SKaiGai Kohei 			scontextp += strlen(nm);
1451da177e4SLinus Torvalds 		}
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 		if (l == 0) {
1481da177e4SLinus Torvalds 			if (mls_level_eq(&context->range.level[0],
1491da177e4SLinus Torvalds 					 &context->range.level[1]))
1501da177e4SLinus Torvalds 				break;
1519fe79ad1SKaiGai Kohei 			else
1529fe79ad1SKaiGai Kohei 				*scontextp++ = '-';
1531da177e4SLinus Torvalds 		}
1541da177e4SLinus Torvalds 	}
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	*scontext = scontextp;
1571da177e4SLinus Torvalds 	return;
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
16045e5421eSStephen Smalley int mls_level_isvalid(struct policydb *p, struct mls_level *l)
16145e5421eSStephen Smalley {
16245e5421eSStephen Smalley 	struct level_datum *levdatum;
16345e5421eSStephen Smalley 	struct ebitmap_node *node;
16445e5421eSStephen Smalley 	int i;
16545e5421eSStephen Smalley 
16645e5421eSStephen Smalley 	if (!l->sens || l->sens > p->p_levels.nprim)
16745e5421eSStephen Smalley 		return 0;
16845e5421eSStephen Smalley 	levdatum = hashtab_search(p->p_levels.table,
16945e5421eSStephen Smalley 				  p->p_sens_val_to_name[l->sens - 1]);
17045e5421eSStephen Smalley 	if (!levdatum)
17145e5421eSStephen Smalley 		return 0;
17245e5421eSStephen Smalley 
17345e5421eSStephen Smalley 	ebitmap_for_each_positive_bit(&l->cat, node, i) {
17445e5421eSStephen Smalley 		if (i > p->p_cats.nprim)
17545e5421eSStephen Smalley 			return 0;
17645e5421eSStephen Smalley 		if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
17745e5421eSStephen Smalley 			/*
17845e5421eSStephen Smalley 			 * Category may not be associated with
17945e5421eSStephen Smalley 			 * sensitivity.
18045e5421eSStephen Smalley 			 */
18145e5421eSStephen Smalley 			return 0;
18245e5421eSStephen Smalley 		}
18345e5421eSStephen Smalley 	}
18445e5421eSStephen Smalley 
18545e5421eSStephen Smalley 	return 1;
18645e5421eSStephen Smalley }
18745e5421eSStephen Smalley 
18845e5421eSStephen Smalley int mls_range_isvalid(struct policydb *p, struct mls_range *r)
18945e5421eSStephen Smalley {
19045e5421eSStephen Smalley 	return (mls_level_isvalid(p, &r->level[0]) &&
19145e5421eSStephen Smalley 		mls_level_isvalid(p, &r->level[1]) &&
19245e5421eSStephen Smalley 		mls_level_dom(&r->level[1], &r->level[0]));
19345e5421eSStephen Smalley }
19445e5421eSStephen Smalley 
1951da177e4SLinus Torvalds /*
1961da177e4SLinus Torvalds  * Return 1 if the MLS fields in the security context
1971da177e4SLinus Torvalds  * structure `c' are valid.  Return 0 otherwise.
1981da177e4SLinus Torvalds  */
1991da177e4SLinus Torvalds int mls_context_isvalid(struct policydb *p, struct context *c)
2001da177e4SLinus Torvalds {
2011da177e4SLinus Torvalds 	struct user_datum *usrdatum;
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
2041da177e4SLinus Torvalds 		return 1;
2051da177e4SLinus Torvalds 
20645e5421eSStephen Smalley 	if (!mls_range_isvalid(p, &c->range))
2071da177e4SLinus Torvalds 		return 0;
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	if (c->role == OBJECT_R_VAL)
2101da177e4SLinus Torvalds 		return 1;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	/*
2131da177e4SLinus Torvalds 	 * User must be authorized for the MLS range.
2141da177e4SLinus Torvalds 	 */
2151da177e4SLinus Torvalds 	if (!c->user || c->user > p->p_users.nprim)
2161da177e4SLinus Torvalds 		return 0;
2171da177e4SLinus Torvalds 	usrdatum = p->user_val_to_struct[c->user - 1];
2181da177e4SLinus Torvalds 	if (!mls_range_contains(usrdatum->range, c->range))
2191da177e4SLinus Torvalds 		return 0; /* user may not be associated with range */
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	return 1;
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds /*
2251da177e4SLinus Torvalds  * Set the MLS fields in the security context structure
2261da177e4SLinus Torvalds  * `context' based on the string representation in
2271da177e4SLinus Torvalds  * the string `*scontext'.  Update `*scontext' to
2281da177e4SLinus Torvalds  * point to the end of the string representation of
2291da177e4SLinus Torvalds  * the MLS fields.
2301da177e4SLinus Torvalds  *
2311da177e4SLinus Torvalds  * This function modifies the string in place, inserting
2321da177e4SLinus Torvalds  * NULL characters to terminate the MLS fields.
233f5c1d5b2SJames Morris  *
234f5c1d5b2SJames Morris  * If a def_sid is provided and no MLS field is present,
235f5c1d5b2SJames Morris  * copy the MLS field of the associated default context.
236f5c1d5b2SJames Morris  * Used for upgraded to MLS systems where objects may lack
237f5c1d5b2SJames Morris  * MLS fields.
238f5c1d5b2SJames Morris  *
239f5c1d5b2SJames Morris  * Policy read-lock must be held for sidtab lookup.
240f5c1d5b2SJames Morris  *
2411da177e4SLinus Torvalds  */
24212b29f34SStephen Smalley int mls_context_to_sid(struct policydb *pol,
24312b29f34SStephen Smalley 		       char oldc,
2441da177e4SLinus Torvalds 		       char **scontext,
245f5c1d5b2SJames Morris 		       struct context *context,
246f5c1d5b2SJames Morris 		       struct sidtab *s,
247f5c1d5b2SJames Morris 		       u32 def_sid)
2481da177e4SLinus Torvalds {
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	char delim;
2511da177e4SLinus Torvalds 	char *scontextp, *p, *rngptr;
2521da177e4SLinus Torvalds 	struct level_datum *levdatum;
2531da177e4SLinus Torvalds 	struct cat_datum *catdatum, *rngdatum;
2541da177e4SLinus Torvalds 	int l, rc = -EINVAL;
2551da177e4SLinus Torvalds 
256e517a0cdSStephen Smalley 	if (!selinux_mls_enabled) {
257e517a0cdSStephen Smalley 		if (def_sid != SECSID_NULL && oldc)
258ab5703b3SRon Yorston 			*scontext += strlen(*scontext)+1;
2591da177e4SLinus Torvalds 		return 0;
260e517a0cdSStephen Smalley 	}
2611da177e4SLinus Torvalds 
262f5c1d5b2SJames Morris 	/*
263f5c1d5b2SJames Morris 	 * No MLS component to the security context, try and map to
264f5c1d5b2SJames Morris 	 * default if provided.
265f5c1d5b2SJames Morris 	 */
266f5c1d5b2SJames Morris 	if (!oldc) {
267f5c1d5b2SJames Morris 		struct context *defcon;
268f5c1d5b2SJames Morris 
269f5c1d5b2SJames Morris 		if (def_sid == SECSID_NULL)
2701da177e4SLinus Torvalds 			goto out;
2711da177e4SLinus Torvalds 
272f5c1d5b2SJames Morris 		defcon = sidtab_search(s, def_sid);
273f5c1d5b2SJames Morris 		if (!defcon)
274f5c1d5b2SJames Morris 			goto out;
275f5c1d5b2SJames Morris 
2760efc61eaSVenkat Yekkirala 		rc = mls_context_cpy(context, defcon);
277f5c1d5b2SJames Morris 		goto out;
278f5c1d5b2SJames Morris 	}
279f5c1d5b2SJames Morris 
2801da177e4SLinus Torvalds 	/* Extract low sensitivity. */
2811da177e4SLinus Torvalds 	scontextp = p = *scontext;
2821da177e4SLinus Torvalds 	while (*p && *p != ':' && *p != '-')
2831da177e4SLinus Torvalds 		p++;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	delim = *p;
2861da177e4SLinus Torvalds 	if (delim != 0)
2871da177e4SLinus Torvalds 		*p++ = 0;
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
29012b29f34SStephen Smalley 		levdatum = hashtab_search(pol->p_levels.table, scontextp);
2911da177e4SLinus Torvalds 		if (!levdatum) {
2921da177e4SLinus Torvalds 			rc = -EINVAL;
2931da177e4SLinus Torvalds 			goto out;
2941da177e4SLinus Torvalds 		}
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 		context->range.level[l].sens = levdatum->level->sens;
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 		if (delim == ':') {
2991da177e4SLinus Torvalds 			/* Extract category set. */
3001da177e4SLinus Torvalds 			while (1) {
3011da177e4SLinus Torvalds 				scontextp = p;
3021da177e4SLinus Torvalds 				while (*p && *p != ',' && *p != '-')
3031da177e4SLinus Torvalds 					p++;
3041da177e4SLinus Torvalds 				delim = *p;
3051da177e4SLinus Torvalds 				if (delim != 0)
3061da177e4SLinus Torvalds 					*p++ = 0;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 				/* Separate into range if exists */
3091a5e6f87SEric Paris 				rngptr = strchr(scontextp, '.');
3101a5e6f87SEric Paris 				if (rngptr != NULL) {
3111da177e4SLinus Torvalds 					/* Remove '.' */
3121da177e4SLinus Torvalds 					*rngptr++ = 0;
3131da177e4SLinus Torvalds 				}
3141da177e4SLinus Torvalds 
31512b29f34SStephen Smalley 				catdatum = hashtab_search(pol->p_cats.table,
3161da177e4SLinus Torvalds 							  scontextp);
3171da177e4SLinus Torvalds 				if (!catdatum) {
3181da177e4SLinus Torvalds 					rc = -EINVAL;
3191da177e4SLinus Torvalds 					goto out;
3201da177e4SLinus Torvalds 				}
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 				rc = ebitmap_set_bit(&context->range.level[l].cat,
3231da177e4SLinus Torvalds 						     catdatum->value - 1, 1);
3241da177e4SLinus Torvalds 				if (rc)
3251da177e4SLinus Torvalds 					goto out;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 				/* If range, set all categories in range */
3281da177e4SLinus Torvalds 				if (rngptr) {
3291da177e4SLinus Torvalds 					int i;
3301da177e4SLinus Torvalds 
33112b29f34SStephen Smalley 					rngdatum = hashtab_search(pol->p_cats.table, rngptr);
3321da177e4SLinus Torvalds 					if (!rngdatum) {
3331da177e4SLinus Torvalds 						rc = -EINVAL;
3341da177e4SLinus Torvalds 						goto out;
3351da177e4SLinus Torvalds 					}
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 					if (catdatum->value >= rngdatum->value) {
3381da177e4SLinus Torvalds 						rc = -EINVAL;
3391da177e4SLinus Torvalds 						goto out;
3401da177e4SLinus Torvalds 					}
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 					for (i = catdatum->value; i < rngdatum->value; i++) {
3431da177e4SLinus Torvalds 						rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
3441da177e4SLinus Torvalds 						if (rc)
3451da177e4SLinus Torvalds 							goto out;
3461da177e4SLinus Torvalds 					}
3471da177e4SLinus Torvalds 				}
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 				if (delim != ',')
3501da177e4SLinus Torvalds 					break;
3511da177e4SLinus Torvalds 			}
3521da177e4SLinus Torvalds 		}
3531da177e4SLinus Torvalds 		if (delim == '-') {
3541da177e4SLinus Torvalds 			/* Extract high sensitivity. */
3551da177e4SLinus Torvalds 			scontextp = p;
3561da177e4SLinus Torvalds 			while (*p && *p != ':')
3571da177e4SLinus Torvalds 				p++;
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 			delim = *p;
3601da177e4SLinus Torvalds 			if (delim != 0)
3611da177e4SLinus Torvalds 				*p++ = 0;
3621da177e4SLinus Torvalds 		} else
3631da177e4SLinus Torvalds 			break;
3641da177e4SLinus Torvalds 	}
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	if (l == 0) {
3671da177e4SLinus Torvalds 		context->range.level[1].sens = context->range.level[0].sens;
3681da177e4SLinus Torvalds 		rc = ebitmap_cpy(&context->range.level[1].cat,
3691da177e4SLinus Torvalds 				 &context->range.level[0].cat);
3701da177e4SLinus Torvalds 		if (rc)
3711da177e4SLinus Torvalds 			goto out;
3721da177e4SLinus Torvalds 	}
3731da177e4SLinus Torvalds 	*scontext = ++p;
3741da177e4SLinus Torvalds 	rc = 0;
3751da177e4SLinus Torvalds out:
3761da177e4SLinus Torvalds 	return rc;
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds /*
380376bd9cbSDarrel Goeddel  * Set the MLS fields in the security context structure
381376bd9cbSDarrel Goeddel  * `context' based on the string representation in
382376bd9cbSDarrel Goeddel  * the string `str'.  This function will allocate temporary memory with the
383376bd9cbSDarrel Goeddel  * given constraints of gfp_mask.
384376bd9cbSDarrel Goeddel  */
385376bd9cbSDarrel Goeddel int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
386376bd9cbSDarrel Goeddel {
387376bd9cbSDarrel Goeddel 	char *tmpstr, *freestr;
388376bd9cbSDarrel Goeddel 	int rc;
389376bd9cbSDarrel Goeddel 
390376bd9cbSDarrel Goeddel 	if (!selinux_mls_enabled)
391376bd9cbSDarrel Goeddel 		return -EINVAL;
392376bd9cbSDarrel Goeddel 
393376bd9cbSDarrel Goeddel 	/* we need freestr because mls_context_to_sid will change
394376bd9cbSDarrel Goeddel 	   the value of tmpstr */
395376bd9cbSDarrel Goeddel 	tmpstr = freestr = kstrdup(str, gfp_mask);
396376bd9cbSDarrel Goeddel 	if (!tmpstr) {
397376bd9cbSDarrel Goeddel 		rc = -ENOMEM;
398376bd9cbSDarrel Goeddel 	} else {
39912b29f34SStephen Smalley 		rc = mls_context_to_sid(&policydb, ':', &tmpstr, context,
400376bd9cbSDarrel Goeddel 					NULL, SECSID_NULL);
401376bd9cbSDarrel Goeddel 		kfree(freestr);
402376bd9cbSDarrel Goeddel 	}
403376bd9cbSDarrel Goeddel 
404376bd9cbSDarrel Goeddel 	return rc;
405376bd9cbSDarrel Goeddel }
406376bd9cbSDarrel Goeddel 
407376bd9cbSDarrel Goeddel /*
4081da177e4SLinus Torvalds  * Copies the MLS range `range' into `context'.
4091da177e4SLinus Torvalds  */
4101da177e4SLinus Torvalds static inline int mls_range_set(struct context *context,
4111da177e4SLinus Torvalds 				struct mls_range *range)
4121da177e4SLinus Torvalds {
4131da177e4SLinus Torvalds 	int l, rc = 0;
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	/* Copy the MLS range into the  context */
4161da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
4171da177e4SLinus Torvalds 		context->range.level[l].sens = range->level[l].sens;
4181da177e4SLinus Torvalds 		rc = ebitmap_cpy(&context->range.level[l].cat,
4191da177e4SLinus Torvalds 				 &range->level[l].cat);
4201da177e4SLinus Torvalds 		if (rc)
4211da177e4SLinus Torvalds 			break;
4221da177e4SLinus Torvalds 	}
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	return rc;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
4281da177e4SLinus Torvalds 			 struct context *usercon)
4291da177e4SLinus Torvalds {
4301da177e4SLinus Torvalds 	if (selinux_mls_enabled) {
4311da177e4SLinus Torvalds 		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
4321da177e4SLinus Torvalds 		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
4331da177e4SLinus Torvalds 		struct mls_level *user_low = &(user->range.level[0]);
4341da177e4SLinus Torvalds 		struct mls_level *user_clr = &(user->range.level[1]);
4351da177e4SLinus Torvalds 		struct mls_level *user_def = &(user->dfltlevel);
4361da177e4SLinus Torvalds 		struct mls_level *usercon_sen = &(usercon->range.level[0]);
4371da177e4SLinus Torvalds 		struct mls_level *usercon_clr = &(usercon->range.level[1]);
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 		/* Honor the user's default level if we can */
440*f5269710SEric Paris 		if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
4411da177e4SLinus Torvalds 			*usercon_sen = *user_def;
442*f5269710SEric Paris 		else if (mls_level_between(fromcon_sen, user_def, user_clr))
4431da177e4SLinus Torvalds 			*usercon_sen = *fromcon_sen;
444*f5269710SEric Paris 		else if (mls_level_between(fromcon_clr, user_low, user_def))
4451da177e4SLinus Torvalds 			*usercon_sen = *user_low;
446*f5269710SEric Paris 		else
4471da177e4SLinus Torvalds 			return -EINVAL;
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 		/* Lower the clearance of available contexts
4501da177e4SLinus Torvalds 		   if the clearance of "fromcon" is lower than
4511da177e4SLinus Torvalds 		   that of the user's default clearance (but
4521da177e4SLinus Torvalds 		   only if the "fromcon" clearance dominates
4531da177e4SLinus Torvalds 		   the user's computed sensitivity level) */
4541a5e6f87SEric Paris 		if (mls_level_dom(user_clr, fromcon_clr))
4551da177e4SLinus Torvalds 			*usercon_clr = *fromcon_clr;
4561a5e6f87SEric Paris 		else if (mls_level_dom(fromcon_clr, user_clr))
4571da177e4SLinus Torvalds 			*usercon_clr = *user_clr;
4581a5e6f87SEric Paris 		else
4591da177e4SLinus Torvalds 			return -EINVAL;
4601da177e4SLinus Torvalds 	}
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	return 0;
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds /*
4661da177e4SLinus Torvalds  * Convert the MLS fields in the security context
4671da177e4SLinus Torvalds  * structure `c' from the values specified in the
4681da177e4SLinus Torvalds  * policy `oldp' to the values specified in the policy `newp'.
4691da177e4SLinus Torvalds  */
4701da177e4SLinus Torvalds int mls_convert_context(struct policydb *oldp,
4711da177e4SLinus Torvalds 			struct policydb *newp,
4721da177e4SLinus Torvalds 			struct context *c)
4731da177e4SLinus Torvalds {
4741da177e4SLinus Torvalds 	struct level_datum *levdatum;
4751da177e4SLinus Torvalds 	struct cat_datum *catdatum;
4761da177e4SLinus Torvalds 	struct ebitmap bitmap;
477782ebb99SStephen Smalley 	struct ebitmap_node *node;
4781da177e4SLinus Torvalds 	int l, i;
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
4811da177e4SLinus Torvalds 		return 0;
4821da177e4SLinus Torvalds 
4831da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
4841da177e4SLinus Torvalds 		levdatum = hashtab_search(newp->p_levels.table,
4851da177e4SLinus Torvalds 			oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 		if (!levdatum)
4881da177e4SLinus Torvalds 			return -EINVAL;
4891da177e4SLinus Torvalds 		c->range.level[l].sens = levdatum->level->sens;
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 		ebitmap_init(&bitmap);
4929fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
4931da177e4SLinus Torvalds 			int rc;
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 			catdatum = hashtab_search(newp->p_cats.table,
496782ebb99SStephen Smalley 						  oldp->p_cat_val_to_name[i]);
4971da177e4SLinus Torvalds 			if (!catdatum)
4981da177e4SLinus Torvalds 				return -EINVAL;
4991da177e4SLinus Torvalds 			rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
5001da177e4SLinus Torvalds 			if (rc)
5011da177e4SLinus Torvalds 				return rc;
5021da177e4SLinus Torvalds 		}
5031da177e4SLinus Torvalds 		ebitmap_destroy(&c->range.level[l].cat);
5041da177e4SLinus Torvalds 		c->range.level[l].cat = bitmap;
5051da177e4SLinus Torvalds 	}
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	return 0;
5081da177e4SLinus Torvalds }
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds int mls_compute_sid(struct context *scontext,
5111da177e4SLinus Torvalds 		    struct context *tcontext,
5121da177e4SLinus Torvalds 		    u16 tclass,
5131da177e4SLinus Torvalds 		    u32 specified,
5141da177e4SLinus Torvalds 		    struct context *newcontext)
5151da177e4SLinus Torvalds {
516f3f87714SDarrel Goeddel 	struct range_trans *rtr;
517f3f87714SDarrel Goeddel 
5181da177e4SLinus Torvalds 	if (!selinux_mls_enabled)
5191da177e4SLinus Torvalds 		return 0;
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	switch (specified) {
5221da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
5231da177e4SLinus Torvalds 		/* Look for a range transition rule. */
524f3f87714SDarrel Goeddel 		for (rtr = policydb.range_tr; rtr; rtr = rtr->next) {
525f3f87714SDarrel Goeddel 			if (rtr->source_type == scontext->type &&
526f3f87714SDarrel Goeddel 			    rtr->target_type == tcontext->type &&
527f3f87714SDarrel Goeddel 			    rtr->target_class == tclass) {
5281da177e4SLinus Torvalds 				/* Set the range from the rule */
5291da177e4SLinus Torvalds 				return mls_range_set(newcontext,
530f3f87714SDarrel Goeddel 						     &rtr->target_range);
5311da177e4SLinus Torvalds 			}
5321da177e4SLinus Torvalds 		}
5331da177e4SLinus Torvalds 		/* Fallthrough */
5341da177e4SLinus Torvalds 	case AVTAB_CHANGE:
5351da177e4SLinus Torvalds 		if (tclass == SECCLASS_PROCESS)
5361da177e4SLinus Torvalds 			/* Use the process MLS attributes. */
5370efc61eaSVenkat Yekkirala 			return mls_context_cpy(newcontext, scontext);
5381da177e4SLinus Torvalds 		else
5391da177e4SLinus Torvalds 			/* Use the process effective MLS attributes. */
5400efc61eaSVenkat Yekkirala 			return mls_context_cpy_low(newcontext, scontext);
5411da177e4SLinus Torvalds 	case AVTAB_MEMBER:
5421da177e4SLinus Torvalds 		/* Use the process effective MLS attributes. */
5430efc61eaSVenkat Yekkirala 		return mls_context_cpy_low(newcontext, scontext);
5441da177e4SLinus Torvalds 	default:
5451da177e4SLinus Torvalds 		return -EINVAL;
5461da177e4SLinus Torvalds 	}
5471da177e4SLinus Torvalds 	return -EINVAL;
5481da177e4SLinus Torvalds }
5491da177e4SLinus Torvalds 
55002752760SPaul Moore #ifdef CONFIG_NETLABEL
5517420ed23SVenkat Yekkirala /**
55202752760SPaul Moore  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
5537420ed23SVenkat Yekkirala  * @context: the security context
55402752760SPaul Moore  * @secattr: the NetLabel security attributes
5557420ed23SVenkat Yekkirala  *
5567420ed23SVenkat Yekkirala  * Description:
55702752760SPaul Moore  * Given the security context copy the low MLS sensitivity level into the
55802752760SPaul Moore  * NetLabel MLS sensitivity level field.
5597420ed23SVenkat Yekkirala  *
5607420ed23SVenkat Yekkirala  */
56102752760SPaul Moore void mls_export_netlbl_lvl(struct context *context,
56202752760SPaul Moore 			   struct netlbl_lsm_secattr *secattr)
5637420ed23SVenkat Yekkirala {
5647420ed23SVenkat Yekkirala 	if (!selinux_mls_enabled)
5657420ed23SVenkat Yekkirala 		return;
5667420ed23SVenkat Yekkirala 
56716efd454SPaul Moore 	secattr->attr.mls.lvl = context->range.level[0].sens - 1;
56802752760SPaul Moore 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
5697420ed23SVenkat Yekkirala }
5707420ed23SVenkat Yekkirala 
5717420ed23SVenkat Yekkirala /**
57202752760SPaul Moore  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
5737420ed23SVenkat Yekkirala  * @context: the security context
57402752760SPaul Moore  * @secattr: the NetLabel security attributes
5757420ed23SVenkat Yekkirala  *
5767420ed23SVenkat Yekkirala  * Description:
57702752760SPaul Moore  * Given the security context and the NetLabel security attributes, copy the
57802752760SPaul Moore  * NetLabel MLS sensitivity level into the context.
5797420ed23SVenkat Yekkirala  *
5807420ed23SVenkat Yekkirala  */
58102752760SPaul Moore void mls_import_netlbl_lvl(struct context *context,
58202752760SPaul Moore 			   struct netlbl_lsm_secattr *secattr)
5837420ed23SVenkat Yekkirala {
5847420ed23SVenkat Yekkirala 	if (!selinux_mls_enabled)
5857420ed23SVenkat Yekkirala 		return;
5867420ed23SVenkat Yekkirala 
58716efd454SPaul Moore 	context->range.level[0].sens = secattr->attr.mls.lvl + 1;
58802752760SPaul Moore 	context->range.level[1].sens = context->range.level[0].sens;
5897420ed23SVenkat Yekkirala }
5907420ed23SVenkat Yekkirala 
5917420ed23SVenkat Yekkirala /**
59202752760SPaul Moore  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
5937420ed23SVenkat Yekkirala  * @context: the security context
59402752760SPaul Moore  * @secattr: the NetLabel security attributes
5957420ed23SVenkat Yekkirala  *
5967420ed23SVenkat Yekkirala  * Description:
59702752760SPaul Moore  * Given the security context copy the low MLS categories into the NetLabel
59802752760SPaul Moore  * MLS category field.  Returns zero on success, negative values on failure.
5997420ed23SVenkat Yekkirala  *
6007420ed23SVenkat Yekkirala  */
60102752760SPaul Moore int mls_export_netlbl_cat(struct context *context,
60202752760SPaul Moore 			  struct netlbl_lsm_secattr *secattr)
6037420ed23SVenkat Yekkirala {
60402752760SPaul Moore 	int rc;
6057420ed23SVenkat Yekkirala 
60602752760SPaul Moore 	if (!selinux_mls_enabled)
6077420ed23SVenkat Yekkirala 		return 0;
6087420ed23SVenkat Yekkirala 
60902752760SPaul Moore 	rc = ebitmap_netlbl_export(&context->range.level[0].cat,
61016efd454SPaul Moore 				   &secattr->attr.mls.cat);
61116efd454SPaul Moore 	if (rc == 0 && secattr->attr.mls.cat != NULL)
61202752760SPaul Moore 		secattr->flags |= NETLBL_SECATTR_MLS_CAT;
61302752760SPaul Moore 
6147420ed23SVenkat Yekkirala 	return rc;
6157420ed23SVenkat Yekkirala }
6167420ed23SVenkat Yekkirala 
6177420ed23SVenkat Yekkirala /**
61802752760SPaul Moore  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
6197420ed23SVenkat Yekkirala  * @context: the security context
62002752760SPaul Moore  * @secattr: the NetLabel security attributes
6217420ed23SVenkat Yekkirala  *
6227420ed23SVenkat Yekkirala  * Description:
62302752760SPaul Moore  * Copy the NetLabel security attributes into the SELinux context; since the
62402752760SPaul Moore  * NetLabel security attribute only contains a single MLS category use it for
62502752760SPaul Moore  * both the low and high categories of the context.  Returns zero on success,
62602752760SPaul Moore  * negative values on failure.
6277420ed23SVenkat Yekkirala  *
6287420ed23SVenkat Yekkirala  */
62902752760SPaul Moore int mls_import_netlbl_cat(struct context *context,
63002752760SPaul Moore 			  struct netlbl_lsm_secattr *secattr)
6317420ed23SVenkat Yekkirala {
63202752760SPaul Moore 	int rc;
6337420ed23SVenkat Yekkirala 
6347420ed23SVenkat Yekkirala 	if (!selinux_mls_enabled)
6357420ed23SVenkat Yekkirala 		return 0;
6367420ed23SVenkat Yekkirala 
63702752760SPaul Moore 	rc = ebitmap_netlbl_import(&context->range.level[0].cat,
63816efd454SPaul Moore 				   secattr->attr.mls.cat);
6397420ed23SVenkat Yekkirala 	if (rc != 0)
64002752760SPaul Moore 		goto import_netlbl_cat_failure;
64102752760SPaul Moore 
6427420ed23SVenkat Yekkirala 	rc = ebitmap_cpy(&context->range.level[1].cat,
6437420ed23SVenkat Yekkirala 			 &context->range.level[0].cat);
6447420ed23SVenkat Yekkirala 	if (rc != 0)
64502752760SPaul Moore 		goto import_netlbl_cat_failure;
6467420ed23SVenkat Yekkirala 
6477420ed23SVenkat Yekkirala 	return 0;
6487420ed23SVenkat Yekkirala 
64902752760SPaul Moore import_netlbl_cat_failure:
6507420ed23SVenkat Yekkirala 	ebitmap_destroy(&context->range.level[0].cat);
6517420ed23SVenkat Yekkirala 	ebitmap_destroy(&context->range.level[1].cat);
6527420ed23SVenkat Yekkirala 	return rc;
6537420ed23SVenkat Yekkirala }
65402752760SPaul Moore #endif /* CONFIG_NETLABEL */
655