• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
4  */
5 /*
6  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
7  *
8  *	Support for enhanced MLS infrastructure.
9  *
10  * Updated: Frank Mayer <mayerf@tresys.com>
11  *          and Karl MacMillan <kmacmillan@tresys.com>
12  *
13  * 	Added conditional policy language extensions
14  *
15  * Updated: Red Hat, Inc.  James Morris <jmorris@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 
sepol_set_sidtab(sidtab_t * s)73 int hidden sepol_set_sidtab(sidtab_t * s)
74 {
75 	sidtab = s;
76 	return 0;
77 }
78 
sepol_set_policydb(policydb_t * p)79 int hidden sepol_set_policydb(policydb_t * p)
80 {
81 	policydb = p;
82 	return 0;
83 }
84 
sepol_set_policydb_from_file(FILE * fp)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  */
constraint_expr_eval(context_struct_t * scontext,context_struct_t * tcontext,context_struct_t * xcontext,constraint_expr_t * cexpr)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  */
context_struct_compute_av(context_struct_t * scontext,context_struct_t * tcontext,sepol_security_class_t tclass,sepol_access_vector_t requested,struct sepol_av_decision * avd,unsigned int * reason)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 
sepol_validate_transition(sepol_security_id_t oldsid,sepol_security_id_t newsid,sepol_security_id_t tasksid,sepol_security_class_t tclass)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 
sepol_compute_av_reason(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_access_vector_t requested,struct sepol_av_decision * avd,unsigned int * reason)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 
sepol_compute_av(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_access_vector_t requested,struct sepol_av_decision * avd)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  */
sepol_sid_to_context(sepol_security_id_t sid,sepol_security_context_t * scontext,size_t * scontext_len)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  */
sepol_context_to_sid(const sepol_security_context_t scontext,size_t scontext_len,sepol_security_id_t * sid)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 
compute_sid_handle_invalid_context(context_struct_t * scontext,context_struct_t * tcontext,sepol_security_class_t tclass,context_struct_t * newcontext)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 
sepol_compute_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,uint32_t specified,sepol_security_id_t * out_sid)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  */
sepol_transition_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)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  */
sepol_member_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)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  */
sepol_change_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)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  */
validate_perm(hashtab_key_t key,hashtab_datum_t datum,void * p)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  */
validate_class(hashtab_key_t key,hashtab_datum_t datum,void * p)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. */
clone_sid(sepol_security_id_t sid,context_struct_t * context,void * arg)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 
convert_context_handle_invalid_context(context_struct_t * context)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  */
convert_context(sepol_security_id_t key,context_struct_t * c,void * p)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". */
next_entry(void * buf,struct policy_file * fp,size_t bytes)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 
put_entry(const void * ptr,size_t size,size_t n,struct policy_file * fp)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  */
sepol_load_policy(void * data,size_t len)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  */
sepol_fs_sid(char * name,sepol_security_id_t * fs_sid,sepol_security_id_t * file_sid)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  */
sepol_port_sid(uint16_t domain,uint16_t type,uint8_t protocol,uint16_t port,sepol_security_id_t * out_sid)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  */
sepol_netif_sid(char * name,sepol_security_id_t * if_sid,sepol_security_id_t * msg_sid)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 
match_ipv6_addrmask(uint32_t * input,uint32_t * addr,uint32_t * mask)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  */
sepol_node_sid(uint16_t domain,void * addrp,size_t addrlen,sepol_security_id_t * out_sid)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 
sepol_get_user_sids(sepol_security_id_t fromsid,char * username,sepol_security_id_t ** sids,uint32_t * nel)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  */
sepol_genfs_sid(const char * fstype,char * path,sepol_security_class_t sclass,sepol_security_id_t * sid)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 
sepol_fs_use(const char * fstype,unsigned int * behavior,sepol_security_id_t * sid)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