• 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 		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  */
constraint_expr_eval(context_struct_t * scontext,context_struct_t * tcontext,context_struct_t * xcontext,constraint_expr_t * cexpr)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  */
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)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 
sepol_validate_transition(sepol_security_id_t oldsid,sepol_security_id_t newsid,sepol_security_id_t tasksid,sepol_security_class_t tclass)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 
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)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 
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)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  */
sepol_sid_to_context(sepol_security_id_t sid,sepol_security_context_t * scontext,size_t * scontext_len)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  */
sepol_context_to_sid(const sepol_security_context_t scontext,size_t scontext_len,sepol_security_id_t * sid)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 
compute_sid_handle_invalid_context(context_struct_t * scontext,context_struct_t * tcontext,sepol_security_class_t tclass,context_struct_t * newcontext)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 
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)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  */
sepol_transition_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)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  */
sepol_member_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)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  */
sepol_change_sid(sepol_security_id_t ssid,sepol_security_id_t tsid,sepol_security_class_t tclass,sepol_security_id_t * out_sid)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  */
validate_perm(hashtab_key_t key,hashtab_datum_t datum,void * p)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  */
validate_class(hashtab_key_t key,hashtab_datum_t datum,void * p)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. */
clone_sid(sepol_security_id_t sid,context_struct_t * context,void * arg)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 
convert_context_handle_invalid_context(context_struct_t * context)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  */
convert_context(sepol_security_id_t key,context_struct_t * c,void * p)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". */
next_entry(void * buf,struct policy_file * fp,size_t bytes)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 
put_entry(const void * ptr,size_t size,size_t n,struct policy_file * fp)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  */
sepol_load_policy(void * data,size_t len)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  */
sepol_fs_sid(char * name,sepol_security_id_t * fs_sid,sepol_security_id_t * file_sid)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  */
sepol_port_sid(uint16_t domain,uint16_t type,uint8_t protocol,uint16_t port,sepol_security_id_t * out_sid)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  */
sepol_netif_sid(char * name,sepol_security_id_t * if_sid,sepol_security_id_t * msg_sid)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 
match_ipv6_addrmask(uint32_t * input,uint32_t * addr,uint32_t * mask)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  */
sepol_node_sid(uint16_t domain,void * addrp,size_t addrlen,sepol_security_id_t * out_sid)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 
sepol_get_user_sids(sepol_security_id_t fromsid,char * username,sepol_security_id_t ** sids,uint32_t * nel)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  */
sepol_genfs_sid(const char * fstype,char * path,sepol_security_class_t sclass,sepol_security_id_t * sid)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 
sepol_fs_use(const char * fstype,unsigned int * behavior,sepol_security_id_t * sid)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