• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Author : Stephen Smalley, <sds@tycho.nsa.gov> */
2 /*
3  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
4  *
5  *	Support for enhanced MLS infrastructure.
6  *
7  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2.1 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23 
24 /* FLASK */
25 
26 /*
27  * Implementation of the multi-level security (MLS) policy.
28  */
29 
30 #include <sepol/policydb/policydb.h>
31 #include <sepol/policydb/services.h>
32 #include <sepol/policydb/flask.h>
33 #include <sepol/policydb/context.h>
34 
35 #include <stdlib.h>
36 
37 #include "handle.h"
38 #include "debug.h"
39 #include "private.h"
40 #include "mls.h"
41 
mls_to_string(sepol_handle_t * handle,const policydb_t * policydb,const context_struct_t * mls,char ** str)42 int mls_to_string(sepol_handle_t * handle,
43 		  const policydb_t * policydb,
44 		  const context_struct_t * mls, char **str)
45 {
46 
47 	char *ptr = NULL, *ptr2 = NULL;
48 
49 	/* Temporary buffer - length + NULL terminator */
50 	int len = mls_compute_context_len(policydb, mls) + 1;
51 
52 	ptr = (char *)malloc(len);
53 	if (ptr == NULL)
54 		goto omem;
55 
56 	/* Final string w/ ':' cut off */
57 	ptr2 = (char *)malloc(len - 1);
58 	if (ptr2 == NULL)
59 		goto omem;
60 
61 	mls_sid_to_context(policydb, mls, &ptr);
62 	ptr -= len - 1;
63 	strcpy(ptr2, ptr + 1);
64 
65 	free(ptr);
66 	*str = ptr2;
67 	return STATUS_SUCCESS;
68 
69       omem:
70 	ERR(handle, "out of memory, could not convert mls context to string");
71 
72 	free(ptr);
73 	free(ptr2);
74 	return STATUS_ERR;
75 
76 }
77 
mls_from_string(sepol_handle_t * handle,const policydb_t * policydb,const char * str,context_struct_t * mls)78 int mls_from_string(sepol_handle_t * handle,
79 		    const policydb_t * policydb,
80 		    const char *str, context_struct_t * mls)
81 {
82 
83 	char *tmp = strdup(str);
84 	char *tmp_cp = tmp;
85 	if (!tmp)
86 		goto omem;
87 
88 	if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) {
89 		ERR(handle, "invalid MLS context %s", str);
90 		free(tmp);
91 		goto err;
92 	}
93 
94 	free(tmp);
95 	return STATUS_SUCCESS;
96 
97       omem:
98 	ERR(handle, "out of memory");
99 
100       err:
101 	ERR(handle, "could not construct mls context structure");
102 	return STATUS_ERR;
103 }
104 
105 /*
106  * Return the length in bytes for the MLS fields of the
107  * security context string representation of `context'.
108  */
mls_compute_context_len(const policydb_t * policydb,const context_struct_t * context)109 int mls_compute_context_len(const policydb_t * policydb,
110 			    const context_struct_t * context)
111 {
112 
113 	unsigned int i, l, len, range;
114 	ebitmap_node_t *cnode;
115 
116 	if (!policydb->mls)
117 		return 0;
118 
119 	len = 1;		/* for the beginning ":" */
120 	for (l = 0; l < 2; l++) {
121 		range = 0;
122 		len +=
123 		    strlen(policydb->
124 			   p_sens_val_to_name[context->range.level[l].sens -
125 					      1]);
126 
127 		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
128 			if (ebitmap_node_get_bit(cnode, i)) {
129 				if (range) {
130 					range++;
131 					continue;
132 				}
133 
134 				len +=
135 				    strlen(policydb->p_cat_val_to_name[i]) + 1;
136 				range++;
137 			} else {
138 				if (range > 1)
139 					len +=
140 					    strlen(policydb->
141 						   p_cat_val_to_name[i - 1]) +
142 					    1;
143 				range = 0;
144 			}
145 		}
146 		/* Handle case where last category is the end of range */
147 		if (range > 1)
148 			len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1;
149 
150 		if (l == 0) {
151 			if (mls_level_eq(&context->range.level[0],
152 					 &context->range.level[1]))
153 				break;
154 			else
155 				len++;
156 		}
157 	}
158 
159 	return len;
160 }
161 
162 /*
163  * Write the security context string representation of
164  * the MLS fields of `context' into the string `*scontext'.
165  * Update `*scontext' to point to the end of the MLS fields.
166  */
mls_sid_to_context(const policydb_t * policydb,const context_struct_t * context,char ** scontext)167 void mls_sid_to_context(const policydb_t * policydb,
168 			const context_struct_t * context, char **scontext)
169 {
170 
171 	char *scontextp;
172 	unsigned int i, l, range, wrote_sep;
173 	ebitmap_node_t *cnode;
174 
175 	if (!policydb->mls)
176 		return;
177 
178 	scontextp = *scontext;
179 
180 	*scontextp = ':';
181 	scontextp++;
182 
183 	for (l = 0; l < 2; l++) {
184 		range = 0;
185 		wrote_sep = 0;
186 		strcpy(scontextp,
187 		       policydb->p_sens_val_to_name[context->range.level[l].
188 						    sens - 1]);
189 		scontextp +=
190 		    strlen(policydb->
191 			   p_sens_val_to_name[context->range.level[l].sens -
192 					      1]);
193 		/* categories */
194 		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
195 			if (ebitmap_node_get_bit(cnode, i)) {
196 				if (range) {
197 					range++;
198 					continue;
199 				}
200 
201 				if (!wrote_sep) {
202 					*scontextp++ = ':';
203 					wrote_sep = 1;
204 				} else
205 					*scontextp++ = ',';
206 				strcpy(scontextp,
207 				       policydb->p_cat_val_to_name[i]);
208 				scontextp +=
209 				    strlen(policydb->p_cat_val_to_name[i]);
210 				range++;
211 			} else {
212 				if (range > 1) {
213 					if (range > 2)
214 						*scontextp++ = '.';
215 					else
216 						*scontextp++ = ',';
217 
218 					strcpy(scontextp,
219 					       policydb->p_cat_val_to_name[i -
220 									   1]);
221 					scontextp +=
222 					    strlen(policydb->
223 						   p_cat_val_to_name[i - 1]);
224 				}
225 				range = 0;
226 			}
227 		}
228 		/* Handle case where last category is the end of range */
229 		if (range > 1) {
230 			if (range > 2)
231 				*scontextp++ = '.';
232 			else
233 				*scontextp++ = ',';
234 
235 			strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]);
236 			scontextp += strlen(policydb->p_cat_val_to_name[i - 1]);
237 		}
238 
239 		if (l == 0) {
240 			if (mls_level_eq(&context->range.level[0],
241 					 &context->range.level[1]))
242 				break;
243 			else {
244 				*scontextp = '-';
245 				scontextp++;
246 			}
247 		}
248 	}
249 
250 	*scontext = scontextp;
251 	return;
252 }
253 
254 /*
255  * Return 1 if the MLS fields in the security context
256  * structure `c' are valid.  Return 0 otherwise.
257  */
mls_context_isvalid(const policydb_t * p,const context_struct_t * c)258 int mls_context_isvalid(const policydb_t * p, const context_struct_t * c)
259 {
260 
261 	level_datum_t *levdatum;
262 	user_datum_t *usrdatum;
263 	unsigned int i, l;
264 	ebitmap_node_t *cnode;
265 	hashtab_key_t key;
266 
267 	if (!p->mls)
268 		return 1;
269 
270 	/*
271 	 * MLS range validity checks: high must dominate low, low level must
272 	 * be valid (category set <-> sensitivity check), and high level must
273 	 * be valid (category set <-> sensitivity check)
274 	 */
275 	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
276 		/* High does not dominate low. */
277 		return 0;
278 
279 	for (l = 0; l < 2; l++) {
280 		if (!c->range.level[l].sens
281 		    || c->range.level[l].sens > p->p_levels.nprim)
282 			return 0;
283 
284 		key = p->p_sens_val_to_name[c->range.level[l].sens - 1];
285 		if (!key)
286 			return 0;
287 
288 		levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, key);
289 		if (!levdatum)
290 			return 0;
291 
292 		ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
293 			if (ebitmap_node_get_bit(cnode, i)) {
294 				if (i > p->p_cats.nprim)
295 					return 0;
296 				if (!ebitmap_get_bit(&levdatum->level->cat, i))
297 					/*
298 					 * Category may not be associated with
299 					 * sensitivity in low level.
300 					 */
301 					return 0;
302 			}
303 		}
304 	}
305 
306 	if (c->role == OBJECT_R_VAL)
307 		return 1;
308 
309 	/*
310 	 * User must be authorized for the MLS range.
311 	 */
312 	if (!c->user || c->user > p->p_users.nprim)
313 		return 0;
314 	usrdatum = p->user_val_to_struct[c->user - 1];
315 	if (!usrdatum || !mls_range_contains(usrdatum->exp_range, c->range))
316 		return 0;	/* user may not be associated with range */
317 
318 	return 1;
319 }
320 
321 /*
322  * Set the MLS fields in the security context structure
323  * `context' based on the string representation in
324  * the string `*scontext'.  Update `*scontext' to
325  * point to the end of the string representation of
326  * the MLS fields.
327  *
328  * This function modifies the string in place, inserting
329  * NULL characters to terminate the MLS fields.
330  */
mls_context_to_sid(const policydb_t * policydb,char oldc,char ** scontext,context_struct_t * context)331 int mls_context_to_sid(const policydb_t * policydb,
332 		       char oldc, char **scontext, context_struct_t * context)
333 {
334 
335 	char delim;
336 	char *scontextp, *p, *rngptr;
337 	level_datum_t *levdatum;
338 	cat_datum_t *catdatum, *rngdatum;
339 	unsigned int l;
340 
341 	if (!policydb->mls)
342 		return 0;
343 
344 	/* No MLS component to the security context */
345 	if (!oldc)
346 		goto err;
347 
348 	/* Extract low sensitivity. */
349 	scontextp = p = *scontext;
350 	while (*p && *p != ':' && *p != '-')
351 		p++;
352 
353 	delim = *p;
354 	if (delim != 0)
355 		*p++ = 0;
356 
357 	for (l = 0; l < 2; l++) {
358 		levdatum =
359 		    (level_datum_t *) hashtab_search(policydb->p_levels.table,
360 						     (hashtab_key_t) scontextp);
361 
362 		if (!levdatum)
363 			goto err;
364 
365 		context->range.level[l].sens = levdatum->level->sens;
366 
367 		if (delim == ':') {
368 			/* Extract category set. */
369 			while (1) {
370 				scontextp = p;
371 				while (*p && *p != ',' && *p != '-')
372 					p++;
373 				delim = *p;
374 				if (delim != 0)
375 					*p++ = 0;
376 
377 				/* Separate into range if exists */
378 				if ((rngptr = strchr(scontextp, '.')) != NULL) {
379 					/* Remove '.' */
380 					*rngptr++ = 0;
381 				}
382 
383 				catdatum =
384 				    (cat_datum_t *) hashtab_search(policydb->
385 								   p_cats.table,
386 								   (hashtab_key_t)
387 								   scontextp);
388 				if (!catdatum)
389 					goto err;
390 
391 				if (ebitmap_set_bit
392 				    (&context->range.level[l].cat,
393 				     catdatum->s.value - 1, 1))
394 					goto err;
395 
396 				/* If range, set all categories in range */
397 				if (rngptr) {
398 					unsigned int i;
399 
400 					rngdatum = (cat_datum_t *)
401 					    hashtab_search(policydb->p_cats.
402 							   table,
403 							   (hashtab_key_t)
404 							   rngptr);
405 					if (!rngdatum)
406 						goto err;
407 
408 					if (catdatum->s.value >=
409 					    rngdatum->s.value)
410 						goto err;
411 
412 					for (i = catdatum->s.value;
413 					     i < rngdatum->s.value; i++) {
414 						if (ebitmap_set_bit
415 						    (&context->range.level[l].
416 						     cat, i, 1))
417 							goto err;
418 					}
419 				}
420 
421 				if (delim != ',')
422 					break;
423 			}
424 		}
425 		if (delim == '-') {
426 			/* Extract high sensitivity. */
427 			scontextp = p;
428 			while (*p && *p != ':')
429 				p++;
430 
431 			delim = *p;
432 			if (delim != 0)
433 				*p++ = 0;
434 		} else
435 			break;
436 	}
437 
438 	/* High level is missing, copy low level */
439 	if (l == 0) {
440 		if (mls_level_cpy(&context->range.level[1],
441 				  &context->range.level[0]) < 0)
442 			goto err;
443 	}
444 	*scontext = ++p;
445 
446 	return STATUS_SUCCESS;
447 
448       err:
449 	return STATUS_ERR;
450 }
451 
452 /*
453  * Copies the MLS range from `src' into `dst'.
454  */
mls_copy_context(context_struct_t * dst,context_struct_t * src)455 static inline int mls_copy_context(context_struct_t * dst,
456 				   context_struct_t * src)
457 {
458 	int l, rc = 0;
459 
460 	/* Copy the MLS range from the source context */
461 	for (l = 0; l < 2; l++) {
462 		dst->range.level[l].sens = src->range.level[l].sens;
463 		rc = ebitmap_cpy(&dst->range.level[l].cat,
464 				 &src->range.level[l].cat);
465 		if (rc)
466 			break;
467 	}
468 
469 	return rc;
470 }
471 
472 /*
473  * Copies the effective MLS range from `src' into `dst'.
474  */
mls_scopy_context(context_struct_t * dst,context_struct_t * src)475 static inline int mls_scopy_context(context_struct_t * dst,
476 				    context_struct_t * src)
477 {
478 	int l, rc = 0;
479 
480 	/* Copy the MLS range from the source context */
481 	for (l = 0; l < 2; l++) {
482 		dst->range.level[l].sens = src->range.level[0].sens;
483 		rc = ebitmap_cpy(&dst->range.level[l].cat,
484 				 &src->range.level[0].cat);
485 		if (rc)
486 			break;
487 	}
488 
489 	return rc;
490 }
491 
492 /*
493  * Copies the MLS range `range' into `context'.
494  */
mls_range_set(context_struct_t * context,mls_range_t * range)495 static inline int mls_range_set(context_struct_t * context, mls_range_t * range)
496 {
497 	int l, rc = 0;
498 
499 	/* Copy the MLS range into the  context */
500 	for (l = 0; l < 2; l++) {
501 		context->range.level[l].sens = range->level[l].sens;
502 		rc = ebitmap_cpy(&context->range.level[l].cat,
503 				 &range->level[l].cat);
504 		if (rc)
505 			break;
506 	}
507 
508 	return rc;
509 }
510 
mls_setup_user_range(context_struct_t * fromcon,user_datum_t * user,context_struct_t * usercon,int mls)511 int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
512 			 context_struct_t * usercon, int mls)
513 {
514 	if (mls) {
515 		mls_level_t *fromcon_sen = &(fromcon->range.level[0]);
516 		mls_level_t *fromcon_clr = &(fromcon->range.level[1]);
517 		mls_level_t *user_low = &(user->exp_range.level[0]);
518 		mls_level_t *user_clr = &(user->exp_range.level[1]);
519 		mls_level_t *user_def = &(user->exp_dfltlevel);
520 		mls_level_t *usercon_sen = &(usercon->range.level[0]);
521 		mls_level_t *usercon_clr = &(usercon->range.level[1]);
522 
523 		/* Honor the user's default level if we can */
524 		if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
525 			*usercon_sen = *user_def;
526 		} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
527 			*usercon_sen = *fromcon_sen;
528 		} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
529 			*usercon_sen = *user_low;
530 		} else
531 			return -EINVAL;
532 
533 		/* Lower the clearance of available contexts
534 		   if the clearance of "fromcon" is lower than
535 		   that of the user's default clearance (but
536 		   only if the "fromcon" clearance dominates
537 		   the user's computed sensitivity level) */
538 		if (mls_level_dom(user_clr, fromcon_clr)) {
539 			*usercon_clr = *fromcon_clr;
540 		} else if (mls_level_dom(fromcon_clr, user_clr)) {
541 			*usercon_clr = *user_clr;
542 		} else
543 			return -EINVAL;
544 	}
545 
546 	return 0;
547 }
548 
549 /*
550  * Convert the MLS fields in the security context
551  * structure `c' from the values specified in the
552  * policy `oldp' to the values specified in the policy `newp'.
553  */
mls_convert_context(policydb_t * oldp,policydb_t * newp,context_struct_t * c)554 int mls_convert_context(policydb_t * oldp,
555 			policydb_t * newp, context_struct_t * c)
556 {
557 	level_datum_t *levdatum;
558 	cat_datum_t *catdatum;
559 	ebitmap_t bitmap;
560 	unsigned int l, i;
561 	ebitmap_node_t *cnode;
562 
563 	if (!oldp->mls)
564 		return 0;
565 
566 	for (l = 0; l < 2; l++) {
567 		levdatum =
568 		    (level_datum_t *) hashtab_search(newp->p_levels.table,
569 						     oldp->
570 						     p_sens_val_to_name[c->
571 									range.
572 									level
573 									[l].
574 									sens -
575 									1]);
576 
577 		if (!levdatum)
578 			return -EINVAL;
579 		c->range.level[l].sens = levdatum->level->sens;
580 
581 		ebitmap_init(&bitmap);
582 		ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
583 			if (ebitmap_node_get_bit(cnode, i)) {
584 				int rc;
585 
586 				catdatum =
587 				    (cat_datum_t *) hashtab_search(newp->p_cats.
588 								   table,
589 								   oldp->
590 								   p_cat_val_to_name
591 								   [i]);
592 				if (!catdatum)
593 					return -EINVAL;
594 				rc = ebitmap_set_bit(&bitmap,
595 						     catdatum->s.value - 1, 1);
596 				if (rc)
597 					return rc;
598 			}
599 		}
600 		ebitmap_destroy(&c->range.level[l].cat);
601 		c->range.level[l].cat = bitmap;
602 	}
603 
604 	return 0;
605 }
606 
mls_compute_sid(policydb_t * policydb,context_struct_t * scontext,context_struct_t * tcontext,sepol_security_class_t tclass,uint32_t specified,context_struct_t * newcontext)607 int mls_compute_sid(policydb_t * policydb,
608 		    context_struct_t * scontext,
609 		    context_struct_t * tcontext,
610 		    sepol_security_class_t tclass,
611 		    uint32_t specified, context_struct_t * newcontext)
612 {
613 	range_trans_t rtr;
614 	struct mls_range *r;
615 	struct class_datum *cladatum;
616 	int default_range = 0;
617 
618 	if (!policydb->mls)
619 		return 0;
620 
621 	switch (specified) {
622 	case AVTAB_TRANSITION:
623 		/* Look for a range transition rule. */
624 		rtr.source_type = scontext->type;
625 		rtr.target_type = tcontext->type;
626 		rtr.target_class = tclass;
627 		r = hashtab_search(policydb->range_tr, (hashtab_key_t) &rtr);
628 		if (r)
629 			return mls_range_set(newcontext, r);
630 
631 		if (tclass && tclass <= policydb->p_classes.nprim) {
632 			cladatum = policydb->class_val_to_struct[tclass - 1];
633 			if (cladatum)
634 				default_range = cladatum->default_range;
635 		}
636 
637 		switch (default_range) {
638 		case DEFAULT_SOURCE_LOW:
639 			return mls_context_cpy_low(newcontext, scontext);
640 		case DEFAULT_SOURCE_HIGH:
641 			return mls_context_cpy_high(newcontext, scontext);
642 		case DEFAULT_SOURCE_LOW_HIGH:
643 			return mls_context_cpy(newcontext, scontext);
644 		case DEFAULT_TARGET_LOW:
645 			return mls_context_cpy_low(newcontext, tcontext);
646 		case DEFAULT_TARGET_HIGH:
647 			return mls_context_cpy_high(newcontext, tcontext);
648 		case DEFAULT_TARGET_LOW_HIGH:
649 			return mls_context_cpy(newcontext, tcontext);
650 		}
651 
652 		/* Fallthrough */
653 	case AVTAB_CHANGE:
654 		if (tclass == SECCLASS_PROCESS)
655 			/* Use the process MLS attributes. */
656 			return mls_copy_context(newcontext, scontext);
657 		else
658 			/* Use the process effective MLS attributes. */
659 			return mls_scopy_context(newcontext, scontext);
660 	case AVTAB_MEMBER:
661 		/* Use the process effective MLS attributes. */
662 		return mls_context_cpy_low(newcontext, scontext);
663 	default:
664 		return -EINVAL;
665 	}
666 	return -EINVAL;
667 }
668 
sepol_mls_contains(sepol_handle_t * handle,sepol_policydb_t * policydb,const char * mls1,const char * mls2,int * response)669 int sepol_mls_contains(sepol_handle_t * handle,
670 		       sepol_policydb_t * policydb,
671 		       const char *mls1, const char *mls2, int *response)
672 {
673 
674 	context_struct_t *ctx1 = NULL, *ctx2 = NULL;
675 	ctx1 = malloc(sizeof(context_struct_t));
676 	ctx2 = malloc(sizeof(context_struct_t));
677 	if (ctx1 == NULL || ctx2 == NULL)
678 		goto omem;
679 	context_init(ctx1);
680 	context_init(ctx2);
681 
682 	if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0)
683 		goto err;
684 
685 	if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0)
686 		goto err;
687 
688 	*response = mls_range_contains(ctx1->range, ctx2->range);
689 	context_destroy(ctx1);
690 	context_destroy(ctx2);
691 	free(ctx1);
692 	free(ctx2);
693 	return STATUS_SUCCESS;
694 
695       omem:
696 	ERR(handle, "out of memory");
697 
698       err:
699 	ERR(handle, "could not check if mls context %s contains %s",
700 	    mls1, mls2);
701 	context_destroy(ctx1);
702 	context_destroy(ctx2);
703 	free(ctx1);
704 	free(ctx2);
705 	return STATUS_ERR;
706 }
707 
sepol_mls_check(sepol_handle_t * handle,sepol_policydb_t * policydb,const char * mls)708 int sepol_mls_check(sepol_handle_t * handle,
709 		    sepol_policydb_t * policydb, const char *mls)
710 {
711 
712 	int ret;
713 	context_struct_t *con = malloc(sizeof(context_struct_t));
714 	if (!con) {
715 		ERR(handle, "out of memory, could not check if "
716 		    "mls context %s is valid", mls);
717 		return STATUS_ERR;
718 	}
719 	context_init(con);
720 
721 	ret = mls_from_string(handle, &policydb->p, mls, con);
722 	context_destroy(con);
723 	free(con);
724 	return ret;
725 }
726 
mls_semantic_cat_init(mls_semantic_cat_t * c)727 void mls_semantic_cat_init(mls_semantic_cat_t * c)
728 {
729 	memset(c, 0, sizeof(mls_semantic_cat_t));
730 }
731 
mls_semantic_cat_destroy(mls_semantic_cat_t * c)732 void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused)))
733 {
734 	/* it's currently a simple struct - really nothing to destroy */
735 	return;
736 }
737 
mls_semantic_level_init(mls_semantic_level_t * l)738 void mls_semantic_level_init(mls_semantic_level_t * l)
739 {
740 	memset(l, 0, sizeof(mls_semantic_level_t));
741 }
742 
mls_semantic_level_destroy(mls_semantic_level_t * l)743 void mls_semantic_level_destroy(mls_semantic_level_t * l)
744 {
745 	mls_semantic_cat_t *cur, *next;
746 
747 	if (l == NULL)
748 		return;
749 
750 	next = l->cat;
751 	while (next) {
752 		cur = next;
753 		next = cur->next;
754 		mls_semantic_cat_destroy(cur);
755 		free(cur);
756 	}
757 }
758 
mls_semantic_level_cpy(mls_semantic_level_t * dst,mls_semantic_level_t * src)759 int mls_semantic_level_cpy(mls_semantic_level_t * dst,
760 			   mls_semantic_level_t * src)
761 {
762 	mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL;
763 
764 	mls_semantic_level_init(dst);
765 	dst->sens = src->sens;
766 	cat = src->cat;
767 	while (cat) {
768 		newcat =
769 		    (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
770 		if (!newcat)
771 			goto err;
772 
773 		mls_semantic_cat_init(newcat);
774 		if (lnewcat)
775 			lnewcat->next = newcat;
776 		else
777 			dst->cat = newcat;
778 
779 		newcat->low = cat->low;
780 		newcat->high = cat->high;
781 
782 		lnewcat = newcat;
783 		cat = cat->next;
784 	}
785 	return 0;
786 
787       err:
788 	mls_semantic_level_destroy(dst);
789 	return -1;
790 }
791 
mls_semantic_range_init(mls_semantic_range_t * r)792 void mls_semantic_range_init(mls_semantic_range_t * r)
793 {
794 	mls_semantic_level_init(&r->level[0]);
795 	mls_semantic_level_init(&r->level[1]);
796 }
797 
mls_semantic_range_destroy(mls_semantic_range_t * r)798 void mls_semantic_range_destroy(mls_semantic_range_t * r)
799 {
800 	mls_semantic_level_destroy(&r->level[0]);
801 	mls_semantic_level_destroy(&r->level[1]);
802 }
803 
mls_semantic_range_cpy(mls_semantic_range_t * dst,mls_semantic_range_t * src)804 int mls_semantic_range_cpy(mls_semantic_range_t * dst,
805 			   mls_semantic_range_t * src)
806 {
807 	if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0)
808 		return -1;
809 
810 	if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) {
811 		mls_semantic_level_destroy(&dst->level[0]);
812 		return -1;
813 	}
814 
815 	return 0;
816 }
817