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