mls.c 15.7 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10
/*
 * Implementation of the multi-level security (MLS) policy.
 *
 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
 */
/*
 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
 *
 *	Support for enhanced MLS infrastructure.
 *
11
 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
Linus Torvalds's avatar
Linus Torvalds committed
12
 */
13
/*
14
 * Updated: Hewlett-Packard <paul@paul-moore.com>
15
 *
16
 *      Added support to import/export the MLS label from NetLabel
17 18 19
 *
 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
 */
Linus Torvalds's avatar
Linus Torvalds committed
20 21 22 23 24

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
25
#include <net/netlabel.h>
26
#include "sidtab.h"
Linus Torvalds's avatar
Linus Torvalds committed
27 28 29 30 31 32 33 34
#include "mls.h"
#include "policydb.h"
#include "services.h"

/*
 * Return the length in bytes for the MLS fields of the
 * security context string representation of `context'.
 */
35
int mls_compute_context_len(struct context *context)
Linus Torvalds's avatar
Linus Torvalds committed
36
{
37 38 39
	int i, l, len, head, prev;
	char *nm;
	struct ebitmap *e;
40
	struct ebitmap_node *node;
Linus Torvalds's avatar
Linus Torvalds committed
41

42
	if (!policydb.mls_enabled)
Linus Torvalds's avatar
Linus Torvalds committed
43 44 45 46
		return 0;

	len = 1; /* for the beginning ":" */
	for (l = 0; l < 2; l++) {
47
		int index_sens = context->range.level[l].sens;
48
		len += strlen(sym_name(&policydb, SYM_LEVELS, index_sens - 1));
Linus Torvalds's avatar
Linus Torvalds committed
49

50 51 52 53 54 55 56 57
		/* categories */
		head = -2;
		prev = -2;
		e = &context->range.level[l].cat;
		ebitmap_for_each_positive_bit(e, node, i) {
			if (i - prev > 1) {
				/* one or more negative bits are skipped */
				if (head != prev) {
58
					nm = sym_name(&policydb, SYM_CATS, prev);
59 60
					len += strlen(nm) + 1;
				}
61
				nm = sym_name(&policydb, SYM_CATS, i);
62 63
				len += strlen(nm) + 1;
				head = i;
Linus Torvalds's avatar
Linus Torvalds committed
64
			}
65 66 67
			prev = i;
		}
		if (prev != head) {
68
			nm = sym_name(&policydb, SYM_CATS, prev);
69
			len += strlen(nm) + 1;
Linus Torvalds's avatar
Linus Torvalds committed
70 71 72
		}
		if (l == 0) {
			if (mls_level_eq(&context->range.level[0],
73
					 &context->range.level[1]))
Linus Torvalds's avatar
Linus Torvalds committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
				break;
			else
				len++;
		}
	}

	return len;
}

/*
 * Write the security context string representation of
 * the MLS fields of `context' into the string `*scontext'.
 * Update `*scontext' to point to the end of the MLS fields.
 */
void mls_sid_to_context(struct context *context,
89
			char **scontext)
