Home | History | Annotate | Download | only in src
      1 
      2 /*
      3  * Author : Stephen Smalley, <sds (at) epoch.ncsc.mil>
      4  */
      5 /*
      6  * Updated: Trusted Computer Solutions, Inc. <dgoeddel (at) trustedcs.com>
      7  *
      8  *	Support for enhanced MLS infrastructure.
      9  *
     10  * Updated: Frank Mayer <mayerf (at) tresys.com>
     11  *          and Karl MacMillan <kmacmillan (at) tresys.com>
     12  *
     13  * 	Added conditional policy language extensions
     14  *
     15  * Updated: Red Hat, Inc.  James Morris <jmorris (at) redhat.com>
     16  *
     17  *      Fine-grained netlink support
     18  *      IPv6 support
     19  *      Code cleanup
     20  *
     21  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
     22  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
     23  * Copyright (C) 2003 - 2004 Red Hat, Inc.
     24  *
     25  *  This library is free software; you can redistribute it and/or
     26  *  modify it under the terms of the GNU Lesser General Public
     27  *  License as published by the Free Software Foundation; either
     28  *  version 2.1 of the License, or (at your option) any later version.
     29  *
     30  *  This library is distributed in the hope that it will be useful,
     31  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     32  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     33  *  Lesser General Public License for more details.
     34  *
     35  *  You should have received a copy of the GNU Lesser General Public
     36  *  License along with this library; if not, write to the Free Software
     37  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     38  */
     39 
     40 /* FLASK */
     41 
     42 /*
     43  * Implementation of the security services.
     44  */
     45 
     46 #include <stdlib.h>
     47 #include <sys/types.h>
     48 #include <sys/socket.h>
     49 #include <netinet/in.h>
     50 #include <arpa/inet.h>
     51 
     52 #include <sepol/policydb/policydb.h>
     53 #include <sepol/policydb/sidtab.h>
     54 #include <sepol/policydb/services.h>
     55 #include <sepol/policydb/conditional.h>
     56 #include <sepol/policydb/flask.h>
     57 
     58 #include "debug.h"
     59 #include "private.h"
     60 #include "context.h"
     61 #include "av_permissions.h"
     62 #include "dso.h"
     63 #include "mls.h"
     64 
     65 #define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
     66 #define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
     67 
     68 static int selinux_enforcing = 1;
     69 
     70 static sidtab_t mysidtab, *sidtab = &mysidtab;
     71 static policydb_t mypolicydb, *policydb = &mypolicydb;
     72 
     73 int hidden sepol_set_sidtab(sidtab_t * s)
     74 {
     75 	sidtab = s;
     76 	return 0;
     77 }
     78 
     79 int hidden sepol_set_policydb(policydb_t * p)
     80 {
     81 	policydb = p;
     82 	return 0;
     83 }
     84 
     85 int sepol_set_policydb_from_file(FILE * fp)
     86 {
     87 	struct policy_file pf;
     88 
     89 	policy_file_init(&pf);
     90 	pf.fp = fp;
     91 	pf.type = PF_USE_STDIO;
     92 	if (mypolicydb.policy_type)
     93 		policydb_destroy(&mypolicydb);
     94 	if (policydb_init(&mypolicydb)) {
     95 		ERR(NULL, "Out of memory!");
     96 		return -1;
     97 	}
     98 	if (policydb_read(&mypolicydb, &pf, 0)) {
     99 		ERR(NULL, "can't read binary policy: %s", strerror(errno));
    100 		return -1;
    101 	}
    102 	policydb = &mypolicydb;
    103 	return sepol_sidtab_init(sidtab);
    104 }
    105 
    106 /*
    107  * The largest sequence number that has been used when
    108  * providing an access decision to the access vector cache.
    109  * The sequence number only changes when a policy change
    110  * occurs.
    111  */
    112 static uint32_t latest_granting = 0;
    113 
    114 /*
    115  * Return the boolean value of a constraint expression
    116  * when it is applied to the specified source and target
    117  * security contexts.
    118  *
    119  * xcontext is a special beast...  It is used by the validatetrans rules
    120  * only.  For these rules, scontext is the context before the transition,
    121  * tcontext is the context after the transition, and xcontext is the context
    122  * of the process performing the transition.  All other callers of
    123  * constraint_expr_eval should pass in NULL for xcontext.
    124  */
    125 static int constraint_expr_eval(context_struct_t * scontext,
    126 				context_struct_t * tcontext,
    127 				context_struct_t * xcontext,
    128 				constraint_expr_t * cexpr)
    129 {
    130 	uint32_t val1, val2;
    131 	context_struct_t *c;
    132 	role_datum_t *r1, *r2;
    133 	mls_level_t *l1, *l2;
    134 	constraint_expr_t *e;
    135 	int s[CEXPR_MAXDEPTH];
    136 	int sp = -1;
    137 
    138 	for (e = cexpr; e; e = e->next) {
    139 		switch (e->expr_type) {
    140 		case CEXPR_NOT:
    141 			BUG_ON(sp < 0);
    142 			s[sp] = !s[sp];
    143 			break;
    144 		case CEXPR_AND:
    145 			BUG_ON(sp < 1);
    146 			sp--;
    147 			s[sp] &= s[sp + 1];
    148 			break;
    149 		case CEXPR_OR:
    150 			BUG_ON(sp < 1);
    151 			sp--;
    152 			s[sp] |= s[sp + 1];
    153 			break;
    154 		case CEXPR_ATTR:
    155 			if (sp == (CEXPR_MAXDEPTH - 1))
    156 				return 0;
    157 			switch (e->attr) {
    158 			case CEXPR_USER:
    159 				val1 = scontext->user;
    160 				val2 = tcontext->user;
    161 				break;
    162 			case CEXPR_TYPE:
    163 				val1 = scontext->type;
    164 				val2 = tcontext->type;
    165 				break;
    166 			case CEXPR_ROLE:
    167 				val1 = scontext->role;
    168 				val2 = tcontext->role;
    169 				r1 = policydb->role_val_to_struct[val1 - 1];
    170 				r2 = policydb->role_val_to_struct[val2 - 1];
    171 				switch (e->op) {
    172 				case CEXPR_DOM:
    173 					s[++sp] =
    174 					    ebitmap_get_bit(&r1->dominates,
    175 							    val2 - 1);
    176 					continue;
    177 				case CEXPR_DOMBY:
    178 					s[++sp] =
    179 					    ebitmap_get_bit(&r2->dominates,
    180 							    val1 - 1);
    181 					continue;
    182 				case CEXPR_INCOMP:
    183 					s[++sp] =
    184 					    (!ebitmap_get_bit
    185 					     (&r1->dominates, val2 - 1)
    186 					     && !ebitmap_get_bit(&r2->dominates,
    187 								 val1 - 1));
    188 					continue;
    189 				default:
    190 					break;
    191 				}
    192 				break;
    193 			case CEXPR_L1L2:
    194 				l1 = &(scontext->range.level[0]);
    195 				l2 = &(tcontext->range.level[0]);
    196 				goto mls_ops;
    197 			case CEXPR_L1H2:
    198 				l1 = &(scontext->range.level[0]);
    199 				l2 = &(tcontext->range.level[1]);
    200 				goto mls_ops;
    201 			case CEXPR_H1L2:
    202 				l1 = &(scontext->range.level[1]);
    203 				l2 = &(tcontext->range.level[0]);
    204 				goto mls_ops;
    205 			case CEXPR_H1H2:
    206 				l1 = &(scontext->range.level[1]);
    207 				l2 = &(tcontext->range.level[1]);
    208 				goto mls_ops;
    209 			case CEXPR_L1H1:
    210 				l1 = &(scontext->range.level[0]);
    211 				l2 = &(scontext->range.level[1]);
    212 				goto mls_ops;
    213 			case CEXPR_L2H2:
    214 				l1 = &(tcontext->range.level[0]);
    215 				l2 = &(tcontext->range.level[1]);
    216 				goto mls_ops;
    217 			      mls_ops:
    218 				switch (e->op) {
    219 				case CEXPR_EQ:
    220 					s[++sp] = mls_level_eq(l1, l2);
    221 					continue;
    222 				case CEXPR_NEQ:
    223 					s[++sp] = !mls_level_eq(l1, l2);
    224 					continue;
    225 				case CEXPR_DOM:
    226 					s[++sp] = mls_level_dom(l1, l2);
    227 					continue;
    228 				case CEXPR_DOMBY:
    229 					s[++sp] = mls_level_dom(l2, l1);
    230 					continue;
    231 				case CEXPR_INCOMP:
    232 					s[++sp] = mls_level_incomp(l2, l1);
    233 					continue;
    234 				default:
    235 					BUG();
    236 					return 0;
    237 				}
    238 				break;
    239 			default:
    240 				BUG();
    241 				return 0;
    242 			}
    243 
    244 			switch (e->op) {
    245 			case CEXPR_EQ:
    246 				s[++sp] = (val1 == val2);
    247 				break;
    248 			case CEXPR_NEQ:
    249 				s[++sp] = (val1 != val2);
    250 				break;
    251 			default:
    252 				BUG();
    253 				return 0;
    254 			}
    255 			break;
    256 		case CEXPR_NAMES:
    257 			if (sp == (CEXPR_MAXDEPTH - 1))
    258 				return 0;
    259 			c = scontext;
    260 			if (e->attr & CEXPR_TARGET)
    261 				c = tcontext;
    262 			else if (e->attr & CEXPR_XTARGET) {
    263 				c = xcontext;
    264 				if (!c) {
    265 					BUG();
    266 					return 0;
    267 				}
    268 			}
    269 			if (e->attr & CEXPR_USER)
    270 				val1 = c->user;
    271 			else if (e->attr & CEXPR_ROLE)
    272 				val1 = c->role;
    273 			else if (e->attr & CEXPR_TYPE)
    274 				val1 = c->type;
    275 			else {
    276 				BUG();
    277 				return 0;
    278 			}
    279 
    280 			switch (e->op) {
    281 			case CEXPR_EQ:
    282 				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
    283 				break;
    284 			case CEXPR_NEQ:
    285 				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
    286 				break;
    287 			default:
    288 				BUG();
    289 				return 0;
    290 			}
    291 			break;
    292 		default:
    293 			BUG();
    294 			return 0;
    295 		}
    296 	}
    297 
    298 	BUG_ON(sp != 0);
    299 	return s[0];
    300 }
    301 
    302 /*
    303  * Compute access vectors based on a context structure pair for
    304  * the permissions in a particular class.
    305  */
    306 static int context_struct_compute_av(context_struct_t * scontext,
    307 				     context_struct_t * tcontext,
    308 				     sepol_security_class_t tclass,
    309 				     sepol_access_vector_t requested,
    310 				     struct sepol_av_decision *avd,
    311 				     unsigned int *reason)
    312 {
    313 	constraint_node_t *constraint;
    314 	struct role_allow *ra;
    315 	avtab_key_t avkey;
    316 	class_datum_t *tclass_datum;
    317 	avtab_ptr_t node;
    318 	ebitmap_t *sattr, *tattr;
    319 	ebitmap_node_t *snode, *tnode;
    320 	unsigned int i, j;
    321 
    322 	if (!tclass || tclass > policydb->p_classes.nprim) {
    323 		ERR(NULL, "unrecognized class %d", tclass);
    324 		return -EINVAL;
    325 	}
    326 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
    327 
    328 	/*
    329 	 * Initialize the access vectors to the default values.
    330 	 */
    331 	avd->allowed = 0;
    332 	avd->decided = 0xffffffff;
    333 	avd->auditallow = 0;
    334 	avd->auditdeny = 0xffffffff;
    335 	avd->seqno = latest_granting;
    336 	*reason = 0;
    337 
    338 	/*
    339 	 * If a specific type enforcement rule was defined for
    340 	 * this permission check, then use it.
    341 	 */
    342 	avkey.target_class = tclass;
    343 	avkey.specified = AVTAB_AV;
    344 	sattr = &policydb->type_attr_map[scontext->type - 1];
    345 	tattr = &policydb->type_attr_map[tcontext->type - 1];
    346 	ebitmap_for_each_bit(sattr, snode, i) {
    347 		if (!ebitmap_node_get_bit(snode, i))
    348 			continue;
    349 		ebitmap_for_each_bit(tattr, tnode, j) {
    350 			if (!ebitmap_node_get_bit(tnode, j))
    351 				continue;
    352 			avkey.source_type = i + 1;
    353 			avkey.target_type = j + 1;
    354 			for (node =
    355 			     avtab_search_node(&policydb->te_avtab, &avkey);
    356 			     node != NULL;
    357 			     node =
    358 			     avtab_search_node_next(node, avkey.specified)) {
    359 				if (node->key.specified == AVTAB_ALLOWED)
    360 					avd->allowed |= node->datum.data;
    361 				else if (node->key.specified ==
    362 					 AVTAB_AUDITALLOW)
    363 					avd->auditallow |= node->datum.data;
    364 				else if (node->key.specified == AVTAB_AUDITDENY)
    365 					avd->auditdeny &= node->datum.data;
    366 			}
    367 
    368 			/* Check conditional av table for additional permissions */
    369 			cond_compute_av(&policydb->te_cond_avtab, &avkey, avd);
    370 
    371 		}
    372 	}
    373 
    374 	if (requested & ~avd->allowed) {
    375 		*reason |= SEPOL_COMPUTEAV_TE;
    376 		requested &= avd->allowed;
    377 	}
    378 
    379 	/*
    380 	 * Remove any permissions prohibited by a constraint (this includes
    381 	 * the MLS policy).
    382 	 */
    383 	constraint = tclass_datum->constraints;
    384 	while (constraint) {
    385 		if ((constraint->permissions & (avd->allowed)) &&
    386 		    !constraint_expr_eval(scontext, tcontext, NULL,
    387 					  constraint->expr)) {
    388 			avd->allowed =
    389 			    (avd->allowed) & ~(constraint->permissions);
    390 		}
    391 		constraint = constraint->next;
    392 	}
    393 
    394 	if (requested & ~avd->allowed) {
    395 		*reason |= SEPOL_COMPUTEAV_CONS;
    396 		requested &= avd->allowed;
    397 	}
    398 
    399 	/*
    400 	 * If checking process transition permission and the
    401 	 * role is changing, then check the (current_role, new_role)
    402 	 * pair.
    403 	 */
    404 	if (tclass == SECCLASS_PROCESS &&
    405 	    (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
    406 	    scontext->role != tcontext->role) {
    407 		for (ra = policydb->role_allow; ra; ra = ra->next) {
    408 			if (scontext->role == ra->role &&
    409 			    tcontext->role == ra->new_role)
    410 				break;
    411 		}
    412 		if (!ra)
    413 			avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
    414 							  PROCESS__DYNTRANSITION);
    415 	}
    416 
    417 	if (requested & ~avd->allowed) {
    418 		*reason |= SEPOL_COMPUTEAV_RBAC;
    419 		requested &= avd->allowed;
    420 	}
    421 
    422 	return 0;
    423 }
    424 
    425 int hidden sepol_validate_transition(sepol_security_id_t oldsid,
    426 				     sepol_security_id_t newsid,
    427 				     sepol_security_id_t tasksid,
    428 				     sepol_security_class_t tclass)
    429 {
    430 	context_struct_t *ocontext;
    431 	context_struct_t *ncontext;
    432 	context_struct_t *tcontext;
    433 	class_datum_t *tclass_datum;
    434 	constraint_node_t *constraint;
    435 
    436 	if (!tclass || tclass > policydb->p_classes.nprim) {
    437 		ERR(NULL, "unrecognized class %d", tclass);
    438 		return -EINVAL;
    439 	}
    440 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
    441 
    442 	ocontext = sepol_sidtab_search(sidtab, oldsid);
    443 	if (!ocontext) {
    444 		ERR(NULL, "unrecognized SID %d", oldsid);
    445 		return -EINVAL;
    446 	}
    447 
    448 	ncontext = sepol_sidtab_search(sidtab, newsid);
    449 	if (!ncontext) {
    450 		ERR(NULL, "unrecognized SID %d", newsid);
    451 		return -EINVAL;
    452 	}
    453 
    454 	tcontext = sepol_sidtab_search(sidtab, tasksid);
    455 	if (!tcontext) {
    456 		ERR(NULL, "unrecognized SID %d", tasksid);
    457 		return -EINVAL;
    458 	}
    459 
    460 	constraint = tclass_datum->validatetrans;
    461 	while (constraint) {
    462 		if (!constraint_expr_eval(ocontext, ncontext, tcontext,
    463 					  constraint->expr)) {
    464 			return -EPERM;
    465 		}
    466 		constraint = constraint->next;
    467 	}
    468 
    469 	return 0;
    470 }
    471 
    472 int hidden sepol_compute_av_reason(sepol_security_id_t ssid,
    473 				   sepol_security_id_t tsid,
    474 				   sepol_security_class_t tclass,
    475 				   sepol_access_vector_t requested,
    476 				   struct sepol_av_decision *avd,
    477 				   unsigned int *reason)
    478 {
    479 	context_struct_t *scontext = 0, *tcontext = 0;
    480 	int rc = 0;
    481 
    482 	scontext = sepol_sidtab_search(sidtab, ssid);
    483 	if (!scontext) {
    484 		ERR(NULL, "unrecognized SID %d", ssid);
    485 		rc = -EINVAL;
    486 		goto out;
    487 	}
    488 	tcontext = sepol_sidtab_search(sidtab, tsid);
    489 	if (!tcontext) {
    490 		ERR(NULL, "unrecognized SID %d", tsid);
    491 		rc = -EINVAL;
    492 		goto out;
    493 	}
    494 
    495 	rc = context_struct_compute_av(scontext, tcontext, tclass,
    496 				       requested, avd, reason);
    497       out:
    498 	return rc;
    499 }
    500 
    501 int hidden sepol_compute_av(sepol_security_id_t ssid,
    502 			    sepol_security_id_t tsid,
    503 			    sepol_security_class_t tclass,
    504 			    sepol_access_vector_t requested,
    505 			    struct sepol_av_decision *avd)
    506 {
    507 	unsigned int reason = 0;
    508 	return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd,
    509 				       &reason);
    510 }
    511 
    512 /*
    513  * Write the security context string representation of
    514  * the context associated with `sid' into a dynamically
    515  * allocated string of the correct size.  Set `*scontext'
    516  * to point to this string and set `*scontext_len' to
    517  * the length of the string.
    518  */
    519 int hidden sepol_sid_to_context(sepol_security_id_t sid,
    520 				sepol_security_context_t * scontext,
    521 				size_t * scontext_len)
    522 {
    523 	context_struct_t *context;
    524 	int rc = 0;
    525 
    526 	context = sepol_sidtab_search(sidtab, sid);
    527 	if (!context) {
    528 		ERR(NULL, "unrecognized SID %d", sid);
    529 		rc = -EINVAL;
    530 		goto out;
    531 	}
    532 	rc = context_to_string(NULL, policydb, context, scontext, scontext_len);
    533       out:
    534 	return rc;
    535 
    536 }
    537 
    538 /*
    539  * Return a SID associated with the security context that
    540  * has the string representation specified by `scontext'.
    541  */
    542 int hidden sepol_context_to_sid(const sepol_security_context_t scontext,
    543 				size_t scontext_len, sepol_security_id_t * sid)
    544 {
    545 
    546 	context_struct_t *context = NULL;
    547 
    548 	/* First, create the context */
    549 	if (context_from_string(NULL, policydb, &context,
    550 				scontext, scontext_len) < 0)
    551 		goto err;
    552 
    553 	/* Obtain the new sid */
    554 	if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0))
    555 		goto err;
    556 
    557 	context_destroy(context);
    558 	free(context);
    559 	return STATUS_SUCCESS;
    560 
    561       err:
    562 	if (context) {
    563 		context_destroy(context);
    564 		free(context);
    565 	}
    566 	ERR(NULL, "could not convert %s to sid", scontext);
    567 	return STATUS_ERR;
    568 }
    569 
    570 static inline int compute_sid_handle_invalid_context(context_struct_t *
    571 						     scontext,
    572 						     context_struct_t *
    573 						     tcontext,
    574 						     sepol_security_class_t
    575 						     tclass,
    576 						     context_struct_t *
    577 						     newcontext)
    578 {
    579 	if (selinux_enforcing) {
    580 		return -EACCES;
    581 	} else {
    582 		sepol_security_context_t s, t, n;
    583 		size_t slen, tlen, nlen;
    584 
    585 		context_to_string(NULL, policydb, scontext, &s, &slen);
    586 		context_to_string(NULL, policydb, tcontext, &t, &tlen);
    587 		context_to_string(NULL, policydb, newcontext, &n, &nlen);
    588 		ERR(NULL, "invalid context %s for "
    589 		    "scontext=%s tcontext=%s tclass=%s",
    590 		    n, s, t, policydb->p_class_val_to_name[tclass - 1]);
    591 		free(s);
    592 		free(t);
    593 		free(n);
    594 		return 0;
    595 	}
    596 }
    597 
    598 static int sepol_compute_sid(sepol_security_id_t ssid,
    599 			     sepol_security_id_t tsid,
    600 			     sepol_security_class_t tclass,
    601 			     uint32_t specified, sepol_security_id_t * out_sid)
    602 {
    603 	context_struct_t *scontext = 0, *tcontext = 0, newcontext;
    604 	struct role_trans *roletr = 0;
    605 	avtab_key_t avkey;
    606 	avtab_datum_t *avdatum;
    607 	avtab_ptr_t node;
    608 	int rc = 0;
    609 
    610 	scontext = sepol_sidtab_search(sidtab, ssid);
    611 	if (!scontext) {
    612 		ERR(NULL, "unrecognized SID %d", ssid);
    613 		rc = -EINVAL;
    614 		goto out;
    615 	}
    616 	tcontext = sepol_sidtab_search(sidtab, tsid);
    617 	if (!tcontext) {
    618 		ERR(NULL, "unrecognized SID %d", tsid);
    619 		rc = -EINVAL;
    620 		goto out;
    621 	}
    622 
    623 	context_init(&newcontext);
    624 
    625 	/* Set the user identity. */
    626 	switch (specified) {
    627 	case AVTAB_TRANSITION:
    628 	case AVTAB_CHANGE:
    629 		/* Use the process user identity. */
    630 		newcontext.user = scontext->user;
    631 		break;
    632 	case AVTAB_MEMBER:
    633 		/* Use the related object owner. */
    634 		newcontext.user = tcontext->user;
    635 		break;
    636 	}
    637 
    638 	/* Set the role and type to default values. */
    639 	switch (tclass) {
    640 	case SECCLASS_PROCESS:
    641 		/* Use the current role and type of process. */
    642 		newcontext.role = scontext->role;
    643 		newcontext.type = scontext->type;
    644 		break;
    645 	default:
    646 		/* Use the well-defined object role. */
    647 		newcontext.role = OBJECT_R_VAL;
    648 		/* Use the type of the related object. */
    649 		newcontext.type = tcontext->type;
    650 	}
    651 
    652 	/* Look for a type transition/member/change rule. */
    653 	avkey.source_type = scontext->type;
    654 	avkey.target_type = tcontext->type;
    655 	avkey.target_class = tclass;
    656 	avkey.specified = specified;
    657 	avdatum = avtab_search(&policydb->te_avtab, &avkey);
    658 
    659 	/* If no permanent rule, also check for enabled conditional rules */
    660 	if (!avdatum) {
    661 		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
    662 		for (; node != NULL;
    663 		     node = avtab_search_node_next(node, specified)) {
    664 			if (node->key.specified & AVTAB_ENABLED) {
    665 				avdatum = &node->datum;
    666 				break;
    667 			}
    668 		}
    669 	}
    670 
    671 	if (avdatum) {
    672 		/* Use the type from the type transition/member/change rule. */
    673 		newcontext.type = avdatum->data;
    674 	}
    675 
    676 	/* Check for class-specific changes. */
    677 	switch (tclass) {
    678 	case SECCLASS_PROCESS:
    679 		if (specified & AVTAB_TRANSITION) {
    680 			/* Look for a role transition rule. */
    681 			for (roletr = policydb->role_tr; roletr;
    682 			     roletr = roletr->next) {
    683 				if (roletr->role == scontext->role &&
    684 				    roletr->type == tcontext->type) {
    685 					/* Use the role transition rule. */
    686 					newcontext.role = roletr->new_role;
    687 					break;
    688 				}
    689 			}
    690 		}
    691 		break;
    692 	default:
    693 		break;
    694 	}
    695 
    696 	/* Set the MLS attributes.
    697 	   This is done last because it may allocate memory. */
    698 	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
    699 			     &newcontext);
    700 	if (rc)
    701 		goto out;
    702 
    703 	/* Check the validity of the context. */
    704 	if (!policydb_context_isvalid(policydb, &newcontext)) {
    705 		rc = compute_sid_handle_invalid_context(scontext,
    706 							tcontext,
    707 							tclass, &newcontext);
    708 		if (rc)
    709 			goto out;
    710 	}
    711 	/* Obtain the sid for the context. */
    712 	rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid);
    713       out:
    714 	context_destroy(&newcontext);
    715 	return rc;
    716 }
    717 
    718 /*
    719  * Compute a SID to use for labeling a new object in the
    720  * class `tclass' based on a SID pair.
    721  */
    722 int hidden sepol_transition_sid(sepol_security_id_t ssid,
    723 				sepol_security_id_t tsid,
    724 				sepol_security_class_t tclass,
    725 				sepol_security_id_t * out_sid)
    726 {
    727 	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
    728 }
    729 
    730 /*
    731  * Compute a SID to use when selecting a member of a
    732  * polyinstantiated object of class `tclass' based on
    733  * a SID pair.
    734  */
    735 int hidden sepol_member_sid(sepol_security_id_t ssid,
    736 			    sepol_security_id_t tsid,
    737 			    sepol_security_class_t tclass,
    738 			    sepol_security_id_t * out_sid)
    739 {
    740 	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
    741 }
    742 
    743 /*
    744  * Compute a SID to use for relabeling an object in the
    745  * class `tclass' based on a SID pair.
    746  */
    747 int hidden sepol_change_sid(sepol_security_id_t ssid,
    748 			    sepol_security_id_t tsid,
    749 			    sepol_security_class_t tclass,
    750 			    sepol_security_id_t * out_sid)
    751 {
    752 	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
    753 }
    754 
    755 /*
    756  * Verify that each permission that is defined under the
    757  * existing policy is still defined with the same value
    758  * in the new policy.
    759  */
    760 static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
    761 {
    762 	hashtab_t h;
    763 	perm_datum_t *perdatum, *perdatum2;
    764 
    765 	h = (hashtab_t) p;
    766 	perdatum = (perm_datum_t *) datum;
    767 
    768 	perdatum2 = (perm_datum_t *) hashtab_search(h, key);
    769 	if (!perdatum2) {
    770 		ERR(NULL, "permission %s disappeared", key);
    771 		return -1;
    772 	}
    773 	if (perdatum->s.value != perdatum2->s.value) {
    774 		ERR(NULL, "the value of permissions %s changed", key);
    775 		return -1;
    776 	}
    777 	return 0;
    778 }
    779 
    780 /*
    781  * Verify that each class that is defined under the
    782  * existing policy is still defined with the same
    783  * attributes in the new policy.
    784  */
    785 static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p)
    786 {
    787 	policydb_t *newp;
    788 	class_datum_t *cladatum, *cladatum2;
    789 
    790 	newp = (policydb_t *) p;
    791 	cladatum = (class_datum_t *) datum;
    792 
    793 	cladatum2 =
    794 	    (class_datum_t *) hashtab_search(newp->p_classes.table, key);
    795 	if (!cladatum2) {
    796 		ERR(NULL, "class %s disappeared", key);
    797 		return -1;
    798 	}
    799 	if (cladatum->s.value != cladatum2->s.value) {
    800 		ERR(NULL, "the value of class %s changed", key);
    801 		return -1;
    802 	}
    803 	if ((cladatum->comdatum && !cladatum2->comdatum) ||
    804 	    (!cladatum->comdatum && cladatum2->comdatum)) {
    805 		ERR(NULL, "the inherits clause for the access "
    806 		    "vector definition for class %s changed", key);
    807 		return -1;
    808 	}
    809 	if (cladatum->comdatum) {
    810 		if (hashtab_map
    811 		    (cladatum->comdatum->permissions.table, validate_perm,
    812 		     cladatum2->comdatum->permissions.table)) {
    813 			ERR(NULL,
    814 			    " in the access vector definition "
    815 			    "for class %s\n", key);
    816 			return -1;
    817 		}
    818 	}
    819 	if (hashtab_map(cladatum->permissions.table, validate_perm,
    820 			cladatum2->permissions.table)) {
    821 		ERR(NULL, " in access vector definition for class %s", key);
    822 		return -1;
    823 	}
    824 	return 0;
    825 }
    826 
    827 /* Clone the SID into the new SID table. */
    828 static int clone_sid(sepol_security_id_t sid,
    829 		     context_struct_t * context, void *arg)
    830 {
    831 	sidtab_t *s = arg;
    832 
    833 	return sepol_sidtab_insert(s, sid, context);
    834 }
    835 
    836 static inline int convert_context_handle_invalid_context(context_struct_t *
    837 							 context)
    838 {
    839 	if (selinux_enforcing) {
    840 		return -EINVAL;
    841 	} else {
    842 		sepol_security_context_t s;
    843 		size_t len;
    844 
    845 		context_to_string(NULL, policydb, context, &s, &len);
    846 		ERR(NULL, "context %s is invalid", s);
    847 		free(s);
    848 		return 0;
    849 	}
    850 }
    851 
    852 typedef struct {
    853 	policydb_t *oldp;
    854 	policydb_t *newp;
    855 } convert_context_args_t;
    856 
    857 /*
    858  * Convert the values in the security context
    859  * structure `c' from the values specified
    860  * in the policy `p->oldp' to the values specified
    861  * in the policy `p->newp'.  Verify that the
    862  * context is valid under the new policy.
    863  */
    864 static int convert_context(sepol_security_id_t key __attribute__ ((unused)),
    865 			   context_struct_t * c, void *p)
    866 {
    867 	convert_context_args_t *args;
    868 	context_struct_t oldc;
    869 	role_datum_t *role;
    870 	type_datum_t *typdatum;
    871 	user_datum_t *usrdatum;
    872 	sepol_security_context_t s;
    873 	size_t len;
    874 	int rc = -EINVAL;
    875 
    876 	args = (convert_context_args_t *) p;
    877 
    878 	if (context_cpy(&oldc, c))
    879 		return -ENOMEM;
    880 
    881 	/* Convert the user. */
    882 	usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table,
    883 						   args->oldp->
    884 						   p_user_val_to_name[c->user -
    885 								      1]);
    886 
    887 	if (!usrdatum) {
    888 		goto bad;
    889 	}
    890 	c->user = usrdatum->s.value;
    891 
    892 	/* Convert the role. */
    893 	role = (role_datum_t *) hashtab_search(args->newp->p_roles.table,
    894 					       args->oldp->
    895 					       p_role_val_to_name[c->role - 1]);
    896 	if (!role) {
    897 		goto bad;
    898 	}
    899 	c->role = role->s.value;
    900 
    901 	/* Convert the type. */
    902 	typdatum = (type_datum_t *)
    903 	    hashtab_search(args->newp->p_types.table,
    904 			   args->oldp->p_type_val_to_name[c->type - 1]);
    905 	if (!typdatum) {
    906 		goto bad;
    907 	}
    908 	c->type = typdatum->s.value;
    909 
    910 	rc = mls_convert_context(args->oldp, args->newp, c);
    911 	if (rc)
    912 		goto bad;
    913 
    914 	/* Check the validity of the new context. */
    915 	if (!policydb_context_isvalid(args->newp, c)) {
    916 		rc = convert_context_handle_invalid_context(&oldc);
    917 		if (rc)
    918 			goto bad;
    919 	}
    920 
    921 	context_destroy(&oldc);
    922 	return 0;
    923 
    924       bad:
    925 	context_to_string(NULL, policydb, &oldc, &s, &len);
    926 	context_destroy(&oldc);
    927 	ERR(NULL, "invalidating context %s", s);
    928 	free(s);
    929 	return rc;
    930 }
    931 
    932 /* Reading from a policy "file". */
    933 int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes)
    934 {
    935 	size_t nread;
    936 
    937 	switch (fp->type) {
    938 	case PF_USE_STDIO:
    939 		nread = fread(buf, bytes, 1, fp->fp);
    940 
    941 		if (nread != 1)
    942 			return -1;
    943 		break;
    944 	case PF_USE_MEMORY:
    945 		if (bytes > fp->len)
    946 			return -1;
    947 		memcpy(buf, fp->data, bytes);
    948 		fp->data += bytes;
    949 		fp->len -= bytes;
    950 		break;
    951 	default:
    952 		return -1;
    953 	}
    954 	return 0;
    955 }
    956 
    957 size_t hidden put_entry(const void *ptr, size_t size, size_t n,
    958 			struct policy_file *fp)
    959 {
    960 	size_t bytes = size * n;
    961 
    962 	switch (fp->type) {
    963 	case PF_USE_STDIO:
    964 		return fwrite(ptr, size, n, fp->fp);
    965 	case PF_USE_MEMORY:
    966 		if (bytes > fp->len) {
    967 			errno = ENOSPC;
    968 			return 0;
    969 		}
    970 
    971 		memcpy(fp->data, ptr, bytes);
    972 		fp->data += bytes;
    973 		fp->len -= bytes;
    974 		return n;
    975 	case PF_LEN:
    976 		fp->len += bytes;
    977 		return n;
    978 	default:
    979 		return 0;
    980 	}
    981 	return 0;
    982 }
    983 
    984 /*
    985  * Read a new set of configuration data from
    986  * a policy database binary representation file.
    987  *
    988  * Verify that each class that is defined under the
    989  * existing policy is still defined with the same
    990  * attributes in the new policy.
    991  *
    992  * Convert the context structures in the SID table to the
    993  * new representation and verify that all entries
    994  * in the SID table are valid under the new policy.
    995  *
    996  * Change the active policy database to use the new
    997  * configuration data.
    998  *
    999  * Reset the access vector cache.
   1000  */
   1001 int hidden sepol_load_policy(void *data, size_t len)
   1002 {
   1003 	policydb_t oldpolicydb, newpolicydb;
   1004 	sidtab_t oldsidtab, newsidtab;
   1005 	convert_context_args_t args;
   1006 	int rc = 0;
   1007 	struct policy_file file, *fp;
   1008 
   1009 	policy_file_init(&file);
   1010 	file.type = PF_USE_MEMORY;
   1011 	file.data = data;
   1012 	file.len = len;
   1013 	fp = &file;
   1014 
   1015 	if (policydb_init(&newpolicydb))
   1016 		return -ENOMEM;
   1017 
   1018 	if (policydb_read(&newpolicydb, fp, 1)) {
   1019 		return -EINVAL;
   1020 	}
   1021 
   1022 	sepol_sidtab_init(&newsidtab);
   1023 
   1024 	/* Verify that the existing classes did not change. */
   1025 	if (hashtab_map
   1026 	    (policydb->p_classes.table, validate_class, &newpolicydb)) {
   1027 		ERR(NULL, "the definition of an existing class changed");
   1028 		rc = -EINVAL;
   1029 		goto err;
   1030 	}
   1031 
   1032 	/* Clone the SID table. */
   1033 	sepol_sidtab_shutdown(sidtab);
   1034 	if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) {
   1035 		rc = -ENOMEM;
   1036 		goto err;
   1037 	}
   1038 
   1039 	/* Convert the internal representations of contexts
   1040 	   in the new SID table and remove invalid SIDs. */
   1041 	args.oldp = policydb;
   1042 	args.newp = &newpolicydb;
   1043 	sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
   1044 
   1045 	/* Save the old policydb and SID table to free later. */
   1046 	memcpy(&oldpolicydb, policydb, sizeof *policydb);
   1047 	sepol_sidtab_set(&oldsidtab, sidtab);
   1048 
   1049 	/* Install the new policydb and SID table. */
   1050 	memcpy(policydb, &newpolicydb, sizeof *policydb);
   1051 	sepol_sidtab_set(sidtab, &newsidtab);
   1052 
   1053 	/* Free the old policydb and SID table. */
   1054 	policydb_destroy(&oldpolicydb);
   1055 	sepol_sidtab_destroy(&oldsidtab);
   1056 
   1057 	return 0;
   1058 
   1059       err:
   1060 	sepol_sidtab_destroy(&newsidtab);
   1061 	policydb_destroy(&newpolicydb);
   1062 	return rc;
   1063 
   1064 }
   1065 
   1066 /*
   1067  * Return the SIDs to use for an unlabeled file system
   1068  * that is being mounted from the device with the
   1069  * the kdevname `name'.  The `fs_sid' SID is returned for
   1070  * the file system and the `file_sid' SID is returned
   1071  * for all files within that file system.
   1072  */
   1073 int hidden sepol_fs_sid(char *name,
   1074 			sepol_security_id_t * fs_sid,
   1075 			sepol_security_id_t * file_sid)
   1076 {
   1077 	int rc = 0;
   1078 	ocontext_t *c;
   1079 
   1080 	c = policydb->ocontexts[OCON_FS];
   1081 	while (c) {
   1082 		if (strcmp(c->u.name, name) == 0)
   1083 			break;
   1084 		c = c->next;
   1085 	}
   1086 
   1087 	if (c) {
   1088 		if (!c->sid[0] || !c->sid[1]) {
   1089 			rc = sepol_sidtab_context_to_sid(sidtab,
   1090 							 &c->context[0],
   1091 							 &c->sid[0]);
   1092 			if (rc)
   1093 				goto out;
   1094 			rc = sepol_sidtab_context_to_sid(sidtab,
   1095 							 &c->context[1],
   1096 							 &c->sid[1]);
   1097 			if (rc)
   1098 				goto out;
   1099 		}
   1100 		*fs_sid = c->sid[0];
   1101 		*file_sid = c->sid[1];
   1102 	} else {
   1103 		*fs_sid = SECINITSID_FS;
   1104 		*file_sid = SECINITSID_FILE;
   1105 	}
   1106 
   1107       out:
   1108 	return rc;
   1109 }
   1110 
   1111 /*
   1112  * Return the SID of the port specified by
   1113  * `domain', `type', `protocol', and `port'.
   1114  */
   1115 int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)),
   1116 			  uint16_t type __attribute__ ((unused)),
   1117 			  uint8_t protocol,
   1118 			  uint16_t port, sepol_security_id_t * out_sid)
   1119 {
   1120 	ocontext_t *c;
   1121 	int rc = 0;
   1122 
   1123 	c = policydb->ocontexts[OCON_PORT];
   1124 	while (c) {
   1125 		if (c->u.port.protocol == protocol &&
   1126 		    c->u.port.low_port <= port && c->u.port.high_port >= port)
   1127 			break;
   1128 		c = c->next;
   1129 	}
   1130 
   1131 	if (c) {
   1132 		if (!c->sid[0]) {
   1133 			rc = sepol_sidtab_context_to_sid(sidtab,
   1134 							 &c->context[0],
   1135 							 &c->sid[0]);
   1136 			if (rc)
   1137 				goto out;
   1138 		}
   1139 		*out_sid = c->sid[0];
   1140 	} else {
   1141 		*out_sid = SECINITSID_PORT;
   1142 	}
   1143 
   1144       out:
   1145 	return rc;
   1146 }
   1147 
   1148 /*
   1149  * Return the SIDs to use for a network interface
   1150  * with the name `name'.  The `if_sid' SID is returned for
   1151  * the interface and the `msg_sid' SID is returned as
   1152  * the default SID for messages received on the
   1153  * interface.
   1154  */
   1155 int hidden sepol_netif_sid(char *name,
   1156 			   sepol_security_id_t * if_sid,
   1157 			   sepol_security_id_t * msg_sid)
   1158 {
   1159 	int rc = 0;
   1160 	ocontext_t *c;
   1161 
   1162 	c = policydb->ocontexts[OCON_NETIF];
   1163 	while (c) {
   1164 		if (strcmp(name, c->u.name) == 0)
   1165 			break;
   1166 		c = c->next;
   1167 	}
   1168 
   1169 	if (c) {
   1170 		if (!c->sid[0] || !c->sid[1]) {
   1171 			rc = sepol_sidtab_context_to_sid(sidtab,
   1172 							 &c->context[0],
   1173 							 &c->sid[0]);
   1174 			if (rc)
   1175 				goto out;
   1176 			rc = sepol_sidtab_context_to_sid(sidtab,
   1177 							 &c->context[1],
   1178 							 &c->sid[1]);
   1179 			if (rc)
   1180 				goto out;
   1181 		}
   1182 		*if_sid = c->sid[0];
   1183 		*msg_sid = c->sid[1];
   1184 	} else {
   1185 		*if_sid = SECINITSID_NETIF;
   1186 		*msg_sid = SECINITSID_NETMSG;
   1187 	}
   1188 
   1189       out:
   1190 	return rc;
   1191 }
   1192 
   1193 static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr,
   1194 			       uint32_t * mask)
   1195 {
   1196 	int i, fail = 0;
   1197 
   1198 	for (i = 0; i < 4; i++)
   1199 		if (addr[i] != (input[i] & mask[i])) {
   1200 			fail = 1;
   1201 			break;
   1202 		}
   1203 
   1204 	return !fail;
   1205 }
   1206 
   1207 /*
   1208  * Return the SID of the node specified by the address
   1209  * `addrp' where `addrlen' is the length of the address
   1210  * in bytes and `domain' is the communications domain or
   1211  * address family in which the address should be interpreted.
   1212  */
   1213 int hidden sepol_node_sid(uint16_t domain,
   1214 			  void *addrp,
   1215 			  size_t addrlen, sepol_security_id_t * out_sid)
   1216 {
   1217 	int rc = 0;
   1218 	ocontext_t *c;
   1219 
   1220 	switch (domain) {
   1221 	case AF_INET:{
   1222 			uint32_t addr;
   1223 
   1224 			if (addrlen != sizeof(uint32_t)) {
   1225 				rc = -EINVAL;
   1226 				goto out;
   1227 			}
   1228 
   1229 			addr = *((uint32_t *) addrp);
   1230 
   1231 			c = policydb->ocontexts[OCON_NODE];
   1232 			while (c) {
   1233 				if (c->u.node.addr == (addr & c->u.node.mask))
   1234 					break;
   1235 				c = c->next;
   1236 			}
   1237 			break;
   1238 		}
   1239 
   1240 	case AF_INET6:
   1241 		if (addrlen != sizeof(uint64_t) * 2) {
   1242 			rc = -EINVAL;
   1243 			goto out;
   1244 		}
   1245 
   1246 		c = policydb->ocontexts[OCON_NODE6];
   1247 		while (c) {
   1248 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
   1249 						c->u.node6.mask))
   1250 				break;
   1251 			c = c->next;
   1252 		}
   1253 		break;
   1254 
   1255 	default:
   1256 		*out_sid = SECINITSID_NODE;
   1257 		goto out;
   1258 	}
   1259 
   1260 	if (c) {
   1261 		if (!c->sid[0]) {
   1262 			rc = sepol_sidtab_context_to_sid(sidtab,
   1263 							 &c->context[0],
   1264 							 &c->sid[0]);
   1265 			if (rc)
   1266 				goto out;
   1267 		}
   1268 		*out_sid = c->sid[0];
   1269 	} else {
   1270 		*out_sid = SECINITSID_NODE;
   1271 	}
   1272 
   1273       out:
   1274 	return rc;
   1275 }
   1276 
   1277 /*
   1278  * Generate the set of SIDs for legal security contexts
   1279  * for a given user that can be reached by `fromsid'.
   1280  * Set `*sids' to point to a dynamically allocated
   1281  * array containing the set of SIDs.  Set `*nel' to the
   1282  * number of elements in the array.
   1283  */
   1284 #define SIDS_NEL 25
   1285 
   1286 int hidden sepol_get_user_sids(sepol_security_id_t fromsid,
   1287 			       char *username,
   1288 			       sepol_security_id_t ** sids, uint32_t * nel)
   1289 {
   1290 	context_struct_t *fromcon, usercon;
   1291 	sepol_security_id_t *mysids, *mysids2, sid;
   1292 	uint32_t mynel = 0, maxnel = SIDS_NEL;
   1293 	user_datum_t *user;
   1294 	role_datum_t *role;
   1295 	struct sepol_av_decision avd;
   1296 	int rc = 0;
   1297 	unsigned int i, j, reason;
   1298 	ebitmap_node_t *rnode, *tnode;
   1299 
   1300 	fromcon = sepol_sidtab_search(sidtab, fromsid);
   1301 	if (!fromcon) {
   1302 		rc = -EINVAL;
   1303 		goto out;
   1304 	}
   1305 
   1306 	user = (user_datum_t *) hashtab_search(policydb->p_users.table,
   1307 					       username);
   1308 	if (!user) {
   1309 		rc = -EINVAL;
   1310 		goto out;
   1311 	}
   1312 	usercon.user = user->s.value;
   1313 
   1314 	mysids = malloc(maxnel * sizeof(sepol_security_id_t));
   1315 	if (!mysids) {
   1316 		rc = -ENOMEM;
   1317 		goto out;
   1318 	}
   1319 	memset(mysids, 0, maxnel * sizeof(sepol_security_id_t));
   1320 
   1321 	ebitmap_for_each_bit(&user->roles.roles, rnode, i) {
   1322 		if (!ebitmap_node_get_bit(rnode, i))
   1323 			continue;
   1324 		role = policydb->role_val_to_struct[i];
   1325 		usercon.role = i + 1;
   1326 		ebitmap_for_each_bit(&role->types.types, tnode, j) {
   1327 			if (!ebitmap_node_get_bit(tnode, j))
   1328 				continue;
   1329 			usercon.type = j + 1;
   1330 			if (usercon.type == fromcon->type)
   1331 				continue;
   1332 
   1333 			if (mls_setup_user_range
   1334 			    (fromcon, user, &usercon, policydb->mls))
   1335 				continue;
   1336 
   1337 			rc = context_struct_compute_av(fromcon, &usercon,
   1338 						       SECCLASS_PROCESS,
   1339 						       PROCESS__TRANSITION,
   1340 						       &avd, &reason);
   1341 			if (rc || !(avd.allowed & PROCESS__TRANSITION))
   1342 				continue;
   1343 			rc = sepol_sidtab_context_to_sid(sidtab, &usercon,
   1344 							 &sid);
   1345 			if (rc) {
   1346 				free(mysids);
   1347 				goto out;
   1348 			}
   1349 			if (mynel < maxnel) {
   1350 				mysids[mynel++] = sid;
   1351 			} else {
   1352 				maxnel += SIDS_NEL;
   1353 				mysids2 =
   1354 				    malloc(maxnel *
   1355 					   sizeof(sepol_security_id_t));
   1356 
   1357 				if (!mysids2) {
   1358 					rc = -ENOMEM;
   1359 					free(mysids);
   1360 					goto out;
   1361 				}
   1362 				memset(mysids2, 0,
   1363 				       maxnel * sizeof(sepol_security_id_t));
   1364 				memcpy(mysids2, mysids,
   1365 				       mynel * sizeof(sepol_security_id_t));
   1366 				free(mysids);
   1367 				mysids = mysids2;
   1368 				mysids[mynel++] = sid;
   1369 			}
   1370 		}
   1371 	}
   1372 
   1373 	*sids = mysids;
   1374 	*nel = mynel;
   1375 
   1376       out:
   1377 	return rc;
   1378 }
   1379 
   1380 /*
   1381  * Return the SID to use for a file in a filesystem
   1382  * that cannot support a persistent label mapping or use another
   1383  * fixed labeling behavior like transition SIDs or task SIDs.
   1384  */
   1385 int hidden sepol_genfs_sid(const char *fstype,
   1386 			   char *path,
   1387 			   sepol_security_class_t sclass,
   1388 			   sepol_security_id_t * sid)
   1389 {
   1390 	size_t len;
   1391 	genfs_t *genfs;
   1392 	ocontext_t *c;
   1393 	int rc = 0, cmp = 0;
   1394 
   1395 	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
   1396 		cmp = strcmp(fstype, genfs->fstype);
   1397 		if (cmp <= 0)
   1398 			break;
   1399 	}
   1400 
   1401 	if (!genfs || cmp) {
   1402 		*sid = SECINITSID_UNLABELED;
   1403 		rc = -ENOENT;
   1404 		goto out;
   1405 	}
   1406 
   1407 	for (c = genfs->head; c; c = c->next) {
   1408 		len = strlen(c->u.name);
   1409 		if ((!c->v.sclass || sclass == c->v.sclass) &&
   1410 		    (strncmp(c->u.name, path, len) == 0))
   1411 			break;
   1412 	}
   1413 
   1414 	if (!c) {
   1415 		*sid = SECINITSID_UNLABELED;
   1416 		rc = -ENOENT;
   1417 		goto out;
   1418 	}
   1419 
   1420 	if (!c->sid[0]) {
   1421 		rc = sepol_sidtab_context_to_sid(sidtab,
   1422 						 &c->context[0], &c->sid[0]);
   1423 		if (rc)
   1424 			goto out;
   1425 	}
   1426 
   1427 	*sid = c->sid[0];
   1428       out:
   1429 	return rc;
   1430 }
   1431 
   1432 int hidden sepol_fs_use(const char *fstype,
   1433 			unsigned int *behavior, sepol_security_id_t * sid)
   1434 {
   1435 	int rc = 0;
   1436 	ocontext_t *c;
   1437 
   1438 	c = policydb->ocontexts[OCON_FSUSE];
   1439 	while (c) {
   1440 		if (strcmp(fstype, c->u.name) == 0)
   1441 			break;
   1442 		c = c->next;
   1443 	}
   1444 
   1445 	if (c) {
   1446 		*behavior = c->v.behavior;
   1447 		if (!c->sid[0]) {
   1448 			rc = sepol_sidtab_context_to_sid(sidtab,
   1449 							 &c->context[0],
   1450 							 &c->sid[0]);
   1451 			if (rc)
   1452 				goto out;
   1453 		}
   1454 		*sid = c->sid[0];
   1455 	} else {
   1456 		rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
   1457 		if (rc) {
   1458 			*behavior = SECURITY_FS_USE_NONE;
   1459 			rc = 0;
   1460 		} else {
   1461 			*behavior = SECURITY_FS_USE_GENFS;
   1462 		}
   1463 	}
   1464 
   1465       out:
   1466 	return rc;
   1467 }
   1468 
   1469 /* FLASK */
   1470