18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Implementation of the multi-level security (MLS) policy.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author : Stephen Smalley, <sds@tycho.nsa.gov>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *	Support for enhanced MLS infrastructure.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * Updated: Hewlett-Packard <paul@paul-moore.com>
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *      Added support to import/export the MLS label from NetLabel
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/kernel.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/string.h>
258c2ecf20Sopenharmony_ci#include <linux/errno.h>
268c2ecf20Sopenharmony_ci#include <net/netlabel.h>
278c2ecf20Sopenharmony_ci#include "sidtab.h"
288c2ecf20Sopenharmony_ci#include "mls.h"
298c2ecf20Sopenharmony_ci#include "policydb.h"
308c2ecf20Sopenharmony_ci#include "services.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * Return the length in bytes for the MLS fields of the
348c2ecf20Sopenharmony_ci * security context string representation of `context'.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ciint mls_compute_context_len(struct policydb *p, struct context *context)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	int i, l, len, head, prev;
398c2ecf20Sopenharmony_ci	char *nm;
408c2ecf20Sopenharmony_ci	struct ebitmap *e;
418c2ecf20Sopenharmony_ci	struct ebitmap_node *node;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
448c2ecf20Sopenharmony_ci		return 0;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	len = 1; /* for the beginning ":" */
478c2ecf20Sopenharmony_ci	for (l = 0; l < 2; l++) {
488c2ecf20Sopenharmony_ci		int index_sens = context->range.level[l].sens;
498c2ecf20Sopenharmony_ci		len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		/* categories */
528c2ecf20Sopenharmony_ci		head = -2;
538c2ecf20Sopenharmony_ci		prev = -2;
548c2ecf20Sopenharmony_ci		e = &context->range.level[l].cat;
558c2ecf20Sopenharmony_ci		ebitmap_for_each_positive_bit(e, node, i) {
568c2ecf20Sopenharmony_ci			if (i - prev > 1) {
578c2ecf20Sopenharmony_ci				/* one or more negative bits are skipped */
588c2ecf20Sopenharmony_ci				if (head != prev) {
598c2ecf20Sopenharmony_ci					nm = sym_name(p, SYM_CATS, prev);
608c2ecf20Sopenharmony_ci					len += strlen(nm) + 1;
618c2ecf20Sopenharmony_ci				}
628c2ecf20Sopenharmony_ci				nm = sym_name(p, SYM_CATS, i);
638c2ecf20Sopenharmony_ci				len += strlen(nm) + 1;
648c2ecf20Sopenharmony_ci				head = i;
658c2ecf20Sopenharmony_ci			}
668c2ecf20Sopenharmony_ci			prev = i;
678c2ecf20Sopenharmony_ci		}
688c2ecf20Sopenharmony_ci		if (prev != head) {
698c2ecf20Sopenharmony_ci			nm = sym_name(p, SYM_CATS, prev);
708c2ecf20Sopenharmony_ci			len += strlen(nm) + 1;
718c2ecf20Sopenharmony_ci		}
728c2ecf20Sopenharmony_ci		if (l == 0) {
738c2ecf20Sopenharmony_ci			if (mls_level_eq(&context->range.level[0],
748c2ecf20Sopenharmony_ci					 &context->range.level[1]))
758c2ecf20Sopenharmony_ci				break;
768c2ecf20Sopenharmony_ci			else
778c2ecf20Sopenharmony_ci				len++;
788c2ecf20Sopenharmony_ci		}
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	return len;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/*
858c2ecf20Sopenharmony_ci * Write the security context string representation of
868c2ecf20Sopenharmony_ci * the MLS fields of `context' into the string `*scontext'.
878c2ecf20Sopenharmony_ci * Update `*scontext' to point to the end of the MLS fields.
888c2ecf20Sopenharmony_ci */
898c2ecf20Sopenharmony_civoid mls_sid_to_context(struct policydb *p,
908c2ecf20Sopenharmony_ci			struct context *context,
918c2ecf20Sopenharmony_ci			char **scontext)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	char *scontextp, *nm;
948c2ecf20Sopenharmony_ci	int i, l, head, prev;
958c2ecf20Sopenharmony_ci	struct ebitmap *e;
968c2ecf20Sopenharmony_ci	struct ebitmap_node *node;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
998c2ecf20Sopenharmony_ci		return;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	scontextp = *scontext;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	*scontextp = ':';
1048c2ecf20Sopenharmony_ci	scontextp++;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	for (l = 0; l < 2; l++) {
1078c2ecf20Sopenharmony_ci		strcpy(scontextp, sym_name(p, SYM_LEVELS,
1088c2ecf20Sopenharmony_ci					   context->range.level[l].sens - 1));
1098c2ecf20Sopenharmony_ci		scontextp += strlen(scontextp);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		/* categories */
1128c2ecf20Sopenharmony_ci		head = -2;
1138c2ecf20Sopenharmony_ci		prev = -2;
1148c2ecf20Sopenharmony_ci		e = &context->range.level[l].cat;
1158c2ecf20Sopenharmony_ci		ebitmap_for_each_positive_bit(e, node, i) {
1168c2ecf20Sopenharmony_ci			if (i - prev > 1) {
1178c2ecf20Sopenharmony_ci				/* one or more negative bits are skipped */
1188c2ecf20Sopenharmony_ci				if (prev != head) {
1198c2ecf20Sopenharmony_ci					if (prev - head > 1)
1208c2ecf20Sopenharmony_ci						*scontextp++ = '.';
1218c2ecf20Sopenharmony_ci					else
1228c2ecf20Sopenharmony_ci						*scontextp++ = ',';
1238c2ecf20Sopenharmony_ci					nm = sym_name(p, SYM_CATS, prev);
1248c2ecf20Sopenharmony_ci					strcpy(scontextp, nm);
1258c2ecf20Sopenharmony_ci					scontextp += strlen(nm);
1268c2ecf20Sopenharmony_ci				}
1278c2ecf20Sopenharmony_ci				if (prev < 0)
1288c2ecf20Sopenharmony_ci					*scontextp++ = ':';
1298c2ecf20Sopenharmony_ci				else
1308c2ecf20Sopenharmony_ci					*scontextp++ = ',';
1318c2ecf20Sopenharmony_ci				nm = sym_name(p, SYM_CATS, i);
1328c2ecf20Sopenharmony_ci				strcpy(scontextp, nm);
1338c2ecf20Sopenharmony_ci				scontextp += strlen(nm);
1348c2ecf20Sopenharmony_ci				head = i;
1358c2ecf20Sopenharmony_ci			}
1368c2ecf20Sopenharmony_ci			prev = i;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		if (prev != head) {
1408c2ecf20Sopenharmony_ci			if (prev - head > 1)
1418c2ecf20Sopenharmony_ci				*scontextp++ = '.';
1428c2ecf20Sopenharmony_ci			else
1438c2ecf20Sopenharmony_ci				*scontextp++ = ',';
1448c2ecf20Sopenharmony_ci			nm = sym_name(p, SYM_CATS, prev);
1458c2ecf20Sopenharmony_ci			strcpy(scontextp, nm);
1468c2ecf20Sopenharmony_ci			scontextp += strlen(nm);
1478c2ecf20Sopenharmony_ci		}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		if (l == 0) {
1508c2ecf20Sopenharmony_ci			if (mls_level_eq(&context->range.level[0],
1518c2ecf20Sopenharmony_ci					 &context->range.level[1]))
1528c2ecf20Sopenharmony_ci				break;
1538c2ecf20Sopenharmony_ci			else
1548c2ecf20Sopenharmony_ci				*scontextp++ = '-';
1558c2ecf20Sopenharmony_ci		}
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	*scontext = scontextp;
1598c2ecf20Sopenharmony_ci	return;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciint mls_level_isvalid(struct policydb *p, struct mls_level *l)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct level_datum *levdatum;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (!l->sens || l->sens > p->p_levels.nprim)
1678c2ecf20Sopenharmony_ci		return 0;
1688c2ecf20Sopenharmony_ci	levdatum = symtab_search(&p->p_levels,
1698c2ecf20Sopenharmony_ci				 sym_name(p, SYM_LEVELS, l->sens - 1));
1708c2ecf20Sopenharmony_ci	if (!levdatum)
1718c2ecf20Sopenharmony_ci		return 0;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/*
1748c2ecf20Sopenharmony_ci	 * Return 1 iff all the bits set in l->cat are also be set in
1758c2ecf20Sopenharmony_ci	 * levdatum->level->cat and no bit in l->cat is larger than
1768c2ecf20Sopenharmony_ci	 * p->p_cats.nprim.
1778c2ecf20Sopenharmony_ci	 */
1788c2ecf20Sopenharmony_ci	return ebitmap_contains(&levdatum->level->cat, &l->cat,
1798c2ecf20Sopenharmony_ci				p->p_cats.nprim);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ciint mls_range_isvalid(struct policydb *p, struct mls_range *r)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	return (mls_level_isvalid(p, &r->level[0]) &&
1858c2ecf20Sopenharmony_ci		mls_level_isvalid(p, &r->level[1]) &&
1868c2ecf20Sopenharmony_ci		mls_level_dom(&r->level[1], &r->level[0]));
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/*
1908c2ecf20Sopenharmony_ci * Return 1 if the MLS fields in the security context
1918c2ecf20Sopenharmony_ci * structure `c' are valid.  Return 0 otherwise.
1928c2ecf20Sopenharmony_ci */
1938c2ecf20Sopenharmony_ciint mls_context_isvalid(struct policydb *p, struct context *c)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct user_datum *usrdatum;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
1988c2ecf20Sopenharmony_ci		return 1;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (!mls_range_isvalid(p, &c->range))
2018c2ecf20Sopenharmony_ci		return 0;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (c->role == OBJECT_R_VAL)
2048c2ecf20Sopenharmony_ci		return 1;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/*
2078c2ecf20Sopenharmony_ci	 * User must be authorized for the MLS range.
2088c2ecf20Sopenharmony_ci	 */
2098c2ecf20Sopenharmony_ci	if (!c->user || c->user > p->p_users.nprim)
2108c2ecf20Sopenharmony_ci		return 0;
2118c2ecf20Sopenharmony_ci	usrdatum = p->user_val_to_struct[c->user - 1];
2128c2ecf20Sopenharmony_ci	if (!mls_range_contains(usrdatum->range, c->range))
2138c2ecf20Sopenharmony_ci		return 0; /* user may not be associated with range */
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	return 1;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci/*
2198c2ecf20Sopenharmony_ci * Set the MLS fields in the security context structure
2208c2ecf20Sopenharmony_ci * `context' based on the string representation in
2218c2ecf20Sopenharmony_ci * the string `scontext'.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * This function modifies the string in place, inserting
2248c2ecf20Sopenharmony_ci * NULL characters to terminate the MLS fields.
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci * If a def_sid is provided and no MLS field is present,
2278c2ecf20Sopenharmony_ci * copy the MLS field of the associated default context.
2288c2ecf20Sopenharmony_ci * Used for upgraded to MLS systems where objects may lack
2298c2ecf20Sopenharmony_ci * MLS fields.
2308c2ecf20Sopenharmony_ci *
2318c2ecf20Sopenharmony_ci * Policy read-lock must be held for sidtab lookup.
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci */
2348c2ecf20Sopenharmony_ciint mls_context_to_sid(struct policydb *pol,
2358c2ecf20Sopenharmony_ci		       char oldc,
2368c2ecf20Sopenharmony_ci		       char *scontext,
2378c2ecf20Sopenharmony_ci		       struct context *context,
2388c2ecf20Sopenharmony_ci		       struct sidtab *s,
2398c2ecf20Sopenharmony_ci		       u32 def_sid)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	char *sensitivity, *cur_cat, *next_cat, *rngptr;
2428c2ecf20Sopenharmony_ci	struct level_datum *levdatum;
2438c2ecf20Sopenharmony_ci	struct cat_datum *catdatum, *rngdatum;
2448c2ecf20Sopenharmony_ci	int l, rc, i;
2458c2ecf20Sopenharmony_ci	char *rangep[2];
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (!pol->mls_enabled) {
2488c2ecf20Sopenharmony_ci		/*
2498c2ecf20Sopenharmony_ci		 * With no MLS, only return -EINVAL if there is a MLS field
2508c2ecf20Sopenharmony_ci		 * and it did not come from an xattr.
2518c2ecf20Sopenharmony_ci		 */
2528c2ecf20Sopenharmony_ci		if (oldc && def_sid == SECSID_NULL)
2538c2ecf20Sopenharmony_ci			return -EINVAL;
2548c2ecf20Sopenharmony_ci		return 0;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/*
2588c2ecf20Sopenharmony_ci	 * No MLS component to the security context, try and map to
2598c2ecf20Sopenharmony_ci	 * default if provided.
2608c2ecf20Sopenharmony_ci	 */
2618c2ecf20Sopenharmony_ci	if (!oldc) {
2628c2ecf20Sopenharmony_ci		struct context *defcon;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		if (def_sid == SECSID_NULL)
2658c2ecf20Sopenharmony_ci			return -EINVAL;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		defcon = sidtab_search(s, def_sid);
2688c2ecf20Sopenharmony_ci		if (!defcon)
2698c2ecf20Sopenharmony_ci			return -EINVAL;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci		return mls_context_cpy(context, defcon);
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/*
2758c2ecf20Sopenharmony_ci	 * If we're dealing with a range, figure out where the two parts
2768c2ecf20Sopenharmony_ci	 * of the range begin.
2778c2ecf20Sopenharmony_ci	 */
2788c2ecf20Sopenharmony_ci	rangep[0] = scontext;
2798c2ecf20Sopenharmony_ci	rangep[1] = strchr(scontext, '-');
2808c2ecf20Sopenharmony_ci	if (rangep[1]) {
2818c2ecf20Sopenharmony_ci		rangep[1][0] = '\0';
2828c2ecf20Sopenharmony_ci		rangep[1]++;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* For each part of the range: */
2868c2ecf20Sopenharmony_ci	for (l = 0; l < 2; l++) {
2878c2ecf20Sopenharmony_ci		/* Split sensitivity and category set. */
2888c2ecf20Sopenharmony_ci		sensitivity = rangep[l];
2898c2ecf20Sopenharmony_ci		if (sensitivity == NULL)
2908c2ecf20Sopenharmony_ci			break;
2918c2ecf20Sopenharmony_ci		next_cat = strchr(sensitivity, ':');
2928c2ecf20Sopenharmony_ci		if (next_cat)
2938c2ecf20Sopenharmony_ci			*(next_cat++) = '\0';
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		/* Parse sensitivity. */
2968c2ecf20Sopenharmony_ci		levdatum = symtab_search(&pol->p_levels, sensitivity);
2978c2ecf20Sopenharmony_ci		if (!levdatum)
2988c2ecf20Sopenharmony_ci			return -EINVAL;
2998c2ecf20Sopenharmony_ci		context->range.level[l].sens = levdatum->level->sens;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		/* Extract category set. */
3028c2ecf20Sopenharmony_ci		while (next_cat != NULL) {
3038c2ecf20Sopenharmony_ci			cur_cat = next_cat;
3048c2ecf20Sopenharmony_ci			next_cat = strchr(next_cat, ',');
3058c2ecf20Sopenharmony_ci			if (next_cat != NULL)
3068c2ecf20Sopenharmony_ci				*(next_cat++) = '\0';
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci			/* Separate into range if exists */
3098c2ecf20Sopenharmony_ci			rngptr = strchr(cur_cat, '.');
3108c2ecf20Sopenharmony_ci			if (rngptr != NULL) {
3118c2ecf20Sopenharmony_ci				/* Remove '.' */
3128c2ecf20Sopenharmony_ci				*rngptr++ = '\0';
3138c2ecf20Sopenharmony_ci			}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci			catdatum = symtab_search(&pol->p_cats, cur_cat);
3168c2ecf20Sopenharmony_ci			if (!catdatum)
3178c2ecf20Sopenharmony_ci				return -EINVAL;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci			rc = ebitmap_set_bit(&context->range.level[l].cat,
3208c2ecf20Sopenharmony_ci					     catdatum->value - 1, 1);
3218c2ecf20Sopenharmony_ci			if (rc)
3228c2ecf20Sopenharmony_ci				return rc;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci			/* If range, set all categories in range */
3258c2ecf20Sopenharmony_ci			if (rngptr == NULL)
3268c2ecf20Sopenharmony_ci				continue;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci			rngdatum = symtab_search(&pol->p_cats, rngptr);
3298c2ecf20Sopenharmony_ci			if (!rngdatum)
3308c2ecf20Sopenharmony_ci				return -EINVAL;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci			if (catdatum->value >= rngdatum->value)
3338c2ecf20Sopenharmony_ci				return -EINVAL;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci			for (i = catdatum->value; i < rngdatum->value; i++) {
3368c2ecf20Sopenharmony_ci				rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
3378c2ecf20Sopenharmony_ci				if (rc)
3388c2ecf20Sopenharmony_ci					return rc;
3398c2ecf20Sopenharmony_ci			}
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/* If we didn't see a '-', the range start is also the range end. */
3448c2ecf20Sopenharmony_ci	if (rangep[1] == NULL) {
3458c2ecf20Sopenharmony_ci		context->range.level[1].sens = context->range.level[0].sens;
3468c2ecf20Sopenharmony_ci		rc = ebitmap_cpy(&context->range.level[1].cat,
3478c2ecf20Sopenharmony_ci				 &context->range.level[0].cat);
3488c2ecf20Sopenharmony_ci		if (rc)
3498c2ecf20Sopenharmony_ci			return rc;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	return 0;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci/*
3568c2ecf20Sopenharmony_ci * Set the MLS fields in the security context structure
3578c2ecf20Sopenharmony_ci * `context' based on the string representation in
3588c2ecf20Sopenharmony_ci * the string `str'.  This function will allocate temporary memory with the
3598c2ecf20Sopenharmony_ci * given constraints of gfp_mask.
3608c2ecf20Sopenharmony_ci */
3618c2ecf20Sopenharmony_ciint mls_from_string(struct policydb *p, char *str, struct context *context,
3628c2ecf20Sopenharmony_ci		    gfp_t gfp_mask)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	char *tmpstr;
3658c2ecf20Sopenharmony_ci	int rc;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
3688c2ecf20Sopenharmony_ci		return -EINVAL;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	tmpstr = kstrdup(str, gfp_mask);
3718c2ecf20Sopenharmony_ci	if (!tmpstr) {
3728c2ecf20Sopenharmony_ci		rc = -ENOMEM;
3738c2ecf20Sopenharmony_ci	} else {
3748c2ecf20Sopenharmony_ci		rc = mls_context_to_sid(p, ':', tmpstr, context,
3758c2ecf20Sopenharmony_ci					NULL, SECSID_NULL);
3768c2ecf20Sopenharmony_ci		kfree(tmpstr);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return rc;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/*
3838c2ecf20Sopenharmony_ci * Copies the MLS range `range' into `context'.
3848c2ecf20Sopenharmony_ci */
3858c2ecf20Sopenharmony_ciint mls_range_set(struct context *context,
3868c2ecf20Sopenharmony_ci				struct mls_range *range)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	int l, rc = 0;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/* Copy the MLS range into the  context */
3918c2ecf20Sopenharmony_ci	for (l = 0; l < 2; l++) {
3928c2ecf20Sopenharmony_ci		context->range.level[l].sens = range->level[l].sens;
3938c2ecf20Sopenharmony_ci		rc = ebitmap_cpy(&context->range.level[l].cat,
3948c2ecf20Sopenharmony_ci				 &range->level[l].cat);
3958c2ecf20Sopenharmony_ci		if (rc)
3968c2ecf20Sopenharmony_ci			break;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return rc;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ciint mls_setup_user_range(struct policydb *p,
4038c2ecf20Sopenharmony_ci			 struct context *fromcon, struct user_datum *user,
4048c2ecf20Sopenharmony_ci			 struct context *usercon)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	if (p->mls_enabled) {
4078c2ecf20Sopenharmony_ci		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
4088c2ecf20Sopenharmony_ci		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
4098c2ecf20Sopenharmony_ci		struct mls_level *user_low = &(user->range.level[0]);
4108c2ecf20Sopenharmony_ci		struct mls_level *user_clr = &(user->range.level[1]);
4118c2ecf20Sopenharmony_ci		struct mls_level *user_def = &(user->dfltlevel);
4128c2ecf20Sopenharmony_ci		struct mls_level *usercon_sen = &(usercon->range.level[0]);
4138c2ecf20Sopenharmony_ci		struct mls_level *usercon_clr = &(usercon->range.level[1]);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		/* Honor the user's default level if we can */
4168c2ecf20Sopenharmony_ci		if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
4178c2ecf20Sopenharmony_ci			*usercon_sen = *user_def;
4188c2ecf20Sopenharmony_ci		else if (mls_level_between(fromcon_sen, user_def, user_clr))
4198c2ecf20Sopenharmony_ci			*usercon_sen = *fromcon_sen;
4208c2ecf20Sopenharmony_ci		else if (mls_level_between(fromcon_clr, user_low, user_def))
4218c2ecf20Sopenharmony_ci			*usercon_sen = *user_low;
4228c2ecf20Sopenharmony_ci		else
4238c2ecf20Sopenharmony_ci			return -EINVAL;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		/* Lower the clearance of available contexts
4268c2ecf20Sopenharmony_ci		   if the clearance of "fromcon" is lower than
4278c2ecf20Sopenharmony_ci		   that of the user's default clearance (but
4288c2ecf20Sopenharmony_ci		   only if the "fromcon" clearance dominates
4298c2ecf20Sopenharmony_ci		   the user's computed sensitivity level) */
4308c2ecf20Sopenharmony_ci		if (mls_level_dom(user_clr, fromcon_clr))
4318c2ecf20Sopenharmony_ci			*usercon_clr = *fromcon_clr;
4328c2ecf20Sopenharmony_ci		else if (mls_level_dom(fromcon_clr, user_clr))
4338c2ecf20Sopenharmony_ci			*usercon_clr = *user_clr;
4348c2ecf20Sopenharmony_ci		else
4358c2ecf20Sopenharmony_ci			return -EINVAL;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	return 0;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci/*
4428c2ecf20Sopenharmony_ci * Convert the MLS fields in the security context
4438c2ecf20Sopenharmony_ci * structure `oldc' from the values specified in the
4448c2ecf20Sopenharmony_ci * policy `oldp' to the values specified in the policy `newp',
4458c2ecf20Sopenharmony_ci * storing the resulting context in `newc'.
4468c2ecf20Sopenharmony_ci */
4478c2ecf20Sopenharmony_ciint mls_convert_context(struct policydb *oldp,
4488c2ecf20Sopenharmony_ci			struct policydb *newp,
4498c2ecf20Sopenharmony_ci			struct context *oldc,
4508c2ecf20Sopenharmony_ci			struct context *newc)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct level_datum *levdatum;
4538c2ecf20Sopenharmony_ci	struct cat_datum *catdatum;
4548c2ecf20Sopenharmony_ci	struct ebitmap_node *node;
4558c2ecf20Sopenharmony_ci	int l, i;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (!oldp->mls_enabled || !newp->mls_enabled)
4588c2ecf20Sopenharmony_ci		return 0;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	for (l = 0; l < 2; l++) {
4618c2ecf20Sopenharmony_ci		char *name = sym_name(oldp, SYM_LEVELS,
4628c2ecf20Sopenharmony_ci				      oldc->range.level[l].sens - 1);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		levdatum = symtab_search(&newp->p_levels, name);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		if (!levdatum)
4678c2ecf20Sopenharmony_ci			return -EINVAL;
4688c2ecf20Sopenharmony_ci		newc->range.level[l].sens = levdatum->level->sens;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci		ebitmap_for_each_positive_bit(&oldc->range.level[l].cat,
4718c2ecf20Sopenharmony_ci					      node, i) {
4728c2ecf20Sopenharmony_ci			int rc;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci			catdatum = symtab_search(&newp->p_cats,
4758c2ecf20Sopenharmony_ci						 sym_name(oldp, SYM_CATS, i));
4768c2ecf20Sopenharmony_ci			if (!catdatum)
4778c2ecf20Sopenharmony_ci				return -EINVAL;
4788c2ecf20Sopenharmony_ci			rc = ebitmap_set_bit(&newc->range.level[l].cat,
4798c2ecf20Sopenharmony_ci					     catdatum->value - 1, 1);
4808c2ecf20Sopenharmony_ci			if (rc)
4818c2ecf20Sopenharmony_ci				return rc;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ciint mls_compute_sid(struct policydb *p,
4898c2ecf20Sopenharmony_ci		    struct context *scontext,
4908c2ecf20Sopenharmony_ci		    struct context *tcontext,
4918c2ecf20Sopenharmony_ci		    u16 tclass,
4928c2ecf20Sopenharmony_ci		    u32 specified,
4938c2ecf20Sopenharmony_ci		    struct context *newcontext,
4948c2ecf20Sopenharmony_ci		    bool sock)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct range_trans rtr;
4978c2ecf20Sopenharmony_ci	struct mls_range *r;
4988c2ecf20Sopenharmony_ci	struct class_datum *cladatum;
4998c2ecf20Sopenharmony_ci	int default_range = 0;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
5028c2ecf20Sopenharmony_ci		return 0;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	switch (specified) {
5058c2ecf20Sopenharmony_ci	case AVTAB_TRANSITION:
5068c2ecf20Sopenharmony_ci		/* Look for a range transition rule. */
5078c2ecf20Sopenharmony_ci		rtr.source_type = scontext->type;
5088c2ecf20Sopenharmony_ci		rtr.target_type = tcontext->type;
5098c2ecf20Sopenharmony_ci		rtr.target_class = tclass;
5108c2ecf20Sopenharmony_ci		r = policydb_rangetr_search(p, &rtr);
5118c2ecf20Sopenharmony_ci		if (r)
5128c2ecf20Sopenharmony_ci			return mls_range_set(newcontext, r);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		if (tclass && tclass <= p->p_classes.nprim) {
5158c2ecf20Sopenharmony_ci			cladatum = p->class_val_to_struct[tclass - 1];
5168c2ecf20Sopenharmony_ci			if (cladatum)
5178c2ecf20Sopenharmony_ci				default_range = cladatum->default_range;
5188c2ecf20Sopenharmony_ci		}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		switch (default_range) {
5218c2ecf20Sopenharmony_ci		case DEFAULT_SOURCE_LOW:
5228c2ecf20Sopenharmony_ci			return mls_context_cpy_low(newcontext, scontext);
5238c2ecf20Sopenharmony_ci		case DEFAULT_SOURCE_HIGH:
5248c2ecf20Sopenharmony_ci			return mls_context_cpy_high(newcontext, scontext);
5258c2ecf20Sopenharmony_ci		case DEFAULT_SOURCE_LOW_HIGH:
5268c2ecf20Sopenharmony_ci			return mls_context_cpy(newcontext, scontext);
5278c2ecf20Sopenharmony_ci		case DEFAULT_TARGET_LOW:
5288c2ecf20Sopenharmony_ci			return mls_context_cpy_low(newcontext, tcontext);
5298c2ecf20Sopenharmony_ci		case DEFAULT_TARGET_HIGH:
5308c2ecf20Sopenharmony_ci			return mls_context_cpy_high(newcontext, tcontext);
5318c2ecf20Sopenharmony_ci		case DEFAULT_TARGET_LOW_HIGH:
5328c2ecf20Sopenharmony_ci			return mls_context_cpy(newcontext, tcontext);
5338c2ecf20Sopenharmony_ci		case DEFAULT_GLBLUB:
5348c2ecf20Sopenharmony_ci			return mls_context_glblub(newcontext,
5358c2ecf20Sopenharmony_ci						  scontext, tcontext);
5368c2ecf20Sopenharmony_ci		}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		fallthrough;
5398c2ecf20Sopenharmony_ci	case AVTAB_CHANGE:
5408c2ecf20Sopenharmony_ci		if ((tclass == p->process_class) || sock)
5418c2ecf20Sopenharmony_ci			/* Use the process MLS attributes. */
5428c2ecf20Sopenharmony_ci			return mls_context_cpy(newcontext, scontext);
5438c2ecf20Sopenharmony_ci		else
5448c2ecf20Sopenharmony_ci			/* Use the process effective MLS attributes. */
5458c2ecf20Sopenharmony_ci			return mls_context_cpy_low(newcontext, scontext);
5468c2ecf20Sopenharmony_ci	case AVTAB_MEMBER:
5478c2ecf20Sopenharmony_ci		/* Use the process effective MLS attributes. */
5488c2ecf20Sopenharmony_ci		return mls_context_cpy_low(newcontext, scontext);
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci	return -EINVAL;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci#ifdef CONFIG_NETLABEL
5548c2ecf20Sopenharmony_ci/**
5558c2ecf20Sopenharmony_ci * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
5568c2ecf20Sopenharmony_ci * @context: the security context
5578c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes
5588c2ecf20Sopenharmony_ci *
5598c2ecf20Sopenharmony_ci * Description:
5608c2ecf20Sopenharmony_ci * Given the security context copy the low MLS sensitivity level into the
5618c2ecf20Sopenharmony_ci * NetLabel MLS sensitivity level field.
5628c2ecf20Sopenharmony_ci *
5638c2ecf20Sopenharmony_ci */
5648c2ecf20Sopenharmony_civoid mls_export_netlbl_lvl(struct policydb *p,
5658c2ecf20Sopenharmony_ci			   struct context *context,
5668c2ecf20Sopenharmony_ci			   struct netlbl_lsm_secattr *secattr)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
5698c2ecf20Sopenharmony_ci		return;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	secattr->attr.mls.lvl = context->range.level[0].sens - 1;
5728c2ecf20Sopenharmony_ci	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/**
5768c2ecf20Sopenharmony_ci * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
5778c2ecf20Sopenharmony_ci * @context: the security context
5788c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes
5798c2ecf20Sopenharmony_ci *
5808c2ecf20Sopenharmony_ci * Description:
5818c2ecf20Sopenharmony_ci * Given the security context and the NetLabel security attributes, copy the
5828c2ecf20Sopenharmony_ci * NetLabel MLS sensitivity level into the context.
5838c2ecf20Sopenharmony_ci *
5848c2ecf20Sopenharmony_ci */
5858c2ecf20Sopenharmony_civoid mls_import_netlbl_lvl(struct policydb *p,
5868c2ecf20Sopenharmony_ci			   struct context *context,
5878c2ecf20Sopenharmony_ci			   struct netlbl_lsm_secattr *secattr)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
5908c2ecf20Sopenharmony_ci		return;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	context->range.level[0].sens = secattr->attr.mls.lvl + 1;
5938c2ecf20Sopenharmony_ci	context->range.level[1].sens = context->range.level[0].sens;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci/**
5978c2ecf20Sopenharmony_ci * mls_export_netlbl_cat - Export the MLS categories to NetLabel
5988c2ecf20Sopenharmony_ci * @context: the security context
5998c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes
6008c2ecf20Sopenharmony_ci *
6018c2ecf20Sopenharmony_ci * Description:
6028c2ecf20Sopenharmony_ci * Given the security context copy the low MLS categories into the NetLabel
6038c2ecf20Sopenharmony_ci * MLS category field.  Returns zero on success, negative values on failure.
6048c2ecf20Sopenharmony_ci *
6058c2ecf20Sopenharmony_ci */
6068c2ecf20Sopenharmony_ciint mls_export_netlbl_cat(struct policydb *p,
6078c2ecf20Sopenharmony_ci			  struct context *context,
6088c2ecf20Sopenharmony_ci			  struct netlbl_lsm_secattr *secattr)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	int rc;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
6138c2ecf20Sopenharmony_ci		return 0;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	rc = ebitmap_netlbl_export(&context->range.level[0].cat,
6168c2ecf20Sopenharmony_ci				   &secattr->attr.mls.cat);
6178c2ecf20Sopenharmony_ci	if (rc == 0 && secattr->attr.mls.cat != NULL)
6188c2ecf20Sopenharmony_ci		secattr->flags |= NETLBL_SECATTR_MLS_CAT;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	return rc;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci/**
6248c2ecf20Sopenharmony_ci * mls_import_netlbl_cat - Import the MLS categories from NetLabel
6258c2ecf20Sopenharmony_ci * @context: the security context
6268c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes
6278c2ecf20Sopenharmony_ci *
6288c2ecf20Sopenharmony_ci * Description:
6298c2ecf20Sopenharmony_ci * Copy the NetLabel security attributes into the SELinux context; since the
6308c2ecf20Sopenharmony_ci * NetLabel security attribute only contains a single MLS category use it for
6318c2ecf20Sopenharmony_ci * both the low and high categories of the context.  Returns zero on success,
6328c2ecf20Sopenharmony_ci * negative values on failure.
6338c2ecf20Sopenharmony_ci *
6348c2ecf20Sopenharmony_ci */
6358c2ecf20Sopenharmony_ciint mls_import_netlbl_cat(struct policydb *p,
6368c2ecf20Sopenharmony_ci			  struct context *context,
6378c2ecf20Sopenharmony_ci			  struct netlbl_lsm_secattr *secattr)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	int rc;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (!p->mls_enabled)
6428c2ecf20Sopenharmony_ci		return 0;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	rc = ebitmap_netlbl_import(&context->range.level[0].cat,
6458c2ecf20Sopenharmony_ci				   secattr->attr.mls.cat);
6468c2ecf20Sopenharmony_ci	if (rc)
6478c2ecf20Sopenharmony_ci		goto import_netlbl_cat_failure;
6488c2ecf20Sopenharmony_ci	memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
6498c2ecf20Sopenharmony_ci	       sizeof(context->range.level[0].cat));
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	return 0;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ciimport_netlbl_cat_failure:
6548c2ecf20Sopenharmony_ci	ebitmap_destroy(&context->range.level[0].cat);
6558c2ecf20Sopenharmony_ci	return rc;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci#endif /* CONFIG_NETLABEL */
658