Linus Torvalds's avatar
Linus Torvalds committed
90
{
91 92 93
	char *scontextp, *nm;
	int i, l, head, prev;
	struct ebitmap *e;
94
	struct ebitmap_node *node;
Linus Torvalds's avatar
Linus Torvalds committed
95

96
	if (!policydb.mls_enabled)
Linus Torvalds's avatar
Linus Torvalds committed
97 98 99 100 101 102 103 104
		return;

	scontextp = *scontext;

	*scontextp = ':';
	scontextp++;

	for (l = 0; l < 2; l++) {
105 106
		strcpy(scontextp, sym_name(&policydb, SYM_LEVELS,
					   context->range.level[l].sens - 1));
107
		scontextp += strlen(scontextp);
Linus Torvalds's avatar
Linus Torvalds committed
108 109

		/* categories */
110 111 112 113 114 115 116 117
		head = -2;
		prev = -2;
		e = &context->range.level[l].cat;
		ebitmap_for_each_positive_bit(e, node, i) {
			if (i - prev > 1) {
				/* one or more negative bits are skipped */
				if (prev != head) {
					if (prev - head > 1)
Linus Torvalds's avatar
Linus Torvalds committed
118 119 120
						*scontextp++ = '.';
					else
						*scontextp++ = ',';
121
					nm = sym_name(&policydb, SYM_CATS, prev);
122 123
					strcpy(scontextp, nm);
					scontextp += strlen(nm);
Linus Torvalds's avatar
Linus Torvalds committed
124
				}
125 126 127 128
				if (prev < 0)
					*scontextp++ = ':';
				else
					*scontextp++ = ',';
129
				nm = sym_name(&policydb, SYM_CATS, i);
130 131 132
				strcpy(scontextp, nm);
				scontextp += strlen(nm);
				head = i;
Linus Torvalds's avatar
Linus Torvalds committed
133
			}
134
			prev = i;
Linus Torvalds's avatar
Linus Torvalds committed
135 136
		}

137 138
		if (prev != head) {
			if (prev - head > 1)
Linus Torvalds's avatar
Linus Torvalds committed
139 140 141
				*scontextp++ = '.';
			else
				*scontextp++ = ',';
142
			nm = sym_name(&policydb, SYM_CATS, prev);
143 144
			strcpy(scontextp, nm);
			scontextp += strlen(nm);
Linus Torvalds's avatar
Linus Torvalds committed
145 146 147 148
		}

		if (l == 0) {
			if (mls_level_eq(&context->range.level[0],
149
					 &context->range.level[1]))
Linus Torvalds's avatar
Linus Torvalds committed
150
				break;
151 152
			else
				*scontextp++ = '-';
Linus Torvalds's avatar
Linus Torvalds committed
153 154 155 156 157 158 159
		}
	}

	*scontext = scontextp;
	return;
}

160 161 162 163 164 165 166
int mls_level_isvalid(struct policydb *p, struct mls_level *l)
{
	struct level_datum *levdatum;

	if (!l->sens || l->sens > p->p_levels.nprim)
		return 0;
	levdatum = hashtab_search(p->p_levels.table,
167
				  sym_name(p, SYM_LEVELS, l->sens - 1));
168 169 170
	if (!levdatum)
		return 0;

171 172 173 174 175 176 177
	/*
	 * Return 1 iff all the bits set in l->cat are also be set in
	 * levdatum->level->cat and no bit in l->cat is larger than
	 * p->p_cats.nprim.
	 */
	return ebitmap_contains(&levdatum->level->cat, &l->cat,
				p->p_cats.nprim);
178 179 180 181 182 183 184 185 186
}

int mls_range_isvalid(struct policydb *p, struct mls_range *r)
{
	return (mls_level_isvalid(p, &r->level[0]) &&
		mls_level_isvalid(p, &r->level[1]) &&
		mls_level_dom(&r->level[1], &r->level[0]));
}

Linus Torvalds's avatar
Linus Torvalds committed
187 188 189 190 191 192 193 194
/*
 * Return 1 if the MLS fields in the security context
 * structure `c' are valid.  Return 0 otherwise.
 */
int mls_context_isvalid(struct policydb *p, struct context *c)
{
	struct user_datum *usrdatum;

195
	if (!p->mls_enabled)
Linus Torvalds's avatar
Linus Torvalds committed
196 197
		return 1;

198
	if (!mls_range_isvalid(p, &c->range))
Linus Torvalds's avatar
Linus Torvalds committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
		return 0;

	if (c->role == OBJECT_R_VAL)
		return 1;

	/*
	 * User must be authorized for the MLS range.
	 */
	if (!c->user || c->user > p->p_users.nprim)
		return 0;
	usrdatum = p->user_val_to_struct[c->user - 1];
	if (!mls_range_contains(usrdatum->range, c->range))
		return 0; /* user may not be associated with range */

	return 1;
}

