xref: /linux/security/selinux/ss/mls.c (revision 4afec360)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Implementation of the multi-level security (MLS) policy.
41da177e4SLinus Torvalds  *
50fe53224SStephen Smalley  * Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
61da177e4SLinus Torvalds  */
7*4afec360SPaul Moore 
81da177e4SLinus Torvalds /*
91da177e4SLinus Torvalds  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
101da177e4SLinus Torvalds  *          Support for enhanced MLS infrastructure.
11376bd9cbSDarrel Goeddel  *          Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12*4afec360SPaul Moore  *
1382c21bfaSPaul Moore  * Updated: Hewlett-Packard <paul@paul-moore.com>
1402752760SPaul Moore  *          Added support to import/export the MLS label from NetLabel
15*4afec360SPaul Moore  *          Copyright (C) Hewlett-Packard Development Company, L.P., 2006
167420ed23SVenkat Yekkirala  */
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <linux/kernel.h>
191da177e4SLinus Torvalds #include <linux/slab.h>
201da177e4SLinus Torvalds #include <linux/string.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
2202752760SPaul Moore #include <net/netlabel.h>
23f5c1d5b2SJames Morris #include "sidtab.h"
241da177e4SLinus Torvalds #include "mls.h"
251da177e4SLinus Torvalds #include "policydb.h"
261da177e4SLinus Torvalds #include "services.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds /*
291da177e4SLinus Torvalds  * Return the length in bytes for the MLS fields of the
301da177e4SLinus Torvalds  * security context string representation of `context'.
311da177e4SLinus Torvalds  */
mls_compute_context_len(struct policydb * p,struct context * context)32aa8e712cSStephen Smalley int mls_compute_context_len(struct policydb *p, struct context *context)
331da177e4SLinus Torvalds {
349fe79ad1SKaiGai Kohei 	int i, l, len, head, prev;
359fe79ad1SKaiGai Kohei 	char *nm;
369fe79ad1SKaiGai Kohei 	struct ebitmap *e;
37782ebb99SStephen Smalley 	struct ebitmap_node *node;
381da177e4SLinus Torvalds 
39aa8e712cSStephen Smalley 	if (!p->mls_enabled)
401da177e4SLinus Torvalds 		return 0;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	len = 1; /* for the beginning ":" */
431da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
44fd5a90ffSChristian Göttsche 		u32 index_sens = context->range.level[l].sens;
45aa8e712cSStephen Smalley 		len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
461da177e4SLinus Torvalds 
479fe79ad1SKaiGai Kohei 		/* categories */
489fe79ad1SKaiGai Kohei 		head = -2;
499fe79ad1SKaiGai Kohei 		prev = -2;
509fe79ad1SKaiGai Kohei 		e = &context->range.level[l].cat;
51*4afec360SPaul Moore 		ebitmap_for_each_positive_bit(e, node, i)
52*4afec360SPaul Moore 		{
539fe79ad1SKaiGai Kohei 			if (i - prev > 1) {
549fe79ad1SKaiGai Kohei 				/* one or more negative bits are skipped */
559fe79ad1SKaiGai Kohei 				if (head != prev) {
56aa8e712cSStephen Smalley 					nm = sym_name(p, SYM_CATS, prev);
579fe79ad1SKaiGai Kohei 					len += strlen(nm) + 1;
581da177e4SLinus Torvalds 				}
59aa8e712cSStephen Smalley 				nm = sym_name(p, SYM_CATS, i);
609fe79ad1SKaiGai Kohei 				len += strlen(nm) + 1;
619fe79ad1SKaiGai Kohei 				head = i;
621da177e4SLinus Torvalds 			}
639fe79ad1SKaiGai Kohei 			prev = i;
641da177e4SLinus Torvalds 		}
659fe79ad1SKaiGai Kohei 		if (prev != head) {
66aa8e712cSStephen Smalley 			nm = sym_name(p, SYM_CATS, prev);
679fe79ad1SKaiGai Kohei 			len += strlen(nm) + 1;
689fe79ad1SKaiGai Kohei 		}
691da177e4SLinus Torvalds 		if (l == 0) {
701da177e4SLinus Torvalds 			if (mls_level_eq(&context->range.level[0],
711da177e4SLinus Torvalds 					 &context->range.level[1]))
721da177e4SLinus Torvalds 				break;
731da177e4SLinus Torvalds 			else
741da177e4SLinus Torvalds 				len++;
751da177e4SLinus Torvalds 		}
761da177e4SLinus Torvalds 	}
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds 	return len;
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds /*
821da177e4SLinus Torvalds  * Write the security context string representation of
831da177e4SLinus Torvalds  * the MLS fields of `context' into the string `*scontext'.
841da177e4SLinus Torvalds  * Update `*scontext' to point to the end of the MLS fields.
851da177e4SLinus Torvalds  */
mls_sid_to_context(struct policydb * p,struct context * context,char ** scontext)86*4afec360SPaul Moore void mls_sid_to_context(struct policydb *p, struct context *context,
871da177e4SLinus Torvalds 			char **scontext)
881da177e4SLinus Torvalds {
899fe79ad1SKaiGai Kohei 	char *scontextp, *nm;
909fe79ad1SKaiGai Kohei 	int i, l, head, prev;
919fe79ad1SKaiGai Kohei 	struct ebitmap *e;
92782ebb99SStephen Smalley 	struct ebitmap_node *node;
931da177e4SLinus Torvalds 
94aa8e712cSStephen Smalley 	if (!p->mls_enabled)
951da177e4SLinus Torvalds 		return;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	scontextp = *scontext;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	*scontextp = ':';
1001da177e4SLinus Torvalds 	scontextp++;
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
103aa8e712cSStephen Smalley 		strcpy(scontextp, sym_name(p, SYM_LEVELS,
104ac76c05bSEric Paris 					   context->range.level[l].sens - 1));
1059fe79ad1SKaiGai Kohei 		scontextp += strlen(scontextp);
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 		/* categories */
1089fe79ad1SKaiGai Kohei 		head = -2;
1099fe79ad1SKaiGai Kohei 		prev = -2;
1109fe79ad1SKaiGai Kohei 		e = &context->range.level[l].cat;
111*4afec360SPaul Moore 		ebitmap_for_each_positive_bit(e, node, i)
112*4afec360SPaul Moore 		{
1139fe79ad1SKaiGai Kohei 			if (i - prev > 1) {
1149fe79ad1SKaiGai Kohei 				/* one or more negative bits are skipped */
1159fe79ad1SKaiGai Kohei 				if (prev != head) {
1169fe79ad1SKaiGai Kohei 					if (prev - head > 1)
1179fe79ad1SKaiGai Kohei 						*scontextp++ = '.';
1189fe79ad1SKaiGai Kohei 					else
1199fe79ad1SKaiGai Kohei 						*scontextp++ = ',';
120aa8e712cSStephen Smalley 					nm = sym_name(p, SYM_CATS, prev);
1219fe79ad1SKaiGai Kohei 					strcpy(scontextp, nm);
1229fe79ad1SKaiGai Kohei 					scontextp += strlen(nm);
1231da177e4SLinus Torvalds 				}
1249fe79ad1SKaiGai Kohei 				if (prev < 0)
1251da177e4SLinus Torvalds 					*scontextp++ = ':';
1269fe79ad1SKaiGai Kohei 				else
1271da177e4SLinus Torvalds 					*scontextp++ = ',';
128aa8e712cSStephen Smalley 				nm = sym_name(p, SYM_CATS, i);
1299fe79ad1SKaiGai Kohei 				strcpy(scontextp, nm);
1309fe79ad1SKaiGai Kohei 				scontextp += strlen(nm);
1319fe79ad1SKaiGai Kohei 				head = i;
1329fe79ad1SKaiGai Kohei 			}
1339fe79ad1SKaiGai Kohei 			prev = i;
1349fe79ad1SKaiGai Kohei 		}
1359fe79ad1SKaiGai Kohei 
1369fe79ad1SKaiGai Kohei 		if (prev != head) {
1379fe79ad1SKaiGai Kohei 			if (prev - head > 1)
1381da177e4SLinus Torvalds 				*scontextp++ = '.';
1391da177e4SLinus Torvalds 			else
1401da177e4SLinus Torvalds 				*scontextp++ = ',';
141aa8e712cSStephen Smalley 			nm = sym_name(p, SYM_CATS, prev);
1429fe79ad1SKaiGai Kohei 			strcpy(scontextp, nm);
1439fe79ad1SKaiGai Kohei 			scontextp += strlen(nm);
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;
1509fe79ad1SKaiGai Kohei 			else
1519fe79ad1SKaiGai Kohei 				*scontextp++ = '-';
1521da177e4SLinus Torvalds 		}
1531da177e4SLinus Torvalds 	}
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 	*scontext = scontextp;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
mls_level_isvalid(struct policydb * p,struct mls_level * l)15845e5421eSStephen Smalley int mls_level_isvalid(struct policydb *p, struct mls_level *l)
15945e5421eSStephen Smalley {
16045e5421eSStephen Smalley 	struct level_datum *levdatum;
16145e5421eSStephen Smalley 
16245e5421eSStephen Smalley 	if (!l->sens || l->sens > p->p_levels.nprim)
16345e5421eSStephen Smalley 		return 0;
164237389e3SOndrej Mosnacek 	levdatum = symtab_search(&p->p_levels,
165ac76c05bSEric Paris 				 sym_name(p, SYM_LEVELS, l->sens - 1));
16645e5421eSStephen Smalley 	if (!levdatum)
16745e5421eSStephen Smalley 		return 0;
16845e5421eSStephen Smalley 
16945e5421eSStephen Smalley 	/*
170fee71142SWaiman Long 	 * Return 1 iff all the bits set in l->cat are also be set in
171fee71142SWaiman Long 	 * levdatum->level->cat and no bit in l->cat is larger than
172fee71142SWaiman Long 	 * p->p_cats.nprim.
17345e5421eSStephen Smalley 	 */
174fee71142SWaiman Long 	return ebitmap_contains(&levdatum->level->cat, &l->cat,
175fee71142SWaiman Long 				p->p_cats.nprim);
17645e5421eSStephen Smalley }
17745e5421eSStephen Smalley 
mls_range_isvalid(struct policydb * p,struct mls_range * r)17845e5421eSStephen Smalley int mls_range_isvalid(struct policydb *p, struct mls_range *r)
17945e5421eSStephen Smalley {
18045e5421eSStephen Smalley 	return (mls_level_isvalid(p, &r->level[0]) &&
18145e5421eSStephen Smalley 		mls_level_isvalid(p, &r->level[1]) &&
18245e5421eSStephen Smalley 		mls_level_dom(&r->level[1], &r->level[0]));
18345e5421eSStephen Smalley }
18445e5421eSStephen Smalley 
1851da177e4SLinus Torvalds /*
1861da177e4SLinus Torvalds  * Return 1 if the MLS fields in the security context
1871da177e4SLinus Torvalds  * structure `c' are valid.  Return 0 otherwise.
1881da177e4SLinus Torvalds  */
mls_context_isvalid(struct policydb * p,struct context * c)1891da177e4SLinus Torvalds int mls_context_isvalid(struct policydb *p, struct context *c)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	struct user_datum *usrdatum;
1921da177e4SLinus Torvalds 
1930719aaf5SGuido Trentalancia 	if (!p->mls_enabled)
1941da177e4SLinus Torvalds 		return 1;
1951da177e4SLinus Torvalds 
19645e5421eSStephen Smalley 	if (!mls_range_isvalid(p, &c->range))
1971da177e4SLinus Torvalds 		return 0;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	if (c->role == OBJECT_R_VAL)
2001da177e4SLinus Torvalds 		return 1;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	/*
2031da177e4SLinus Torvalds 	 * User must be authorized for the MLS range.
2041da177e4SLinus Torvalds 	 */
2051da177e4SLinus Torvalds 	if (!c->user || c->user > p->p_users.nprim)
2061da177e4SLinus Torvalds 		return 0;
2071da177e4SLinus Torvalds 	usrdatum = p->user_val_to_struct[c->user - 1];
2081da177e4SLinus Torvalds 	if (!mls_range_contains(usrdatum->range, c->range))
2091da177e4SLinus Torvalds 		return 0; /* user may not be associated with range */
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	return 1;
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds /*
2151da177e4SLinus Torvalds  * Set the MLS fields in the security context structure
2161da177e4SLinus Torvalds  * `context' based on the string representation in
21795ffe194SJann Horn  * the string `scontext'.
2181da177e4SLinus Torvalds  *
2191da177e4SLinus Torvalds  * This function modifies the string in place, inserting
2201da177e4SLinus Torvalds  * NULL characters to terminate the MLS fields.
221f5c1d5b2SJames Morris  *
222f5c1d5b2SJames Morris  * If a def_sid is provided and no MLS field is present,
223f5c1d5b2SJames Morris  * copy the MLS field of the associated default context.
224f5c1d5b2SJames Morris  * Used for upgraded to MLS systems where objects may lack
225f5c1d5b2SJames Morris  * MLS fields.
226f5c1d5b2SJames Morris  *
227f5c1d5b2SJames Morris  * Policy read-lock must be held for sidtab lookup.
228f5c1d5b2SJames Morris  *
2291da177e4SLinus Torvalds  */
mls_context_to_sid(struct policydb * pol,char oldc,char * scontext,struct context * context,struct sidtab * s,u32 def_sid)230*4afec360SPaul Moore int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext,
231*4afec360SPaul Moore 		       struct context *context, struct sidtab *s, u32 def_sid)
2321da177e4SLinus Torvalds {
23395ffe194SJann Horn 	char *sensitivity, *cur_cat, *next_cat, *rngptr;
2341da177e4SLinus Torvalds 	struct level_datum *levdatum;
2351da177e4SLinus Torvalds 	struct cat_datum *catdatum, *rngdatum;
236fd5a90ffSChristian Göttsche 	u32 i;
237fd5a90ffSChristian Göttsche 	int l, rc;
23895ffe194SJann Horn 	char *rangep[2];
2391da177e4SLinus Torvalds 
2400719aaf5SGuido Trentalancia 	if (!pol->mls_enabled) {
241877181a8SPaul Moore 		/*
242877181a8SPaul Moore 		 * With no MLS, only return -EINVAL if there is a MLS field
243877181a8SPaul Moore 		 * and it did not come from an xattr.
244877181a8SPaul Moore 		 */
245877181a8SPaul Moore 		if (oldc && def_sid == SECSID_NULL)
24695ffe194SJann Horn 			return -EINVAL;
247877181a8SPaul Moore 		return 0;
248e517a0cdSStephen Smalley 	}
2491da177e4SLinus Torvalds 
250f5c1d5b2SJames Morris 	/*
251f5c1d5b2SJames Morris 	 * No MLS component to the security context, try and map to
252f5c1d5b2SJames Morris 	 * default if provided.
253f5c1d5b2SJames Morris 	 */
254f5c1d5b2SJames Morris 	if (!oldc) {
255f5c1d5b2SJames Morris 		struct context *defcon;
256f5c1d5b2SJames Morris 
257f5c1d5b2SJames Morris 		if (def_sid == SECSID_NULL)
25895ffe194SJann Horn 			return -EINVAL;
2591da177e4SLinus Torvalds 
260f5c1d5b2SJames Morris 		defcon = sidtab_search(s, def_sid);
261f5c1d5b2SJames Morris 		if (!defcon)
26295ffe194SJann Horn 			return -EINVAL;
263f5c1d5b2SJames Morris 
26495ffe194SJann Horn 		return mls_context_cpy(context, defcon);
265f5c1d5b2SJames Morris 	}
266f5c1d5b2SJames Morris 
26795ffe194SJann Horn 	/*
26895ffe194SJann Horn 	 * If we're dealing with a range, figure out where the two parts
26995ffe194SJann Horn 	 * of the range begin.
27095ffe194SJann Horn 	 */
27195ffe194SJann Horn 	rangep[0] = scontext;
27295ffe194SJann Horn 	rangep[1] = strchr(scontext, '-');
27395ffe194SJann Horn 	if (rangep[1]) {
27495ffe194SJann Horn 		rangep[1][0] = '\0';
27595ffe194SJann Horn 		rangep[1]++;
27695ffe194SJann Horn 	}
2771da177e4SLinus Torvalds 
27895ffe194SJann Horn 	/* For each part of the range: */
2791da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
28095ffe194SJann Horn 		/* Split sensitivity and category set. */
28195ffe194SJann Horn 		sensitivity = rangep[l];
28295ffe194SJann Horn 		if (sensitivity == NULL)
28395ffe194SJann Horn 			break;
28495ffe194SJann Horn 		next_cat = strchr(sensitivity, ':');
28595ffe194SJann Horn 		if (next_cat)
28695ffe194SJann Horn 			*(next_cat++) = '\0';
2871da177e4SLinus Torvalds 
28895ffe194SJann Horn 		/* Parse sensitivity. */
289237389e3SOndrej Mosnacek 		levdatum = symtab_search(&pol->p_levels, sensitivity);
29095ffe194SJann Horn 		if (!levdatum)
29195ffe194SJann Horn 			return -EINVAL;
2921da177e4SLinus Torvalds 		context->range.level[l].sens = levdatum->level->sens;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 		/* Extract category set. */
29595ffe194SJann Horn 		while (next_cat != NULL) {
29695ffe194SJann Horn 			cur_cat = next_cat;
29795ffe194SJann Horn 			next_cat = strchr(next_cat, ',');
29895ffe194SJann Horn 			if (next_cat != NULL)
29995ffe194SJann Horn 				*(next_cat++) = '\0';
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 			/* Separate into range if exists */
30295ffe194SJann Horn 			rngptr = strchr(cur_cat, '.');
3031a5e6f87SEric Paris 			if (rngptr != NULL) {
3041da177e4SLinus Torvalds 				/* Remove '.' */
305df4ea865SVesa-Matti J Kari 				*rngptr++ = '\0';
3061da177e4SLinus Torvalds 			}
3071da177e4SLinus Torvalds 
308237389e3SOndrej Mosnacek 			catdatum = symtab_search(&pol->p_cats, cur_cat);
30995ffe194SJann Horn 			if (!catdatum)
31095ffe194SJann Horn 				return -EINVAL;
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 			rc = ebitmap_set_bit(&context->range.level[l].cat,
3131da177e4SLinus Torvalds 					     catdatum->value - 1, 1);
3141da177e4SLinus Torvalds 			if (rc)
31595ffe194SJann Horn 				return rc;
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 			/* If range, set all categories in range */
31895ffe194SJann Horn 			if (rngptr == NULL)
31995ffe194SJann Horn 				continue;
3201da177e4SLinus Torvalds 
321237389e3SOndrej Mosnacek 			rngdatum = symtab_search(&pol->p_cats, rngptr);
32295ffe194SJann Horn 			if (!rngdatum)
32395ffe194SJann Horn 				return -EINVAL;
3241da177e4SLinus Torvalds 
32595ffe194SJann Horn 			if (catdatum->value >= rngdatum->value)
32695ffe194SJann Horn 				return -EINVAL;
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 			for (i = catdatum->value; i < rngdatum->value; i++) {
329*4afec360SPaul Moore 				rc = ebitmap_set_bit(
330*4afec360SPaul Moore 					&context->range.level[l].cat, i, 1);
3311da177e4SLinus Torvalds 				if (rc)
33295ffe194SJann Horn 					return rc;
33395ffe194SJann Horn 			}
3341da177e4SLinus Torvalds 		}
3351da177e4SLinus Torvalds 	}
3361da177e4SLinus Torvalds 
33795ffe194SJann Horn 	/* If we didn't see a '-', the range start is also the range end. */
33895ffe194SJann Horn 	if (rangep[1] == NULL) {
3391da177e4SLinus Torvalds 		context->range.level[1].sens = context->range.level[0].sens;
3401da177e4SLinus Torvalds 		rc = ebitmap_cpy(&context->range.level[1].cat,
3411da177e4SLinus Torvalds 				 &context->range.level[0].cat);
3421da177e4SLinus Torvalds 		if (rc)
3431da177e4SLinus Torvalds 			return rc;
3441da177e4SLinus Torvalds 	}
3451da177e4SLinus Torvalds 
34695ffe194SJann Horn 	return 0;
34795ffe194SJann Horn }
34895ffe194SJann Horn 
3491da177e4SLinus Torvalds /*
350376bd9cbSDarrel Goeddel  * Set the MLS fields in the security context structure
351376bd9cbSDarrel Goeddel  * `context' based on the string representation in
352376bd9cbSDarrel Goeddel  * the string `str'.  This function will allocate temporary memory with the
353376bd9cbSDarrel Goeddel  * given constraints of gfp_mask.
354376bd9cbSDarrel Goeddel  */
mls_from_string(struct policydb * p,char * str,struct context * context,gfp_t gfp_mask)355aa8e712cSStephen Smalley int mls_from_string(struct policydb *p, char *str, struct context *context,
356aa8e712cSStephen Smalley 		    gfp_t gfp_mask)
357376bd9cbSDarrel Goeddel {
35895ffe194SJann Horn 	char *tmpstr;
359376bd9cbSDarrel Goeddel 	int rc;
360376bd9cbSDarrel Goeddel 
361aa8e712cSStephen Smalley 	if (!p->mls_enabled)
362376bd9cbSDarrel Goeddel 		return -EINVAL;
363376bd9cbSDarrel Goeddel 
36495ffe194SJann Horn 	tmpstr = kstrdup(str, gfp_mask);
365376bd9cbSDarrel Goeddel 	if (!tmpstr) {
366376bd9cbSDarrel Goeddel 		rc = -ENOMEM;
367376bd9cbSDarrel Goeddel 	} else {
368*4afec360SPaul Moore 		rc = mls_context_to_sid(p, ':', tmpstr, context, NULL,
369*4afec360SPaul Moore 					SECSID_NULL);
37095ffe194SJann Horn 		kfree(tmpstr);
371376bd9cbSDarrel Goeddel 	}
372376bd9cbSDarrel Goeddel 
373376bd9cbSDarrel Goeddel 	return rc;
374376bd9cbSDarrel Goeddel }
375376bd9cbSDarrel Goeddel 
376376bd9cbSDarrel Goeddel /*
3771da177e4SLinus Torvalds  * Copies the MLS range `range' into `context'.
3781da177e4SLinus Torvalds  */
mls_range_set(struct context * context,struct mls_range * range)379*4afec360SPaul Moore int mls_range_set(struct context *context, struct mls_range *range)
3801da177e4SLinus Torvalds {
3811da177e4SLinus Torvalds 	int l, rc = 0;
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	/* Copy the MLS range into the  context */
3841da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
3851da177e4SLinus Torvalds 		context->range.level[l].sens = range->level[l].sens;
3861da177e4SLinus Torvalds 		rc = ebitmap_cpy(&context->range.level[l].cat,
3871da177e4SLinus Torvalds 				 &range->level[l].cat);
3881da177e4SLinus Torvalds 		if (rc)
3891da177e4SLinus Torvalds 			break;
3901da177e4SLinus Torvalds 	}
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	return rc;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds 
mls_setup_user_range(struct policydb * p,struct context * fromcon,struct user_datum * user,struct context * usercon)395*4afec360SPaul Moore int mls_setup_user_range(struct policydb *p, struct context *fromcon,
396*4afec360SPaul Moore 			 struct user_datum *user, struct context *usercon)
3971da177e4SLinus Torvalds {
398aa8e712cSStephen Smalley 	if (p->mls_enabled) {
3991da177e4SLinus Torvalds 		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
4001da177e4SLinus Torvalds 		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
4011da177e4SLinus Torvalds 		struct mls_level *user_low = &(user->range.level[0]);
4021da177e4SLinus Torvalds 		struct mls_level *user_clr = &(user->range.level[1]);
4031da177e4SLinus Torvalds 		struct mls_level *user_def = &(user->dfltlevel);
4041da177e4SLinus Torvalds 		struct mls_level *usercon_sen = &(usercon->range.level[0]);
4051da177e4SLinus Torvalds 		struct mls_level *usercon_clr = &(usercon->range.level[1]);
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 		/* Honor the user's default level if we can */
408f5269710SEric Paris 		if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
4091da177e4SLinus Torvalds 			*usercon_sen = *user_def;
410f5269710SEric Paris 		else if (mls_level_between(fromcon_sen, user_def, user_clr))
4111da177e4SLinus Torvalds 			*usercon_sen = *fromcon_sen;
412f5269710SEric Paris 		else if (mls_level_between(fromcon_clr, user_low, user_def))
4131da177e4SLinus Torvalds 			*usercon_sen = *user_low;
414f5269710SEric Paris 		else
4151da177e4SLinus Torvalds 			return -EINVAL;
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 		/* Lower the clearance of available contexts
4181da177e4SLinus Torvalds 		   if the clearance of "fromcon" is lower than
4191da177e4SLinus Torvalds 		   that of the user's default clearance (but
4201da177e4SLinus Torvalds 		   only if the "fromcon" clearance dominates
4211da177e4SLinus Torvalds 		   the user's computed sensitivity level) */
4221a5e6f87SEric Paris 		if (mls_level_dom(user_clr, fromcon_clr))
4231da177e4SLinus Torvalds 			*usercon_clr = *fromcon_clr;
4241a5e6f87SEric Paris 		else if (mls_level_dom(fromcon_clr, user_clr))
4251da177e4SLinus Torvalds 			*usercon_clr = *user_clr;
4261a5e6f87SEric Paris 		else
4271da177e4SLinus Torvalds 			return -EINVAL;
4281da177e4SLinus Torvalds 	}
4291da177e4SLinus Torvalds 
4301da177e4SLinus Torvalds 	return 0;
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds 
4331da177e4SLinus Torvalds /*
4341da177e4SLinus Torvalds  * Convert the MLS fields in the security context
435ee1a84fdSOndrej Mosnacek  * structure `oldc' from the values specified in the
436ee1a84fdSOndrej Mosnacek  * policy `oldp' to the values specified in the policy `newp',
437ee1a84fdSOndrej Mosnacek  * storing the resulting context in `newc'.
4381da177e4SLinus Torvalds  */
mls_convert_context(struct policydb * oldp,struct policydb * newp,struct context * oldc,struct context * newc)439*4afec360SPaul Moore int mls_convert_context(struct policydb *oldp, struct policydb *newp,
440*4afec360SPaul Moore 			struct context *oldc, struct context *newc)
4411da177e4SLinus Torvalds {
4421da177e4SLinus Torvalds 	struct level_datum *levdatum;
4431da177e4SLinus Torvalds 	struct cat_datum *catdatum;
444782ebb99SStephen Smalley 	struct ebitmap_node *node;
445fd5a90ffSChristian Göttsche 	u32 i;
446fd5a90ffSChristian Göttsche 	int l;
4471da177e4SLinus Torvalds 
448aa8e712cSStephen Smalley 	if (!oldp->mls_enabled || !newp->mls_enabled)
4491da177e4SLinus Torvalds 		return 0;
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	for (l = 0; l < 2; l++) {
452237389e3SOndrej Mosnacek 		char *name = sym_name(oldp, SYM_LEVELS,
453237389e3SOndrej Mosnacek 				      oldc->range.level[l].sens - 1);
454237389e3SOndrej Mosnacek 
455237389e3SOndrej Mosnacek 		levdatum = symtab_search(&newp->p_levels, name);
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 		if (!levdatum)
4581da177e4SLinus Torvalds 			return -EINVAL;
459ee1a84fdSOndrej Mosnacek 		newc->range.level[l].sens = levdatum->level->sens;
4601da177e4SLinus Torvalds 
461*4afec360SPaul Moore 		ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node,
462*4afec360SPaul Moore 					      i)
463*4afec360SPaul Moore 		{
4641da177e4SLinus Torvalds 			int rc;
4651da177e4SLinus Torvalds 
466237389e3SOndrej Mosnacek 			catdatum = symtab_search(&newp->p_cats,
467ac76c05bSEric Paris 						 sym_name(oldp, SYM_CATS, i));
4681da177e4SLinus Torvalds 			if (!catdatum)
4691da177e4SLinus Torvalds 				return -EINVAL;
470ee1a84fdSOndrej Mosnacek 			rc = ebitmap_set_bit(&newc->range.level[l].cat,
471ee1a84fdSOndrej Mosnacek 					     catdatum->value - 1, 1);
4721da177e4SLinus Torvalds 			if (rc)
4731da177e4SLinus Torvalds 				return rc;
4741da177e4SLinus Torvalds 		}
4751da177e4SLinus Torvalds 	}
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	return 0;
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds 
mls_compute_sid(struct policydb * p,struct context * scontext,struct context * tcontext,u16 tclass,u32 specified,struct context * newcontext,bool sock)480*4afec360SPaul Moore int mls_compute_sid(struct policydb *p, struct context *scontext,
481*4afec360SPaul Moore 		    struct context *tcontext, u16 tclass, u32 specified,
482*4afec360SPaul Moore 		    struct context *newcontext, bool sock)
4831da177e4SLinus Torvalds {
4842f3e82d6SStephen Smalley 	struct range_trans rtr;
4852f3e82d6SStephen Smalley 	struct mls_range *r;
486aa893269SEric Paris 	struct class_datum *cladatum;
487fd5a90ffSChristian Göttsche 	char default_range = 0;
488f3f87714SDarrel Goeddel 
489aa8e712cSStephen Smalley 	if (!p->mls_enabled)
4901da177e4SLinus Torvalds 		return 0;
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	switch (specified) {
4931da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
4941da177e4SLinus Torvalds 		/* Look for a range transition rule. */
4952f3e82d6SStephen Smalley 		rtr.source_type = scontext->type;
4962f3e82d6SStephen Smalley 		rtr.target_type = tcontext->type;
4972f3e82d6SStephen Smalley 		rtr.target_class = tclass;
49824def7bbSOndrej Mosnacek 		r = policydb_rangetr_search(p, &rtr);
4992f3e82d6SStephen Smalley 		if (r)
5002f3e82d6SStephen Smalley 			return mls_range_set(newcontext, r);
501aa893269SEric Paris 
502aa8e712cSStephen Smalley 		if (tclass && tclass <= p->p_classes.nprim) {
503aa8e712cSStephen Smalley 			cladatum = p->class_val_to_struct[tclass - 1];
504aa893269SEric Paris 			if (cladatum)
505aa893269SEric Paris 				default_range = cladatum->default_range;
506aa893269SEric Paris 		}
507aa893269SEric Paris 
508aa893269SEric Paris 		switch (default_range) {
509aa893269SEric Paris 		case DEFAULT_SOURCE_LOW:
510aa893269SEric Paris 			return mls_context_cpy_low(newcontext, scontext);
511aa893269SEric Paris 		case DEFAULT_SOURCE_HIGH:
512aa893269SEric Paris 			return mls_context_cpy_high(newcontext, scontext);
513aa893269SEric Paris 		case DEFAULT_SOURCE_LOW_HIGH:
514aa893269SEric Paris 			return mls_context_cpy(newcontext, scontext);
515aa893269SEric Paris 		case DEFAULT_TARGET_LOW:
516aa893269SEric Paris 			return mls_context_cpy_low(newcontext, tcontext);
517aa893269SEric Paris 		case DEFAULT_TARGET_HIGH:
518aa893269SEric Paris 			return mls_context_cpy_high(newcontext, tcontext);
519aa893269SEric Paris 		case DEFAULT_TARGET_LOW_HIGH:
520aa893269SEric Paris 			return mls_context_cpy(newcontext, tcontext);
52142345b68SJoshua Brindle 		case DEFAULT_GLBLUB:
522*4afec360SPaul Moore 			return mls_context_glblub(newcontext, scontext,
523*4afec360SPaul Moore 						  tcontext);
524aa893269SEric Paris 		}
525aa893269SEric Paris 
526df561f66SGustavo A. R. Silva 		fallthrough;
5271da177e4SLinus Torvalds 	case AVTAB_CHANGE:
5284b850396SZou Wei 		if ((tclass == p->process_class) || sock)
5291da177e4SLinus Torvalds 			/* Use the process MLS attributes. */
5300efc61eaSVenkat Yekkirala 			return mls_context_cpy(newcontext, scontext);
5311da177e4SLinus Torvalds 		else
5321da177e4SLinus Torvalds 			/* Use the process effective MLS attributes. */
5330efc61eaSVenkat Yekkirala 			return mls_context_cpy_low(newcontext, scontext);
5341da177e4SLinus Torvalds 	case AVTAB_MEMBER:
5351da177e4SLinus Torvalds 		/* Use the process effective MLS attributes. */
5360efc61eaSVenkat Yekkirala 		return mls_context_cpy_low(newcontext, scontext);
5371da177e4SLinus Torvalds 	}
5381da177e4SLinus Torvalds 	return -EINVAL;
5391da177e4SLinus Torvalds }
5401da177e4SLinus Torvalds 
54102752760SPaul Moore #ifdef CONFIG_NETLABEL
5427420ed23SVenkat Yekkirala /**
54302752760SPaul Moore  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
544e9fd7292SPaul Moore  * @p: the policy
5457420ed23SVenkat Yekkirala  * @context: the security context
54602752760SPaul Moore  * @secattr: the NetLabel security attributes
5477420ed23SVenkat Yekkirala  *
5487420ed23SVenkat Yekkirala  * Description:
54902752760SPaul Moore  * Given the security context copy the low MLS sensitivity level into the
55002752760SPaul Moore  * NetLabel MLS sensitivity level field.
5517420ed23SVenkat Yekkirala  *
5527420ed23SVenkat Yekkirala  */
mls_export_netlbl_lvl(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)553*4afec360SPaul Moore void mls_export_netlbl_lvl(struct policydb *p, struct context *context,
55402752760SPaul Moore 			   struct netlbl_lsm_secattr *secattr)
5557420ed23SVenkat Yekkirala {
556aa8e712cSStephen Smalley 	if (!p->mls_enabled)
5577420ed23SVenkat Yekkirala 		return;
5587420ed23SVenkat Yekkirala 
55916efd454SPaul Moore 	secattr->attr.mls.lvl = context->range.level[0].sens - 1;
56002752760SPaul Moore 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
5617420ed23SVenkat Yekkirala }
5627420ed23SVenkat Yekkirala 
5637420ed23SVenkat Yekkirala /**
56402752760SPaul Moore  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
565e9fd7292SPaul Moore  * @p: the policy
5667420ed23SVenkat Yekkirala  * @context: the security context
56702752760SPaul Moore  * @secattr: the NetLabel security attributes
5687420ed23SVenkat Yekkirala  *
5697420ed23SVenkat Yekkirala  * Description:
57002752760SPaul Moore  * Given the security context and the NetLabel security attributes, copy the
57102752760SPaul Moore  * NetLabel MLS sensitivity level into the context.
5727420ed23SVenkat Yekkirala  *
5737420ed23SVenkat Yekkirala  */
mls_import_netlbl_lvl(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)574*4afec360SPaul Moore void mls_import_netlbl_lvl(struct policydb *p, struct context *context,
57502752760SPaul Moore 			   struct netlbl_lsm_secattr *secattr)
5767420ed23SVenkat Yekkirala {
577aa8e712cSStephen Smalley 	if (!p->mls_enabled)
5787420ed23SVenkat Yekkirala 		return;
5797420ed23SVenkat Yekkirala 
58016efd454SPaul Moore 	context->range.level[0].sens = secattr->attr.mls.lvl + 1;
58102752760SPaul Moore 	context->range.level[1].sens = context->range.level[0].sens;
5827420ed23SVenkat Yekkirala }
5837420ed23SVenkat Yekkirala 
5847420ed23SVenkat Yekkirala /**
58502752760SPaul Moore  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
586e9fd7292SPaul Moore  * @p: the policy
5877420ed23SVenkat Yekkirala  * @context: the security context
58802752760SPaul Moore  * @secattr: the NetLabel security attributes
5897420ed23SVenkat Yekkirala  *
5907420ed23SVenkat Yekkirala  * Description:
59102752760SPaul Moore  * Given the security context copy the low MLS categories into the NetLabel
59202752760SPaul Moore  * MLS category field.  Returns zero on success, negative values on failure.
5937420ed23SVenkat Yekkirala  *
5947420ed23SVenkat Yekkirala  */
mls_export_netlbl_cat(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)595*4afec360SPaul Moore int mls_export_netlbl_cat(struct policydb *p, struct context *context,
59602752760SPaul Moore 			  struct netlbl_lsm_secattr *secattr)
5977420ed23SVenkat Yekkirala {
59802752760SPaul Moore 	int rc;
5997420ed23SVenkat Yekkirala 
600aa8e712cSStephen Smalley 	if (!p->mls_enabled)
6017420ed23SVenkat Yekkirala 		return 0;
6027420ed23SVenkat Yekkirala 
60302752760SPaul Moore 	rc = ebitmap_netlbl_export(&context->range.level[0].cat,
60416efd454SPaul Moore 				   &secattr->attr.mls.cat);
60516efd454SPaul Moore 	if (rc == 0 && secattr->attr.mls.cat != NULL)
60602752760SPaul Moore 		secattr->flags |= NETLBL_SECATTR_MLS_CAT;
60702752760SPaul Moore 
6087420ed23SVenkat Yekkirala 	return rc;
6097420ed23SVenkat Yekkirala }
6107420ed23SVenkat Yekkirala 
6117420ed23SVenkat Yekkirala /**
61202752760SPaul Moore  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
613e9fd7292SPaul Moore  * @p: the policy
6147420ed23SVenkat Yekkirala  * @context: the security context
61502752760SPaul Moore  * @secattr: the NetLabel security attributes
6167420ed23SVenkat Yekkirala  *
6177420ed23SVenkat Yekkirala  * Description:
61802752760SPaul Moore  * Copy the NetLabel security attributes into the SELinux context; since the
61902752760SPaul Moore  * NetLabel security attribute only contains a single MLS category use it for
62002752760SPaul Moore  * both the low and high categories of the context.  Returns zero on success,
62102752760SPaul Moore  * negative values on failure.
6227420ed23SVenkat Yekkirala  *
6237420ed23SVenkat Yekkirala  */
mls_import_netlbl_cat(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)624*4afec360SPaul Moore int mls_import_netlbl_cat(struct policydb *p, struct context *context,
62502752760SPaul Moore 			  struct netlbl_lsm_secattr *secattr)
6267420ed23SVenkat Yekkirala {
62702752760SPaul Moore 	int rc;
6287420ed23SVenkat Yekkirala 
629aa8e712cSStephen Smalley 	if (!p->mls_enabled)
6307420ed23SVenkat Yekkirala 		return 0;
6317420ed23SVenkat Yekkirala 
63202752760SPaul Moore 	rc = ebitmap_netlbl_import(&context->range.level[0].cat,
63316efd454SPaul Moore 				   secattr->attr.mls.cat);
634da8026faSPaul Moore 	if (rc)
63502752760SPaul Moore 		goto import_netlbl_cat_failure;
636da8026faSPaul Moore 	memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
637da8026faSPaul Moore 	       sizeof(context->range.level[0].cat));
6387420ed23SVenkat Yekkirala 
6397420ed23SVenkat Yekkirala 	return 0;
6407420ed23SVenkat Yekkirala 
64102752760SPaul Moore import_netlbl_cat_failure:
6427420ed23SVenkat Yekkirala 	ebitmap_destroy(&context->range.level[0].cat);
6437420ed23SVenkat Yekkirala 	return rc;
6447420ed23SVenkat Yekkirala }
64502752760SPaul Moore #endif /* CONFIG_NETLABEL */
646