/*
 * Set the MLS fields in the security context structure
 * `context' based on the string representation in
 * the string `*scontext'.  Update `*scontext' to
 * point to the end of the string representation of
 * the MLS fields.
 *
 * This function modifies the string in place, inserting
 * NULL characters to terminate the MLS fields.
225 226 227 228 229 230 231 232
 *
 * If a def_sid is provided and no MLS field is present,
 * copy the MLS field of the associated default context.
 * Used for upgraded to MLS systems where objects may lack
 * MLS fields.
 *
 * Policy read-lock must be held for sidtab lookup.
 *
Linus Torvalds's avatar
Linus Torvalds committed
233
 */
234 235
int mls_context_to_sid(struct policydb *pol,
		       char oldc,
Linus Torvalds's avatar
Linus Torvalds committed
236
		       char **scontext,
237 238 239
		       struct context *context,
		       struct sidtab *s,
		       u32 def_sid)
Linus Torvalds's avatar
Linus Torvalds committed
240 241 242 243 244 245 246 247
{

	char delim;
	char *scontextp, *p, *rngptr;
	struct level_datum *levdatum;
	struct cat_datum *catdatum, *rngdatum;
	int l, rc = -EINVAL;

248
	if (!pol->mls_enabled) {
249
		if (def_sid != SECSID_NULL && oldc)
250
			*scontext += strlen(*scontext) + 1;
Linus Torvalds's avatar
Linus Torvalds committed
251
		return 0;
252
	}
Linus Torvalds's avatar
Linus Torvalds committed
253

254 255 256 257 258 259 260 261 262 263 264 265 266 267
	/*
	 * No MLS component to the security context, try and map to
	 * default if provided.
	 */
	if (!oldc) {
		struct context *defcon;

		if (def_sid == SECSID_NULL)
			goto out;

		defcon = sidtab_search(s, def_sid);
		if (!defcon)
			goto out;

268
		rc = mls_context_cpy(context, defcon);
Linus Torvalds's avatar
Linus Torvalds committed
269
		goto out;
270
	}
Linus Torvalds's avatar
Linus Torvalds committed
271 272 273 274 275 276 277

	/* Extract low sensitivity. */
	scontextp = p = *scontext;
	while (*p && *p != ':' && *p != '-')
		p++;

	delim = *p;
278 279
	if (delim != '\0')
		*p++ = '\0';
Linus Torvalds's avatar
Linus Torvalds committed
280 281

	for (l = 0; l < 2; l++) {
282
		levdatum = hashtab_search(pol->p_levels.table, scontextp);
Linus Torvalds's avatar
Linus Torvalds committed
283 284 285 286 287 288 289 290 291 292 293 294 295 296
		if (!levdatum) {
			rc = -EINVAL;
			goto out;
		}

		context->range.level[l].sens = levdatum->level->sens;

		if (delim == ':') {
			/* Extract category set. */
			while (1) {
				scontextp = p;
				while (*p && *p != ',' && *p != '-')
					p++;
				delim = *p;
297 298
				if (delim != '\0')
					*p++ = '\0';
Linus Torvalds's avatar
Linus Torvalds committed
299 300

				/* Separate into range if exists */
301 302
				rngptr = strchr(scontextp, '.');
				if (rngptr != NULL) {
Linus Torvalds's avatar
Linus Torvalds committed
303
					/* Remove '.' */
304
					*rngptr++ = '\0';
Linus Torvalds's avatar
Linus Torvalds committed
305 306
				}

307
				catdatum = hashtab_search(pol->p_cats.table,
308
							  scontextp);
Linus Torvalds's avatar
Linus Torvalds committed
309 310 311 312 313 314
				if (!catdatum) {
					rc = -EINVAL;
					goto out;
				}

				rc = ebitmap_set_bit(&context->range.level[l].cat,
315
						     catdatum->value - 1, 1);
Linus Torvalds's avatar
Linus Torvalds committed
316 317 318 319 320 321 322
				if (rc)
					goto out;

				/* If range, set all categories in range */
				if (rngptr) {
					int i;

323
					rngdatum = hashtab_search(pol->p_cats.table, rngptr);
Linus Torvalds's avatar
Linus Torvalds committed
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
					if (!rngdatum) {
						rc = -EINVAL;
						goto out;
					}

					if (catdatum->value >= rngdatum->value) {
						rc = -EINVAL;
						goto out;
					}

					for (i = catdatum->value; i < rngdatum->value; i++) {
						rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
						if (rc)
							goto out;
					}
				}

				if (delim != ',')
					break;
			}
		}
		if (delim == '-') {
			/* Extract high sensitivity. */
			scontextp = p;
			while (*p && *p != ':')
				p++;

			delim = *p;
352 353
			if (delim != '\0')
				*p++ = '\0';
Linus Torvalds's avatar
Linus Torvalds committed
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
		} else
			break;
	}

	if (l == 0) {
		context->range.level[1].sens = context->range.level[0].sens;
		rc = ebitmap_cpy(&context->range.level[1].cat,
				 &context->range.level[0].cat);
		if (rc)
			goto out;
	}
	*scontext = ++p;
	rc = 0;
out:
	return rc;
}

371 372 373 374 375 376 377 378 379 380 381
/*
 * Set the MLS fields in the security context structure
 * `context' based on the string representation in
 * the string `str'.  This function will allocate temporary memory with the
 * given constraints of gfp_mask.
 */
int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
{
	char *tmpstr, *freestr;
	int rc;

382
	if (!policydb.mls_enabled)
383 384 385 386 387 388 389 390
		return -EINVAL;

	/* we need freestr because mls_context_to_sid will change
	   the value of tmpstr */
	tmpstr = freestr = kstrdup(str, gfp_mask);
	if (!tmpstr) {
		rc = -ENOMEM;
	} else {
391
		rc = mls_context_to_sid(&policydb, ':', &tmpstr, context,
392
					NULL, SECSID_NULL);
393 394 395 396 397 398
		kfree(freestr);
	}

	return rc;
}

Linus Torvalds's avatar
Linus Torvalds committed
399 400 401
/*
 * Copies the MLS range `range' into `context'.
 */
402
int mls_range_set(struct context *context,
403
				struct mls_range *range)
Linus Torvalds's avatar
Linus Torvalds committed
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
{
	int l, rc = 0;

	/* Copy the MLS range into the  context */
	for (l = 0; l < 2; l++) {
		context->range.level[l].sens = range->level[l].sens;
		rc = ebitmap_cpy(&context->range.level[l].cat,
				 &range->level[l].cat);
		if (rc)
			break;
	}

	return rc;
}

int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
420
			 struct context *usercon)
Linus Torvalds's avatar
Linus Torvalds committed
421
{
422
	if (policydb.mls_enabled) {
Linus Torvalds's avatar
Linus Torvalds committed
423 424 425 426 427 428 429 430 431
		struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
		struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
		struct mls_level *user_low = &(user->range.level[0]);
		struct mls_level *user_clr = &(user->range.level[1]);
		struct mls_level *user_def = &(user->dfltlevel);
		struct mls_level *usercon_sen = &(usercon->range.level[0]);
		struct mls_level *usercon_clr = &(usercon->range.level[1]);

		/* Honor the user's default level if we can */
432
		if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
Linus Torvalds's avatar
Linus Torvalds committed
433
			*usercon_sen = *user_def;
434
		else if (mls_level_between(fromcon_sen, user_def, user_clr))
Linus Torvalds's avatar
Linus Torvalds committed
435
			*usercon_sen = *fromcon_sen;
436
		else if (mls_level_between(fromcon_clr, user_low, user_def))
Linus Torvalds's avatar
Linus Torvalds committed
437
			*usercon_sen = *user_low;
438
		else
Linus Torvalds's avatar
Linus Torvalds committed
439 440 441 442 443 444 445
			return -EINVAL;

		/* Lower the clearance of available contexts
		   if the clearance of "fromcon" is lower than
		   that of the user's default clearance (but
		   only if the "fromcon" clearance dominates
		   the user's computed sensitivity level) */
446
		if (mls_level_dom(user_clr, fromcon_clr))
Linus Torvalds's avatar
Linus Torvalds committed
447
			*usercon_clr = *fromcon_clr;
448
		else if (mls_level_dom(fromcon_clr, user_clr))
Linus Torvalds's avatar
Linus Torvalds committed
449
			*usercon_clr = *user_clr;
450
		else
Linus Torvalds's avatar
Linus Torvalds committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
			return -EINVAL;
	}

	return 0;
}

/*
 * Convert the MLS fields in the security context
 * structure `c' from the values specified in the
 * policy `oldp' to the values specified in the policy `newp'.
 */
int mls_convert_context(struct policydb *oldp,
			struct policydb *newp,
			struct context *c)
{
	struct level_datum *levdatum;
	struct cat_datum *catdatum;
	struct ebitmap bitmap;
469
	struct ebitmap_node *node;
Linus Torvalds's avatar
Linus Torvalds committed
470 471
	int l, i;

472
	if (!policydb.mls_enabled)
Linus Torvalds's avatar
Linus Torvalds committed
473 474 475 476
		return 0;

	for (l = 0; l < 2; l++) {
		levdatum = hashtab_search(newp->p_levels.table,
477 478
					  sym_name(oldp, SYM_LEVELS,
						   c->range.level[l].sens - 1));
Linus Torvalds's avatar
Linus Torvalds committed
479 480 481 482 483 484

		if (!levdatum)
			return -EINVAL;
		c->range.level[l].sens = levdatum->level->sens;

		ebitmap_init(&bitmap);
485 486 487 488
		ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
			int rc;

			catdatum = hashtab_search(newp->p_cats.table,
489
						  sym_name(oldp, SYM_CATS, i));
490 491 492 493 494
			if (!catdatum)
				return -EINVAL;
			rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
			if (rc)
				return rc;
Linus Torvalds's avatar
Linus Torvalds committed
495 496 497 498 499 500 501 502 503 504 505 506
		}
		ebitmap_destroy(&c->range.level[l].cat);
		c->range.level[l].cat = bitmap;
	}

	return 0;
}

int mls_compute_sid(struct context *scontext,
		    struct context *tcontext,
		    u16 tclass,
		    u32 specified,
507 508
		    struct context *newcontext,
		    bool sock)
Linus Torvalds's avatar
Linus Torvalds committed
509
{
510 511
	struct range_trans rtr;
	struct mls_range *r;
512 513
	struct class_datum *cladatum;
	int default_range = 0;
514

515
	if (!policydb.mls_enabled)
Linus Torvalds's avatar
Linus Torvalds committed
516 517 518 519
		return 0;

	switch (specified) {
	case AVTAB_TRANSITION:
520
		/* Look for a range transition rule. */
521 522 523 524 525 526
		rtr.source_type = scontext->type;
		rtr.target_type = tcontext->type;
		rtr.target_class = tclass;
		r = hashtab_search(policydb.range_tr, &rtr);
		if (r)
			return mls_range_set(newcontext, r);
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548

		if (tclass && tclass <= policydb.p_classes.nprim) {
			cladatum = policydb.class_val_to_struct[tclass - 1];
			if (cladatum)
				default_range = cladatum->default_range;
		}

		switch (default_range) {
		case DEFAULT_SOURCE_LOW:
			return mls_context_cpy_low(newcontext, scontext);
		case DEFAULT_SOURCE_HIGH:
			return mls_context_cpy_high(newcontext, scontext);
		case DEFAULT_SOURCE_LOW_HIGH:
			return mls_context_cpy(newcontext, scontext);
		case DEFAULT_TARGET_LOW:
			return mls_context_cpy_low(newcontext, tcontext);
		case DEFAULT_TARGET_HIGH:
			return mls_context_cpy_high(newcontext, tcontext);
		case DEFAULT_TARGET_LOW_HIGH:
			return mls_context_cpy(newcontext, tcontext);
		}

Linus Torvalds's avatar
Linus Torvalds committed
549 550
		/* Fallthrough */
	case AVTAB_CHANGE:
551
		if ((tclass == policydb.process_class) || (sock == true))
Linus Torvalds's avatar
Linus Torvalds committed
552
			/* Use the process MLS attributes. */
553
			return mls_context_cpy(newcontext, scontext);
Linus Torvalds's avatar
Linus Torvalds committed
554 555
		else
			/* Use the process effective MLS attributes. */
556
			return mls_context_cpy_low(newcontext, scontext);
Linus Torvalds's avatar
Linus Torvalds committed
557
	case AVTAB_MEMBER:
558 559
		/* Use the process effective MLS attributes. */
		return mls_context_cpy_low(newcontext, scontext);
560 561

	/* fall through */
Linus Torvalds's avatar
Linus Torvalds committed
562 563 564 565
	}
	return -EINVAL;
}

566
#ifdef CONFIG_NETLABEL
567
/**
568
 * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
569
 * @context: the security context
570
 * @secattr: the NetLabel security attributes
571 572
 *
 * Description:
573 574
 * Given the security context copy the low MLS sensitivity level into the
 * NetLabel MLS sensitivity level field.
575 576
 *
 */
577 578
void mls_export_netlbl_lvl(struct context *context,
			   struct netlbl_lsm_secattr *secattr)
579
{
580
	if (!policydb.mls_enabled)
581 582
		return;

583
	secattr->attr.mls.lvl = context->range.level[0].sens - 1;
584
	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
585 586 587
}

/**
588
 * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
589
 * @context: the security context
590
 * @secattr: the NetLabel security attributes
591 592
 *
 * Description:
593 594
 * Given the security context and the NetLabel security attributes, copy the
 * NetLabel MLS sensitivity level into the context.
595 596
 *
 */
597 598
void mls_import_netlbl_lvl(struct context *context,
			   struct netlbl_lsm_secattr *secattr)
599
{
600
	if (!policydb.mls_enabled)
601 602
		return;

603
	context->range.level[0].sens = secattr->attr.mls.lvl + 1;
604
	context->range.level[1].sens = context->range.level[0].sens;
605 606 607
}

/**
608
 * mls_export_netlbl_cat - Export the MLS categories to NetLabel
609
 * @context: the security context
610
 * @secattr: the NetLabel security attributes
611 612
 *
 * Description:
613 614
 * Given the security context copy the low MLS categories into the NetLabel
 * MLS category field.  Returns zero on success, negative values on failure.
615 616
 *
 */
617 618
int mls_export_netlbl_cat(struct context *context,
			  struct netlbl_lsm_secattr *secattr)
619
{
620
	int rc;
621

622
	if (!policydb.mls_enabled)
623 624
		return 0;

625
	rc = ebitmap_netlbl_export(&context->range.level[0].cat,
626 627
				   &secattr->attr.mls.cat);
	if (rc == 0 && secattr->attr.mls.cat != NULL)
628
		secattr->flags |= NETLBL_SECATTR_MLS_CAT;
629 630 631 632 633

	return rc;
}

/**
634
 * mls_import_netlbl_cat - Import the MLS categories from NetLabel
635
 * @context: the security context
636
 * @secattr: the NetLabel security attributes
637 638
 *
 * Description:
639 640 641 642
 * Copy the NetLabel security attributes into the SELinux context; since the
 * NetLabel security attribute only contains a single MLS category use it for
 * both the low and high categories of the context.  Returns zero on success,
 * negative values on failure.
643 644
 *
 */
645 646
int mls_import_netlbl_cat(struct context *context,
			  struct netlbl_lsm_secattr *secattr)
647
{
648
	int rc;
649

650
	if (!policydb.mls_enabled)
651 652
		return 0;

653
	rc = ebitmap_netlbl_import(&context->range.level[0].cat,
654
				   secattr->attr.mls.cat);
655 656 657 658 659 660 661
	if (rc != 0)
		goto import_netlbl_cat_failure;

	rc = ebitmap_cpy(&context->range.level[1].cat,
			 &context->range.level[0].cat);
	if (rc != 0)
		goto import_netlbl_cat_failure;
662 663 664

	return 0;

665
import_netlbl_cat_failure:
666 667 668 669
	ebitmap_destroy(&context->range.level[0].cat);
	ebitmap_destroy(&context->range.level[1].cat);
	return rc;
}
670
#endif /* CONFIG_NETLABEL */