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/* Initial sizes malloc'd for sepol_compute_av_reason_buffer() support */
47#define REASON_BUF_SIZE 2048
48#define EXPR_BUF_SIZE 1024
49#define STACK_LEN 32
50
51#include <stdlib.h>
52#include <sys/types.h>
53#include <sys/socket.h>
54#include <netinet/in.h>
55#include <arpa/inet.h>
56
57#include <sepol/policydb/policydb.h>
58#include <sepol/policydb/sidtab.h>
59#include <sepol/policydb/services.h>
60#include <sepol/policydb/conditional.h>
61#include <sepol/policydb/flask.h>
62#include <sepol/policydb/util.h>
63
64#include "debug.h"
65#include "private.h"
66#include "context.h"
67#include "av_permissions.h"
68#include "dso.h"
69#include "mls.h"
70
71#define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
72#define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0)
73
74static int selinux_enforcing = 1;
75
76static sidtab_t mysidtab, *sidtab = &mysidtab;
77static policydb_t mypolicydb, *policydb = &mypolicydb;
78
79/* Used by sepol_compute_av_reason_buffer() to keep track of entries */
80static int reason_buf_used;
81static int reason_buf_len;
82
83/* Stack services for RPN to infix conversion. */
84static char **stack;
85static int stack_len;
86static int next_stack_entry;
87
88static void push(char *expr_ptr)
89{
90	if (next_stack_entry >= stack_len) {
91		char **new_stack = stack;
92		int new_stack_len;
93
94		if (stack_len == 0)
95			new_stack_len = STACK_LEN;
96		else
97			new_stack_len = stack_len * 2;
98
99		new_stack = realloc(stack, new_stack_len * sizeof(*stack));
100		if (!new_stack) {
101			ERR(NULL, "unable to allocate stack space");
102			return;
103		}
104		stack_len = new_stack_len;
105		stack = new_stack;
106	}
107	stack[next_stack_entry] = expr_ptr;
108	next_stack_entry++;
109}
110
111static char *pop(void)
112{
113	next_stack_entry--;
114	if (next_stack_entry < 0) {
115		next_stack_entry = 0;
116		ERR(NULL, "pop called with no stack entries");
117		return NULL;
118	}
119	return stack[next_stack_entry];
120}
121/* End Stack services */
122
123int hidden sepol_set_sidtab(sidtab_t * s)
124{
125	sidtab = s;
126	return 0;
127}
128
129int hidden sepol_set_policydb(policydb_t * p)
130{
131	policydb = p;
132	return 0;
133}
134
135int sepol_set_policydb_from_file(FILE * fp)
136{
137	struct policy_file pf;
138
139	policy_file_init(&pf);
140	pf.fp = fp;
141	pf.type = PF_USE_STDIO;
142	if (mypolicydb.policy_type)
143		policydb_destroy(&mypolicydb);
144	if (policydb_init(&mypolicydb)) {
145		ERR(NULL, "Out of memory!");
146		return -1;
147	}
148	if (policydb_read(&mypolicydb, &pf, 0)) {
149		policydb_destroy(&mypolicydb);
150		ERR(NULL, "can't read binary policy: %s", strerror(errno));
151		return -1;
152	}
153	policydb = &mypolicydb;
154	return sepol_sidtab_init(sidtab);
155}
156
157/*
158 * The largest sequence number that has been used when
159 * providing an access decision to the access vector cache.
160 * The sequence number only changes when a policy change
161 * occurs.
162 */
163static uint32_t latest_granting = 0;
164
165/*
166 * cat_expr_buf adds a string to an expression buffer and handles
167 * realloc's if buffer is too small. The array of expression text
168 * buffer pointers and its counter are globally defined here as
169 * constraint_expr_eval_reason() sets them up and cat_expr_buf
170 * updates the e_buf pointer.
171 */
172static int expr_counter;
173static char **expr_list;
174static int expr_buf_used;
175static int expr_buf_len;
176
177static void cat_expr_buf(char *e_buf, char *string)
178{
179	int len, new_buf_len;
180	char *p, *new_buf = e_buf;
181
182	while (1) {
183		p = e_buf + expr_buf_used;
184		len = snprintf(p, expr_buf_len - expr_buf_used, "%s", string);
185		if (len < 0 || len >= expr_buf_len - expr_buf_used) {
186			new_buf_len = expr_buf_len + EXPR_BUF_SIZE;
187			new_buf = realloc(e_buf, new_buf_len);
188			if (!new_buf) {
189				ERR(NULL, "failed to realloc expr buffer");
190				return;
191			}
192			/* Update new ptr in expr list and locally + new len */
193			expr_list[expr_counter] = new_buf;
194			e_buf = new_buf;
195			expr_buf_len = new_buf_len;
196		} else {
197			expr_buf_used += len;
198			return;
199		}
200	}
201}
202
203/*
204 * If the POLICY_KERN version is >= POLICYDB_VERSION_CONSTRAINT_NAMES,
205 * then for 'types' only, read the types_names->types list as it will
206 * contain a list of types and attributes that were defined in the
207 * policy source.
208 * For user and role plus types (for policy vers <
209 * POLICYDB_VERSION_CONSTRAINT_NAMES) just read the e->names list.
210 */
211static void get_name_list(constraint_expr_t *e, int type,
212							char *src, char *op, int failed)
213{
214	ebitmap_t *types;
215	int rc = 0;
216	unsigned int i;
217	char tmp_buf[128];
218	int counter = 0;
219
220	if (policydb->policy_type == POLICY_KERN &&
221			policydb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES &&
222			type == CEXPR_TYPE)
223		types = &e->type_names->types;
224	else
225		types = &e->names;
226
227	/* Find out how many entries */
228	for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) {
229		rc = ebitmap_get_bit(types, i);
230		if (rc == 0)
231			continue;
232		else
233			counter++;
234	}
235	snprintf(tmp_buf, sizeof(tmp_buf), "(%s%s", src, op);
236	cat_expr_buf(expr_list[expr_counter], tmp_buf);
237
238	if (counter == 0)
239		cat_expr_buf(expr_list[expr_counter], "<empty_set> ");
240	if (counter > 1)
241		cat_expr_buf(expr_list[expr_counter], " {");
242	if (counter >= 1) {
243		for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) {
244			rc = ebitmap_get_bit(types, i);
245			if (rc == 0)
246				continue;
247
248			/* Collect entries */
249			switch (type) {
250			case CEXPR_USER:
251				snprintf(tmp_buf, sizeof(tmp_buf), " %s",
252							policydb->p_user_val_to_name[i]);
253				break;
254			case CEXPR_ROLE:
255				snprintf(tmp_buf, sizeof(tmp_buf), " %s",
256							policydb->p_role_val_to_name[i]);
257				break;
258			case CEXPR_TYPE:
259				snprintf(tmp_buf, sizeof(tmp_buf), " %s",
260							policydb->p_type_val_to_name[i]);
261				break;
262			}
263			cat_expr_buf(expr_list[expr_counter], tmp_buf);
264		}
265	}
266	if (counter > 1)
267		cat_expr_buf(expr_list[expr_counter], " }");
268	if (failed)
269		cat_expr_buf(expr_list[expr_counter], " -Fail-) ");
270	else
271		cat_expr_buf(expr_list[expr_counter], ") ");
272
273	return;
274}
275
276static void msgcat(char *src, char *tgt, char *op, int failed)
277{
278	char tmp_buf[128];
279	if (failed)
280		snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Fail-) ",
281				src, op, tgt);
282	else
283		snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s) ",
284				src, op, tgt);
285	cat_expr_buf(expr_list[expr_counter], tmp_buf);
286}
287
288/* Returns a buffer with class, statement type and permissions */
289static char *get_class_info(sepol_security_class_t tclass,
290							constraint_node_t *constraint,
291							context_struct_t *xcontext)
292{
293	constraint_expr_t *e;
294	int mls, state_num;
295
296	/* Find if MLS statement or not */
297	mls = 0;
298	for (e = constraint->expr; e; e = e->next) {
299		if (e->attr >= CEXPR_L1L2) {
300			mls = 1;
301			break;
302		}
303	}
304
305	/* Determine statement type */
306	char *statements[] = {
307		"constrain ",			/* 0 */
308		"mlsconstrain ",		/* 1 */
309		"validatetrans ",		/* 2 */
310		"mlsvalidatetrans ",	/* 3 */
311		0 };
312
313	if (xcontext == NULL)
314		state_num = mls + 0;
315	else
316		state_num = mls + 2;
317
318	int class_buf_len = 0;
319	int new_class_buf_len;
320	int len, buf_used;
321	char *class_buf = NULL, *p;
322	char *new_class_buf = NULL;
323
324	while (1) {
325		new_class_buf_len = class_buf_len + EXPR_BUF_SIZE;
326		new_class_buf = realloc(class_buf, new_class_buf_len);
327			if (!new_class_buf)
328				return NULL;
329		class_buf_len = new_class_buf_len;
330		class_buf = new_class_buf;
331		buf_used = 0;
332		p = class_buf;
333
334		/* Add statement type */
335		len = snprintf(p, class_buf_len - buf_used, "%s", statements[state_num]);
336		if (len < 0 || len >= class_buf_len - buf_used)
337			continue;
338
339		/* Add class entry */
340		p += len;
341		buf_used += len;
342		len = snprintf(p, class_buf_len - buf_used, "%s ",
343				policydb->p_class_val_to_name[tclass - 1]);
344		if (len < 0 || len >= class_buf_len - buf_used)
345			continue;
346
347		/* Add permission entries */
348		p += len;
349		buf_used += len;
350		len = snprintf(p, class_buf_len - buf_used, "{%s } (",
351				sepol_av_to_string(policydb, tclass, constraint->permissions));
352		if (len < 0 || len >= class_buf_len - buf_used)
353			continue;
354		break;
355	}
356	return class_buf;
357}
358
359/*
360 * Modified version of constraint_expr_eval that will process each
361 * constraint as before but adds the information to text buffers that
362 * will hold various components. The expression will be in RPN format,
363 * therefore there is a stack based RPN to infix converter to produce
364 * the final readable constraint.
365 *
366 * Return the boolean value of a constraint expression
367 * when it is applied to the specified source and target
368 * security contexts.
369 *
370 * xcontext is a special beast...  It is used by the validatetrans rules
371 * only.  For these rules, scontext is the context before the transition,
372 * tcontext is the context after the transition, and xcontext is the
373 * context of the process performing the transition.  All other callers
374 * of constraint_expr_eval_reason should pass in NULL for xcontext.
375 *
376 * This function will also build a buffer as the constraint is processed
377 * for analysis. If this option is not required, then:
378 *      'tclass' should be '0' and r_buf MUST be NULL.
379 */
380static int constraint_expr_eval_reason(context_struct_t *scontext,
381				context_struct_t *tcontext,
382				context_struct_t *xcontext,
383				sepol_security_class_t tclass,
384				constraint_node_t *constraint,
385				char **r_buf,
386				unsigned int flags)
387{
388	uint32_t val1, val2;
389	context_struct_t *c;
390	role_datum_t *r1, *r2;
391	mls_level_t *l1, *l2;
392	constraint_expr_t *e;
393	int s[CEXPR_MAXDEPTH];
394	int sp = -1;
395	char tmp_buf[128];
396
397/*
398 * Define the s_t_x_num values that make up r1, t2 etc. in text strings
399 * Set 1 = source, 2 = target, 3 = xcontext for validatetrans
400 */
401#define SOURCE  1
402#define TARGET  2
403#define XTARGET 3
404
405	int s_t_x_num = SOURCE;
406
407	/* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */
408	int u_r_t = 0;
409
410	char *src = NULL;
411	char *tgt = NULL;
412	int rc = 0, x;
413	char *class_buf = NULL;
414
415	class_buf = get_class_info(tclass, constraint, xcontext);
416	if (!class_buf) {
417		ERR(NULL, "failed to allocate class buffer");
418		return -ENOMEM;
419	}
420
421	/* Original function but with buffer support */
422	int expr_list_len = 0;
423	expr_counter = 0;
424	expr_list = NULL;
425	for (e = constraint->expr; e; e = e->next) {
426		/* Allocate a stack to hold expression buffer entries */
427		if (expr_counter >= expr_list_len) {
428			char **new_expr_list = expr_list;
429			int new_expr_list_len;
430
431			if (expr_list_len == 0)
432				new_expr_list_len = STACK_LEN;
433			else
434				new_expr_list_len = expr_list_len * 2;
435
436			new_expr_list = realloc(expr_list,
437					new_expr_list_len * sizeof(*expr_list));
438			if (!new_expr_list) {
439				ERR(NULL, "failed to allocate expr buffer stack");
440				rc = -ENOMEM;
441				goto out;
442			}
443			expr_list_len = new_expr_list_len;
444			expr_list = new_expr_list;
445		}
446
447		/*
448		 * malloc a buffer to store each expression text component. If
449		 * buffer is too small cat_expr_buf() will realloc extra space.
450		 */
451		expr_buf_len = EXPR_BUF_SIZE;
452		expr_list[expr_counter] = malloc(expr_buf_len);
453		if (!expr_list[expr_counter]) {
454			ERR(NULL, "failed to allocate expr buffer");
455			rc = -ENOMEM;
456			goto out;
457		}
458		expr_buf_used = 0;
459
460		/* Now process each expression of the constraint */
461		switch (e->expr_type) {
462		case CEXPR_NOT:
463			BUG_ON(sp < 0);
464			s[sp] = !s[sp];
465			cat_expr_buf(expr_list[expr_counter], "not");
466			break;
467		case CEXPR_AND:
468			BUG_ON(sp < 1);
469			sp--;
470			s[sp] &= s[sp + 1];
471			cat_expr_buf(expr_list[expr_counter], "and");
472			break;
473		case CEXPR_OR:
474			BUG_ON(sp < 1);
475			sp--;
476			s[sp] |= s[sp + 1];
477			cat_expr_buf(expr_list[expr_counter], "or");
478			break;
479		case CEXPR_ATTR:
480			if (sp == (CEXPR_MAXDEPTH - 1))
481				goto out;
482
483			switch (e->attr) {
484			case CEXPR_USER:
485				val1 = scontext->user;
486				val2 = tcontext->user;
487				free(src); src = strdup("u1");
488				free(tgt); tgt = strdup("u2");
489				break;
490			case CEXPR_TYPE:
491				val1 = scontext->type;
492				val2 = tcontext->type;
493				free(src); src = strdup("t1");
494				free(tgt); tgt = strdup("t2");
495				break;
496			case CEXPR_ROLE:
497				val1 = scontext->role;
498				val2 = tcontext->role;
499				r1 = policydb->role_val_to_struct[val1 - 1];
500				r2 = policydb->role_val_to_struct[val2 - 1];
501				free(src); src = strdup("r1");
502				free(tgt); tgt = strdup("r2");
503
504				switch (e->op) {
505				case CEXPR_DOM:
506					s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1);
507					msgcat(src, tgt, "dom", s[sp] == 0);
508					expr_counter++;
509					continue;
510				case CEXPR_DOMBY:
511					s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1);
512					msgcat(src, tgt, "domby", s[sp] == 0);
513					expr_counter++;
514					continue;
515				case CEXPR_INCOMP:
516					s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1)
517						 && !ebitmap_get_bit(&r2->dominates, val1 - 1));
518					msgcat(src, tgt, "incomp", s[sp] == 0);
519					expr_counter++;
520					continue;
521				default:
522					break;
523				}
524				break;
525			case CEXPR_L1L2:
526				l1 = &(scontext->range.level[0]);
527				l2 = &(tcontext->range.level[0]);
528				free(src); src = strdup("l1");
529				free(tgt); tgt = strdup("l2");
530				goto mls_ops;
531			case CEXPR_L1H2:
532				l1 = &(scontext->range.level[0]);
533				l2 = &(tcontext->range.level[1]);
534				free(src); src = strdup("l1");
535				free(tgt); tgt = strdup("h2");
536				goto mls_ops;
537			case CEXPR_H1L2:
538				l1 = &(scontext->range.level[1]);
539				l2 = &(tcontext->range.level[0]);
540				free(src); src = strdup("h1");
541				free(tgt); tgt = strdup("l2");
542				goto mls_ops;
543			case CEXPR_H1H2:
544				l1 = &(scontext->range.level[1]);
545				l2 = &(tcontext->range.level[1]);
546				free(src); src = strdup("h1");
547				free(tgt); tgt = strdup("h2");
548				goto mls_ops;
549			case CEXPR_L1H1:
550				l1 = &(scontext->range.level[0]);
551				l2 = &(scontext->range.level[1]);
552				free(src); src = strdup("l1");
553				free(tgt); tgt = strdup("h1");
554				goto mls_ops;
555			case CEXPR_L2H2:
556				l1 = &(tcontext->range.level[0]);
557				l2 = &(tcontext->range.level[1]);
558				free(src); src = strdup("l2");
559				free(tgt); tgt = strdup("h2");
560mls_ops:
561				switch (e->op) {
562				case CEXPR_EQ:
563					s[++sp] = mls_level_eq(l1, l2);
564					msgcat(src, tgt, "eq", s[sp] == 0);
565					expr_counter++;
566					continue;
567				case CEXPR_NEQ:
568					s[++sp] = !mls_level_eq(l1, l2);
569					msgcat(src, tgt, "!=", s[sp] == 0);
570					expr_counter++;
571					continue;
572				case CEXPR_DOM:
573					s[++sp] = mls_level_dom(l1, l2);
574					msgcat(src, tgt, "dom", s[sp] == 0);
575					expr_counter++;
576					continue;
577				case CEXPR_DOMBY:
578					s[++sp] = mls_level_dom(l2, l1);
579					msgcat(src, tgt, "domby", s[sp] == 0);
580					expr_counter++;
581					continue;
582				case CEXPR_INCOMP:
583					s[++sp] = mls_level_incomp(l2, l1);
584					msgcat(src, tgt, "incomp", s[sp] == 0);
585					expr_counter++;
586					continue;
587				default:
588					BUG();
589					goto out;
590				}
591				break;
592			default:
593				BUG();
594				goto out;
595			}
596
597			switch (e->op) {
598			case CEXPR_EQ:
599				s[++sp] = (val1 == val2);
600				msgcat(src, tgt, "==", s[sp] == 0);
601				break;
602			case CEXPR_NEQ:
603				s[++sp] = (val1 != val2);
604				msgcat(src, tgt, "!=", s[sp] == 0);
605				break;
606			default:
607				BUG();
608				goto out;
609			}
610			break;
611		case CEXPR_NAMES:
612			if (sp == (CEXPR_MAXDEPTH - 1))
613				goto out;
614			s_t_x_num = SOURCE;
615			c = scontext;
616			if (e->attr & CEXPR_TARGET) {
617				s_t_x_num = TARGET;
618				c = tcontext;
619			} else if (e->attr & CEXPR_XTARGET) {
620				s_t_x_num = XTARGET;
621				c = xcontext;
622			}
623			if (!c) {
624				BUG();
625				goto out;
626			}
627			if (e->attr & CEXPR_USER) {
628				u_r_t = CEXPR_USER;
629				val1 = c->user;
630				snprintf(tmp_buf, sizeof(tmp_buf), "u%d ", s_t_x_num);
631				free(src); src = strdup(tmp_buf);
632			} else if (e->attr & CEXPR_ROLE) {
633				u_r_t = CEXPR_ROLE;
634				val1 = c->role;
635				snprintf(tmp_buf, sizeof(tmp_buf), "r%d ", s_t_x_num);
636				free(src); src = strdup(tmp_buf);
637			} else if (e->attr & CEXPR_TYPE) {
638				u_r_t = CEXPR_TYPE;
639				val1 = c->type;
640				snprintf(tmp_buf, sizeof(tmp_buf), "t%d ", s_t_x_num);
641				free(src); src = strdup(tmp_buf);
642			} else {
643				BUG();
644				goto out;
645			}
646
647			switch (e->op) {
648			case CEXPR_EQ:
649				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
650				get_name_list(e, u_r_t, src, "==", s[sp] == 0);
651				break;
652
653			case CEXPR_NEQ:
654				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
655				get_name_list(e, u_r_t, src, "!=", s[sp] == 0);
656				break;
657			default:
658				BUG();
659				goto out;
660			}
661			break;
662		default:
663			BUG();
664			goto out;
665		}
666		expr_counter++;
667	}
668
669	/*
670	 * At this point each expression of the constraint is in
671	 * expr_list[n+1] and in RPN format. Now convert to 'infix'
672	 */
673
674	/*
675	 * Save expr count but zero expr_counter to detect if
676	 * 'BUG(); goto out;' was called as we need to release any used
677	 * expr_list malloc's. Normally they are released by the RPN to
678	 * infix code.
679	 */
680	int expr_count = expr_counter;
681	expr_counter = 0;
682
683	/*
684	 * The array of expression answer buffer pointers and counter.
685	 * Generate the same number of answer buffer entries as expression
686	 * buffers (as there will never be more).
687	 */
688	char **answer_list;
689	int answer_counter = 0;
690
691	answer_list = malloc(expr_count * sizeof(*answer_list));
692	if (!answer_list) {
693		ERR(NULL, "failed to allocate answer stack");
694		rc = -ENOMEM;
695		goto out;
696	}
697
698	/* The pop operands */
699	char *a;
700	char *b;
701	int a_len, b_len;
702
703	/* Convert constraint from RPN to infix notation. */
704	for (x = 0; x != expr_count; x++) {
705		if (strncmp(expr_list[x], "and", 3) == 0 || strncmp(expr_list[x],
706					"or", 2) == 0) {
707			b = pop();
708			b_len = strlen(b);
709			a = pop();
710			a_len = strlen(a);
711
712			/* get a buffer to hold the answer */
713			answer_list[answer_counter] = malloc(a_len + b_len + 8);
714			if (!answer_list[answer_counter]) {
715				ERR(NULL, "failed to allocate answer buffer");
716				rc = -ENOMEM;
717				goto out;
718			}
719			memset(answer_list[answer_counter], '\0', a_len + b_len + 8);
720
721			sprintf(answer_list[answer_counter], "%s %s %s", a,
722					expr_list[x], b);
723			push(answer_list[answer_counter++]);
724			free(a);
725			free(b);
726		} else if (strncmp(expr_list[x], "not", 3) == 0) {
727			b = pop();
728			b_len = strlen(b);
729
730			answer_list[answer_counter] = malloc(b_len + 8);
731			if (!answer_list[answer_counter]) {
732				ERR(NULL, "failed to allocate answer buffer");
733				rc = -ENOMEM;
734				goto out;
735			}
736			memset(answer_list[answer_counter], '\0', b_len + 8);
737
738			if (strncmp(b, "not", 3) == 0)
739				sprintf(answer_list[answer_counter], "%s (%s)",
740						expr_list[x], b);
741			else
742				sprintf(answer_list[answer_counter], "%s%s",
743						expr_list[x], b);
744			push(answer_list[answer_counter++]);
745			free(b);
746		} else {
747			push(expr_list[x]);
748		}
749	}
750	/* Get the final answer from tos and build constraint text */
751	a = pop();
752
753	/* Constraint calculation: rc = 0 is denied, rc = 1 is granted */
754	sprintf(tmp_buf, "Constraint %s\n", s[0] ? "GRANTED" : "DENIED");
755
756	int len, new_buf_len;
757	char *p, **new_buf = r_buf;
758	/*
759	 * These contain the constraint components that are added to the
760	 * callers reason buffer.
761	 */
762	char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 };
763
764	/*
765	 * This will add the constraints to the callers reason buffer (who is
766	 * responsible for freeing the memory). It will handle any realloc's
767	 * should the buffer be too short.
768	 * The reason_buf_used and reason_buf_len counters are defined
769	 * globally as multiple constraints can be in the buffer.
770	 */
771
772	if (r_buf && ((s[0] == 0) || ((s[0] == 1 &&
773				(flags & SHOW_GRANTED) == SHOW_GRANTED)))) {
774		for (x = 0; buffers[x] != NULL; x++) {
775			while (1) {
776				p = *r_buf + reason_buf_used;
777				len = snprintf(p, reason_buf_len - reason_buf_used,
778						"%s", buffers[x]);
779				if (len < 0 || len >= reason_buf_len - reason_buf_used) {
780					new_buf_len = reason_buf_len + REASON_BUF_SIZE;
781					*new_buf = realloc(*r_buf, new_buf_len);
782					if (!new_buf) {
783						ERR(NULL, "failed to realloc reason buffer");
784						goto out1;
785					}
786					**r_buf = **new_buf;
787					reason_buf_len = new_buf_len;
788					continue;
789				} else {
790					reason_buf_used += len;
791					break;
792				}
793			}
794		}
795	}
796
797out1:
798	rc = s[0];
799	free(a);
800
801out:
802	free(class_buf);
803	free(src);
804	free(tgt);
805
806	if (expr_counter) {
807		for (x = 0; expr_list[x] != NULL; x++)
808			free(expr_list[x]);
809	}
810	return rc;
811}
812
813/*
814 * Compute access vectors based on a context structure pair for
815 * the permissions in a particular class.
816 */
817static int context_struct_compute_av(context_struct_t * scontext,
818				     context_struct_t * tcontext,
819				     sepol_security_class_t tclass,
820				     sepol_access_vector_t requested,
821				     struct sepol_av_decision *avd,
822				     unsigned int *reason,
823				     char **r_buf,
824					 unsigned int flags)
825{
826	constraint_node_t *constraint;
827	struct role_allow *ra;
828	avtab_key_t avkey;
829	class_datum_t *tclass_datum;
830	avtab_ptr_t node;
831	ebitmap_t *sattr, *tattr;
832	ebitmap_node_t *snode, *tnode;
833	unsigned int i, j;
834
835	if (!tclass || tclass > policydb->p_classes.nprim) {
836		ERR(NULL, "unrecognized class %d", tclass);
837		return -EINVAL;
838	}
839	tclass_datum = policydb->class_val_to_struct[tclass - 1];
840
841	/*
842	 * Initialize the access vectors to the default values.
843	 */
844	avd->allowed = 0;
845	avd->decided = 0xffffffff;
846	avd->auditallow = 0;
847	avd->auditdeny = 0xffffffff;
848	avd->seqno = latest_granting;
849	*reason = 0;
850
851	/*
852	 * If a specific type enforcement rule was defined for
853	 * this permission check, then use it.
854	 */
855	avkey.target_class = tclass;
856	avkey.specified = AVTAB_AV;
857	sattr = &policydb->type_attr_map[scontext->type - 1];
858	tattr = &policydb->type_attr_map[tcontext->type - 1];
859	ebitmap_for_each_bit(sattr, snode, i) {
860		if (!ebitmap_node_get_bit(snode, i))
861			continue;
862		ebitmap_for_each_bit(tattr, tnode, j) {
863			if (!ebitmap_node_get_bit(tnode, j))
864				continue;
865			avkey.source_type = i + 1;
866			avkey.target_type = j + 1;
867			for (node =
868			     avtab_search_node(&policydb->te_avtab, &avkey);
869			     node != NULL;
870			     node =
871			     avtab_search_node_next(node, avkey.specified)) {
872				if (node->key.specified == AVTAB_ALLOWED)
873					avd->allowed |= node->datum.data;
874				else if (node->key.specified ==
875					 AVTAB_AUDITALLOW)
876					avd->auditallow |= node->datum.data;
877				else if (node->key.specified == AVTAB_AUDITDENY)
878					avd->auditdeny &= node->datum.data;
879			}
880
881			/* Check conditional av table for additional permissions */
882			cond_compute_av(&policydb->te_cond_avtab, &avkey, avd);
883
884		}
885	}
886
887	if (requested & ~avd->allowed) {
888		*reason |= SEPOL_COMPUTEAV_TE;
889		requested &= avd->allowed;
890	}
891
892	/*
893	 * Remove any permissions prohibited by a constraint (this includes
894	 * the MLS policy).
895	 */
896	constraint = tclass_datum->constraints;
897	while (constraint) {
898		if ((constraint->permissions & (avd->allowed)) &&
899		    !constraint_expr_eval_reason(scontext, tcontext, NULL,
900					  tclass, constraint, r_buf, flags)) {
901			avd->allowed =
902			    (avd->allowed) & ~(constraint->permissions);
903		}
904		constraint = constraint->next;
905	}
906
907	if (requested & ~avd->allowed) {
908		*reason |= SEPOL_COMPUTEAV_CONS;
909		requested &= avd->allowed;
910	}
911
912	/*
913	 * If checking process transition permission and the
914	 * role is changing, then check the (current_role, new_role)
915	 * pair.
916	 */
917	if (tclass == SECCLASS_PROCESS &&
918	    (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
919	    scontext->role != tcontext->role) {
920		for (ra = policydb->role_allow; ra; ra = ra->next) {
921			if (scontext->role == ra->role &&
922			    tcontext->role == ra->new_role)
923				break;
924		}
925		if (!ra)
926			avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
927							  PROCESS__DYNTRANSITION);
928	}
929
930	if (requested & ~avd->allowed) {
931		*reason |= SEPOL_COMPUTEAV_RBAC;
932		requested &= avd->allowed;
933	}
934
935	return 0;
936}
937
938int hidden sepol_validate_transition(sepol_security_id_t oldsid,
939				     sepol_security_id_t newsid,
940				     sepol_security_id_t tasksid,
941				     sepol_security_class_t tclass)
942{
943	context_struct_t *ocontext;
944	context_struct_t *ncontext;
945	context_struct_t *tcontext;
946	class_datum_t *tclass_datum;
947	constraint_node_t *constraint;
948
949	if (!tclass || tclass > policydb->p_classes.nprim) {
950		ERR(NULL, "unrecognized class %d", tclass);
951		return -EINVAL;
952	}
953	tclass_datum = policydb->class_val_to_struct[tclass - 1];
954
955	ocontext = sepol_sidtab_search(sidtab, oldsid);
956	if (!ocontext) {
957		ERR(NULL, "unrecognized SID %d", oldsid);
958		return -EINVAL;
959	}
960
961	ncontext = sepol_sidtab_search(sidtab, newsid);
962	if (!ncontext) {
963		ERR(NULL, "unrecognized SID %d", newsid);
964		return -EINVAL;
965	}
966
967	tcontext = sepol_sidtab_search(sidtab, tasksid);
968	if (!tcontext) {
969		ERR(NULL, "unrecognized SID %d", tasksid);
970		return -EINVAL;
971	}
972
973	constraint = tclass_datum->validatetrans;
974	while (constraint) {
975		if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext,
976					  0, constraint, NULL, 0)) {
977			return -EPERM;
978		}
979		constraint = constraint->next;
980	}
981
982	return 0;
983}
984
985int hidden sepol_compute_av_reason(sepol_security_id_t ssid,
986				   sepol_security_id_t tsid,
987				   sepol_security_class_t tclass,
988				   sepol_access_vector_t requested,
989				   struct sepol_av_decision *avd,
990				   unsigned int *reason)
991{
992	context_struct_t *scontext = 0, *tcontext = 0;
993	int rc = 0;
994
995	scontext = sepol_sidtab_search(sidtab, ssid);
996	if (!scontext) {
997		ERR(NULL, "unrecognized SID %d", ssid);
998		rc = -EINVAL;
999		goto out;
1000	}
1001	tcontext = sepol_sidtab_search(sidtab, tsid);
1002	if (!tcontext) {
1003		ERR(NULL, "unrecognized SID %d", tsid);
1004		rc = -EINVAL;
1005		goto out;
1006	}
1007
1008	rc = context_struct_compute_av(scontext, tcontext, tclass,
1009					requested, avd, reason, NULL, 0);
1010      out:
1011	return rc;
1012}
1013
1014/*
1015 * sepol_compute_av_reason_buffer - the reason buffer is malloc'd to
1016 * REASON_BUF_SIZE. If the buffer size is exceeded, then it is realloc'd
1017 * in the constraint_expr_eval_reason() function.
1018 */
1019int hidden sepol_compute_av_reason_buffer(sepol_security_id_t ssid,
1020				   sepol_security_id_t tsid,
1021				   sepol_security_class_t tclass,
1022				   sepol_access_vector_t requested,
1023				   struct sepol_av_decision *avd,
1024				   unsigned int *reason,
1025				   char **reason_buf,
1026				   unsigned int flags)
1027{
1028	context_struct_t *scontext = 0, *tcontext = 0;
1029	int rc = 0;
1030
1031	scontext = sepol_sidtab_search(sidtab, ssid);
1032	if (!scontext) {
1033		ERR(NULL, "unrecognized SID %d", ssid);
1034		rc = -EINVAL;
1035		goto out;
1036	}
1037	tcontext = sepol_sidtab_search(sidtab, tsid);
1038	if (!tcontext) {
1039		ERR(NULL, "unrecognized SID %d", tsid);
1040		rc = -EINVAL;
1041		goto out;
1042	}
1043
1044	/*
1045	 * Set the buffer to NULL as constraints may not be processed.
1046	 * If a buffer is required, then the routines in
1047	 * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE
1048	 * chunks (as it gets called for each constraint processed).
1049	 * We just make sure these start from zero.
1050	 */
1051	*reason_buf = NULL;
1052	reason_buf_used = 0;
1053	reason_buf_len = 0;
1054
1055	rc = context_struct_compute_av(scontext, tcontext, tclass,
1056					   requested, avd, reason, reason_buf, flags);
1057out:
1058	return rc;
1059}
1060
1061int hidden sepol_compute_av(sepol_security_id_t ssid,
1062			    sepol_security_id_t tsid,
1063			    sepol_security_class_t tclass,
1064			    sepol_access_vector_t requested,
1065			    struct sepol_av_decision *avd)
1066{
1067	unsigned int reason = 0;
1068	return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd,
1069				       &reason);
1070}
1071
1072/*
1073 * Return a class ID associated with the class string specified by
1074 * class_name.
1075 */
1076int hidden sepol_string_to_security_class(const char *class_name,
1077			sepol_security_class_t *tclass)
1078{
1079	char *class = NULL;
1080	sepol_security_class_t id;
1081
1082	for (id = 1;; id++) {
1083		class = policydb->p_class_val_to_name[id - 1];
1084		if (class == NULL) {
1085			ERR(NULL, "could not convert %s to class id", class_name);
1086			return STATUS_ERR;
1087		}
1088		if ((strcmp(class, class_name)) == 0) {
1089			*tclass = id;
1090			return STATUS_SUCCESS;
1091		}
1092	}
1093}
1094
1095/*
1096 * Return access vector bit associated with the class ID and permission
1097 * string.
1098 */
1099int hidden sepol_string_to_av_perm(sepol_security_class_t tclass,
1100					const char *perm_name,
1101					sepol_access_vector_t *av)
1102{
1103	class_datum_t *tclass_datum;
1104	perm_datum_t *perm_datum;
1105
1106	if (!tclass || tclass > policydb->p_classes.nprim) {
1107		ERR(NULL, "unrecognized class %d", tclass);
1108		return -EINVAL;
1109	}
1110	tclass_datum = policydb->class_val_to_struct[tclass - 1];
1111
1112	/* Check for unique perms then the common ones (if any) */
1113	perm_datum = (perm_datum_t *)
1114			hashtab_search(tclass_datum->permissions.table,
1115			(hashtab_key_t)perm_name);
1116	if (perm_datum != NULL) {
1117		*av = 0x1 << (perm_datum->s.value - 1);
1118		return STATUS_SUCCESS;
1119	}
1120
1121	if (tclass_datum->comdatum == NULL)
1122		goto out;
1123
1124	perm_datum = (perm_datum_t *)
1125			hashtab_search(tclass_datum->comdatum->permissions.table,
1126			(hashtab_key_t)perm_name);
1127
1128	if (perm_datum != NULL) {
1129		*av = 0x1 << (perm_datum->s.value - 1);
1130		return STATUS_SUCCESS;
1131	}
1132out:
1133	ERR(NULL, "could not convert %s to av bit", perm_name);
1134	return STATUS_ERR;
1135}
1136
1137/*
1138 * Write the security context string representation of
1139 * the context associated with `sid' into a dynamically
1140 * allocated string of the correct size.  Set `*scontext'
1141 * to point to this string and set `*scontext_len' to
1142 * the length of the string.
1143 */
1144int hidden sepol_sid_to_context(sepol_security_id_t sid,
1145				sepol_security_context_t * scontext,
1146				size_t * scontext_len)
1147{
1148	context_struct_t *context;
1149	int rc = 0;
1150
1151	context = sepol_sidtab_search(sidtab, sid);
1152	if (!context) {
1153		ERR(NULL, "unrecognized SID %d", sid);
1154		rc = -EINVAL;
1155		goto out;
1156	}
1157	rc = context_to_string(NULL, policydb, context, scontext, scontext_len);
1158      out:
1159	return rc;
1160
1161}
1162
1163/*
1164 * Return a SID associated with the security context that
1165 * has the string representation specified by `scontext'.
1166 */
1167int hidden sepol_context_to_sid(const sepol_security_context_t scontext,
1168				size_t scontext_len, sepol_security_id_t * sid)
1169{
1170
1171	context_struct_t *context = NULL;
1172
1173	/* First, create the context */
1174	if (context_from_string(NULL, policydb, &context,
1175				scontext, scontext_len) < 0)
1176		goto err;
1177
1178	/* Obtain the new sid */
1179	if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0))
1180		goto err;
1181
1182	context_destroy(context);
1183	free(context);
1184	return STATUS_SUCCESS;
1185
1186      err:
1187	if (context) {
1188		context_destroy(context);
1189		free(context);
1190	}
1191	ERR(NULL, "could not convert %s to sid", scontext);
1192	return STATUS_ERR;
1193}
1194
1195static inline int compute_sid_handle_invalid_context(context_struct_t *
1196						     scontext,
1197						     context_struct_t *
1198						     tcontext,
1199						     sepol_security_class_t
1200						     tclass,
1201						     context_struct_t *
1202						     newcontext)
1203{
1204	if (selinux_enforcing) {
1205		return -EACCES;
1206	} else {
1207		sepol_security_context_t s, t, n;
1208		size_t slen, tlen, nlen;
1209
1210		context_to_string(NULL, policydb, scontext, &s, &slen);
1211		context_to_string(NULL, policydb, tcontext, &t, &tlen);
1212		context_to_string(NULL, policydb, newcontext, &n, &nlen);
1213		ERR(NULL, "invalid context %s for "
1214		    "scontext=%s tcontext=%s tclass=%s",
1215		    n, s, t, policydb->p_class_val_to_name[tclass - 1]);
1216		free(s);
1217		free(t);
1218		free(n);
1219		return 0;
1220	}
1221}
1222
1223static int sepol_compute_sid(sepol_security_id_t ssid,
1224			     sepol_security_id_t tsid,
1225			     sepol_security_class_t tclass,
1226			     uint32_t specified, sepol_security_id_t * out_sid)
1227{
1228	context_struct_t *scontext = 0, *tcontext = 0, newcontext;
1229	struct role_trans *roletr = 0;
1230	avtab_key_t avkey;
1231	avtab_datum_t *avdatum;
1232	avtab_ptr_t node;
1233	int rc = 0;
1234
1235	scontext = sepol_sidtab_search(sidtab, ssid);
1236	if (!scontext) {
1237		ERR(NULL, "unrecognized SID %d", ssid);
1238		rc = -EINVAL;
1239		goto out;
1240	}
1241	tcontext = sepol_sidtab_search(sidtab, tsid);
1242	if (!tcontext) {
1243		ERR(NULL, "unrecognized SID %d", tsid);
1244		rc = -EINVAL;
1245		goto out;
1246	}
1247
1248	context_init(&newcontext);
1249
1250	/* Set the user identity. */
1251	switch (specified) {
1252	case AVTAB_TRANSITION:
1253	case AVTAB_CHANGE:
1254		/* Use the process user identity. */
1255		newcontext.user = scontext->user;
1256		break;
1257	case AVTAB_MEMBER:
1258		/* Use the related object owner. */
1259		newcontext.user = tcontext->user;
1260		break;
1261	}
1262
1263	/* Set the role and type to default values. */
1264	switch (tclass) {
1265	case SECCLASS_PROCESS:
1266		/* Use the current role and type of process. */
1267		newcontext.role = scontext->role;
1268		newcontext.type = scontext->type;
1269		break;
1270	default:
1271		/* Use the well-defined object role. */
1272		newcontext.role = OBJECT_R_VAL;
1273		/* Use the type of the related object. */
1274		newcontext.type = tcontext->type;
1275	}
1276
1277	/* Look for a type transition/member/change rule. */
1278	avkey.source_type = scontext->type;
1279	avkey.target_type = tcontext->type;
1280	avkey.target_class = tclass;
1281	avkey.specified = specified;
1282	avdatum = avtab_search(&policydb->te_avtab, &avkey);
1283
1284	/* If no permanent rule, also check for enabled conditional rules */
1285	if (!avdatum) {
1286		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1287		for (; node != NULL;
1288		     node = avtab_search_node_next(node, specified)) {
1289			if (node->key.specified & AVTAB_ENABLED) {
1290				avdatum = &node->datum;
1291				break;
1292			}
1293		}
1294	}
1295
1296	if (avdatum) {
1297		/* Use the type from the type transition/member/change rule. */
1298		newcontext.type = avdatum->data;
1299	}
1300
1301	/* Check for class-specific changes. */
1302	switch (tclass) {
1303	case SECCLASS_PROCESS:
1304		if (specified & AVTAB_TRANSITION) {
1305			/* Look for a role transition rule. */
1306			for (roletr = policydb->role_tr; roletr;
1307			     roletr = roletr->next) {
1308				if (roletr->role == scontext->role &&
1309				    roletr->type == tcontext->type) {
1310					/* Use the role transition rule. */
1311					newcontext.role = roletr->new_role;
1312					break;
1313				}
1314			}
1315		}
1316		break;
1317	default:
1318		break;
1319	}
1320
1321	/* Set the MLS attributes.
1322	   This is done last because it may allocate memory. */
1323	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
1324			     &newcontext);
1325	if (rc)
1326		goto out;
1327
1328	/* Check the validity of the context. */
1329	if (!policydb_context_isvalid(policydb, &newcontext)) {
1330		rc = compute_sid_handle_invalid_context(scontext,
1331							tcontext,
1332							tclass, &newcontext);
1333		if (rc)
1334			goto out;
1335	}
1336	/* Obtain the sid for the context. */
1337	rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid);
1338      out:
1339	context_destroy(&newcontext);
1340	return rc;
1341}
1342
1343/*
1344 * Compute a SID to use for labeling a new object in the
1345 * class `tclass' based on a SID pair.
1346 */
1347int hidden sepol_transition_sid(sepol_security_id_t ssid,
1348				sepol_security_id_t tsid,
1349				sepol_security_class_t tclass,
1350				sepol_security_id_t * out_sid)
1351{
1352	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
1353}
1354
1355/*
1356 * Compute a SID to use when selecting a member of a
1357 * polyinstantiated object of class `tclass' based on
1358 * a SID pair.
1359 */
1360int hidden sepol_member_sid(sepol_security_id_t ssid,
1361			    sepol_security_id_t tsid,
1362			    sepol_security_class_t tclass,
1363			    sepol_security_id_t * out_sid)
1364{
1365	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
1366}
1367
1368/*
1369 * Compute a SID to use for relabeling an object in the
1370 * class `tclass' based on a SID pair.
1371 */
1372int hidden sepol_change_sid(sepol_security_id_t ssid,
1373			    sepol_security_id_t tsid,
1374			    sepol_security_class_t tclass,
1375			    sepol_security_id_t * out_sid)
1376{
1377	return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
1378}
1379
1380/*
1381 * Verify that each permission that is defined under the
1382 * existing policy is still defined with the same value
1383 * in the new policy.
1384 */
1385static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
1386{
1387	hashtab_t h;
1388	perm_datum_t *perdatum, *perdatum2;
1389
1390	h = (hashtab_t) p;
1391	perdatum = (perm_datum_t *) datum;
1392
1393	perdatum2 = (perm_datum_t *) hashtab_search(h, key);
1394	if (!perdatum2) {
1395		ERR(NULL, "permission %s disappeared", key);
1396		return -1;
1397	}
1398	if (perdatum->s.value != perdatum2->s.value) {
1399		ERR(NULL, "the value of permissions %s changed", key);
1400		return -1;
1401	}
1402	return 0;
1403}
1404
1405/*
1406 * Verify that each class that is defined under the
1407 * existing policy is still defined with the same
1408 * attributes in the new policy.
1409 */
1410static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p)
1411{
1412	policydb_t *newp;
1413	class_datum_t *cladatum, *cladatum2;
1414
1415	newp = (policydb_t *) p;
1416	cladatum = (class_datum_t *) datum;
1417
1418	cladatum2 =
1419	    (class_datum_t *) hashtab_search(newp->p_classes.table, key);
1420	if (!cladatum2) {
1421		ERR(NULL, "class %s disappeared", key);
1422		return -1;
1423	}
1424	if (cladatum->s.value != cladatum2->s.value) {
1425		ERR(NULL, "the value of class %s changed", key);
1426		return -1;
1427	}
1428	if ((cladatum->comdatum && !cladatum2->comdatum) ||
1429	    (!cladatum->comdatum && cladatum2->comdatum)) {
1430		ERR(NULL, "the inherits clause for the access "
1431		    "vector definition for class %s changed", key);
1432		return -1;
1433	}
1434	if (cladatum->comdatum) {
1435		if (hashtab_map
1436		    (cladatum->comdatum->permissions.table, validate_perm,
1437		     cladatum2->comdatum->permissions.table)) {
1438			ERR(NULL,
1439			    " in the access vector definition "
1440			    "for class %s\n", key);
1441			return -1;
1442		}
1443	}
1444	if (hashtab_map(cladatum->permissions.table, validate_perm,
1445			cladatum2->permissions.table)) {
1446		ERR(NULL, " in access vector definition for class %s", key);
1447		return -1;
1448	}
1449	return 0;
1450}
1451
1452/* Clone the SID into the new SID table. */
1453static int clone_sid(sepol_security_id_t sid,
1454		     context_struct_t * context, void *arg)
1455{
1456	sidtab_t *s = arg;
1457
1458	return sepol_sidtab_insert(s, sid, context);
1459}
1460
1461static inline int convert_context_handle_invalid_context(context_struct_t *
1462							 context)
1463{
1464	if (selinux_enforcing) {
1465		return -EINVAL;
1466	} else {
1467		sepol_security_context_t s;
1468		size_t len;
1469
1470		context_to_string(NULL, policydb, context, &s, &len);
1471		ERR(NULL, "context %s is invalid", s);
1472		free(s);
1473		return 0;
1474	}
1475}
1476
1477typedef struct {
1478	policydb_t *oldp;
1479	policydb_t *newp;
1480} convert_context_args_t;
1481
1482/*
1483 * Convert the values in the security context
1484 * structure `c' from the values specified
1485 * in the policy `p->oldp' to the values specified
1486 * in the policy `p->newp'.  Verify that the
1487 * context is valid under the new policy.
1488 */
1489static int convert_context(sepol_security_id_t key __attribute__ ((unused)),
1490			   context_struct_t * c, void *p)
1491{
1492	convert_context_args_t *args;
1493	context_struct_t oldc;
1494	role_datum_t *role;
1495	type_datum_t *typdatum;
1496	user_datum_t *usrdatum;
1497	sepol_security_context_t s;
1498	size_t len;
1499	int rc = -EINVAL;
1500
1501	args = (convert_context_args_t *) p;
1502
1503	if (context_cpy(&oldc, c))
1504		return -ENOMEM;
1505
1506	/* Convert the user. */
1507	usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table,
1508						   args->oldp->
1509						   p_user_val_to_name[c->user -
1510								      1]);
1511
1512	if (!usrdatum) {
1513		goto bad;
1514	}
1515	c->user = usrdatum->s.value;
1516
1517	/* Convert the role. */
1518	role = (role_datum_t *) hashtab_search(args->newp->p_roles.table,
1519					       args->oldp->
1520					       p_role_val_to_name[c->role - 1]);
1521	if (!role) {
1522		goto bad;
1523	}
1524	c->role = role->s.value;
1525
1526	/* Convert the type. */
1527	typdatum = (type_datum_t *)
1528	    hashtab_search(args->newp->p_types.table,
1529			   args->oldp->p_type_val_to_name[c->type - 1]);
1530	if (!typdatum) {
1531		goto bad;
1532	}
1533	c->type = typdatum->s.value;
1534
1535	rc = mls_convert_context(args->oldp, args->newp, c);
1536	if (rc)
1537		goto bad;
1538
1539	/* Check the validity of the new context. */
1540	if (!policydb_context_isvalid(args->newp, c)) {
1541		rc = convert_context_handle_invalid_context(&oldc);
1542		if (rc)
1543			goto bad;
1544	}
1545
1546	context_destroy(&oldc);
1547	return 0;
1548
1549      bad:
1550	context_to_string(NULL, policydb, &oldc, &s, &len);
1551	context_destroy(&oldc);
1552	ERR(NULL, "invalidating context %s", s);
1553	free(s);
1554	return rc;
1555}
1556
1557/* Reading from a policy "file". */
1558int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes)
1559{
1560	size_t nread;
1561
1562	switch (fp->type) {
1563	case PF_USE_STDIO:
1564		nread = fread(buf, bytes, 1, fp->fp);
1565
1566		if (nread != 1)
1567			return -1;
1568		break;
1569	case PF_USE_MEMORY:
1570		if (bytes > fp->len)
1571			return -1;
1572		memcpy(buf, fp->data, bytes);
1573		fp->data += bytes;
1574		fp->len -= bytes;
1575		break;
1576	default:
1577		return -1;
1578	}
1579	return 0;
1580}
1581
1582size_t hidden put_entry(const void *ptr, size_t size, size_t n,
1583			struct policy_file *fp)
1584{
1585	size_t bytes = size * n;
1586
1587	switch (fp->type) {
1588	case PF_USE_STDIO:
1589		return fwrite(ptr, size, n, fp->fp);
1590	case PF_USE_MEMORY:
1591		if (bytes > fp->len) {
1592			errno = ENOSPC;
1593			return 0;
1594		}
1595
1596		memcpy(fp->data, ptr, bytes);
1597		fp->data += bytes;
1598		fp->len -= bytes;
1599		return n;
1600	case PF_LEN:
1601		fp->len += bytes;
1602		return n;
1603	default:
1604		return 0;
1605	}
1606	return 0;
1607}
1608
1609/*
1610 * Read a new set of configuration data from
1611 * a policy database binary representation file.
1612 *
1613 * Verify that each class that is defined under the
1614 * existing policy is still defined with the same
1615 * attributes in the new policy.
1616 *
1617 * Convert the context structures in the SID table to the
1618 * new representation and verify that all entries
1619 * in the SID table are valid under the new policy.
1620 *
1621 * Change the active policy database to use the new
1622 * configuration data.
1623 *
1624 * Reset the access vector cache.
1625 */
1626int hidden sepol_load_policy(void *data, size_t len)
1627{
1628	policydb_t oldpolicydb, newpolicydb;
1629	sidtab_t oldsidtab, newsidtab;
1630	convert_context_args_t args;
1631	int rc = 0;
1632	struct policy_file file, *fp;
1633
1634	policy_file_init(&file);
1635	file.type = PF_USE_MEMORY;
1636	file.data = data;
1637	file.len = len;
1638	fp = &file;
1639
1640	if (policydb_init(&newpolicydb))
1641		return -ENOMEM;
1642
1643	if (policydb_read(&newpolicydb, fp, 1)) {
1644		policydb_destroy(&mypolicydb);
1645		return -EINVAL;
1646	}
1647
1648	sepol_sidtab_init(&newsidtab);
1649
1650	/* Verify that the existing classes did not change. */
1651	if (hashtab_map
1652	    (policydb->p_classes.table, validate_class, &newpolicydb)) {
1653		ERR(NULL, "the definition of an existing class changed");
1654		rc = -EINVAL;
1655		goto err;
1656	}
1657
1658	/* Clone the SID table. */
1659	sepol_sidtab_shutdown(sidtab);
1660	if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) {
1661		rc = -ENOMEM;
1662		goto err;
1663	}
1664
1665	/* Convert the internal representations of contexts
1666	   in the new SID table and remove invalid SIDs. */
1667	args.oldp = policydb;
1668	args.newp = &newpolicydb;
1669	sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
1670
1671	/* Save the old policydb and SID table to free later. */
1672	memcpy(&oldpolicydb, policydb, sizeof *policydb);
1673	sepol_sidtab_set(&oldsidtab, sidtab);
1674
1675	/* Install the new policydb and SID table. */
1676	memcpy(policydb, &newpolicydb, sizeof *policydb);
1677	sepol_sidtab_set(sidtab, &newsidtab);
1678
1679	/* Free the old policydb and SID table. */
1680	policydb_destroy(&oldpolicydb);
1681	sepol_sidtab_destroy(&oldsidtab);
1682
1683	return 0;
1684
1685      err:
1686	sepol_sidtab_destroy(&newsidtab);
1687	policydb_destroy(&newpolicydb);
1688	return rc;
1689
1690}
1691
1692/*
1693 * Return the SIDs to use for an unlabeled file system
1694 * that is being mounted from the device with the
1695 * the kdevname `name'.  The `fs_sid' SID is returned for
1696 * the file system and the `file_sid' SID is returned
1697 * for all files within that file system.
1698 */
1699int hidden sepol_fs_sid(char *name,
1700			sepol_security_id_t * fs_sid,
1701			sepol_security_id_t * file_sid)
1702{
1703	int rc = 0;
1704	ocontext_t *c;
1705
1706	c = policydb->ocontexts[OCON_FS];
1707	while (c) {
1708		if (strcmp(c->u.name, name) == 0)
1709			break;
1710		c = c->next;
1711	}
1712
1713	if (c) {
1714		if (!c->sid[0] || !c->sid[1]) {
1715			rc = sepol_sidtab_context_to_sid(sidtab,
1716							 &c->context[0],
1717							 &c->sid[0]);
1718			if (rc)
1719				goto out;
1720			rc = sepol_sidtab_context_to_sid(sidtab,
1721							 &c->context[1],
1722							 &c->sid[1]);
1723			if (rc)
1724				goto out;
1725		}
1726		*fs_sid = c->sid[0];
1727		*file_sid = c->sid[1];
1728	} else {
1729		*fs_sid = SECINITSID_FS;
1730		*file_sid = SECINITSID_FILE;
1731	}
1732
1733      out:
1734	return rc;
1735}
1736
1737/*
1738 * Return the SID of the port specified by
1739 * `domain', `type', `protocol', and `port'.
1740 */
1741int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)),
1742			  uint16_t type __attribute__ ((unused)),
1743			  uint8_t protocol,
1744			  uint16_t port, sepol_security_id_t * out_sid)
1745{
1746	ocontext_t *c;
1747	int rc = 0;
1748
1749	c = policydb->ocontexts[OCON_PORT];
1750	while (c) {
1751		if (c->u.port.protocol == protocol &&
1752		    c->u.port.low_port <= port && c->u.port.high_port >= port)
1753			break;
1754		c = c->next;
1755	}
1756
1757	if (c) {
1758		if (!c->sid[0]) {
1759			rc = sepol_sidtab_context_to_sid(sidtab,
1760							 &c->context[0],
1761							 &c->sid[0]);
1762			if (rc)
1763				goto out;
1764		}
1765		*out_sid = c->sid[0];
1766	} else {
1767		*out_sid = SECINITSID_PORT;
1768	}
1769
1770      out:
1771	return rc;
1772}
1773
1774/*
1775 * Return the SIDs to use for a network interface
1776 * with the name `name'.  The `if_sid' SID is returned for
1777 * the interface and the `msg_sid' SID is returned as
1778 * the default SID for messages received on the
1779 * interface.
1780 */
1781int hidden sepol_netif_sid(char *name,
1782			   sepol_security_id_t * if_sid,
1783			   sepol_security_id_t * msg_sid)
1784{
1785	int rc = 0;
1786	ocontext_t *c;
1787
1788	c = policydb->ocontexts[OCON_NETIF];
1789	while (c) {
1790		if (strcmp(name, c->u.name) == 0)
1791			break;
1792		c = c->next;
1793	}
1794
1795	if (c) {
1796		if (!c->sid[0] || !c->sid[1]) {
1797			rc = sepol_sidtab_context_to_sid(sidtab,
1798							 &c->context[0],
1799							 &c->sid[0]);
1800			if (rc)
1801				goto out;
1802			rc = sepol_sidtab_context_to_sid(sidtab,
1803							 &c->context[1],
1804							 &c->sid[1]);
1805			if (rc)
1806				goto out;
1807		}
1808		*if_sid = c->sid[0];
1809		*msg_sid = c->sid[1];
1810	} else {
1811		*if_sid = SECINITSID_NETIF;
1812		*msg_sid = SECINITSID_NETMSG;
1813	}
1814
1815      out:
1816	return rc;
1817}
1818
1819static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr,
1820			       uint32_t * mask)
1821{
1822	int i, fail = 0;
1823
1824	for (i = 0; i < 4; i++)
1825		if (addr[i] != (input[i] & mask[i])) {
1826			fail = 1;
1827			break;
1828		}
1829
1830	return !fail;
1831}
1832
1833/*
1834 * Return the SID of the node specified by the address
1835 * `addrp' where `addrlen' is the length of the address
1836 * in bytes and `domain' is the communications domain or
1837 * address family in which the address should be interpreted.
1838 */
1839int hidden sepol_node_sid(uint16_t domain,
1840			  void *addrp,
1841			  size_t addrlen, sepol_security_id_t * out_sid)
1842{
1843	int rc = 0;
1844	ocontext_t *c;
1845
1846	switch (domain) {
1847	case AF_INET:{
1848			uint32_t addr;
1849
1850			if (addrlen != sizeof(uint32_t)) {
1851				rc = -EINVAL;
1852				goto out;
1853			}
1854
1855			addr = *((uint32_t *) addrp);
1856
1857			c = policydb->ocontexts[OCON_NODE];
1858			while (c) {
1859				if (c->u.node.addr == (addr & c->u.node.mask))
1860					break;
1861				c = c->next;
1862			}
1863			break;
1864		}
1865
1866	case AF_INET6:
1867		if (addrlen != sizeof(uint64_t) * 2) {
1868			rc = -EINVAL;
1869			goto out;
1870		}
1871
1872		c = policydb->ocontexts[OCON_NODE6];
1873		while (c) {
1874			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
1875						c->u.node6.mask))
1876				break;
1877			c = c->next;
1878		}
1879		break;
1880
1881	default:
1882		*out_sid = SECINITSID_NODE;
1883		goto out;
1884	}
1885
1886	if (c) {
1887		if (!c->sid[0]) {
1888			rc = sepol_sidtab_context_to_sid(sidtab,
1889							 &c->context[0],
1890							 &c->sid[0]);
1891			if (rc)
1892				goto out;
1893		}
1894		*out_sid = c->sid[0];
1895	} else {
1896		*out_sid = SECINITSID_NODE;
1897	}
1898
1899      out:
1900	return rc;
1901}
1902
1903/*
1904 * Generate the set of SIDs for legal security contexts
1905 * for a given user that can be reached by `fromsid'.
1906 * Set `*sids' to point to a dynamically allocated
1907 * array containing the set of SIDs.  Set `*nel' to the
1908 * number of elements in the array.
1909 */
1910#define SIDS_NEL 25
1911
1912int hidden sepol_get_user_sids(sepol_security_id_t fromsid,
1913			       char *username,
1914			       sepol_security_id_t ** sids, uint32_t * nel)
1915{
1916	context_struct_t *fromcon, usercon;
1917	sepol_security_id_t *mysids, *mysids2, sid;
1918	uint32_t mynel = 0, maxnel = SIDS_NEL;
1919	user_datum_t *user;
1920	role_datum_t *role;
1921	struct sepol_av_decision avd;
1922	int rc = 0;
1923	unsigned int i, j, reason;
1924	ebitmap_node_t *rnode, *tnode;
1925
1926	fromcon = sepol_sidtab_search(sidtab, fromsid);
1927	if (!fromcon) {
1928		rc = -EINVAL;
1929		goto out;
1930	}
1931
1932	user = (user_datum_t *) hashtab_search(policydb->p_users.table,
1933					       username);
1934	if (!user) {
1935		rc = -EINVAL;
1936		goto out;
1937	}
1938	usercon.user = user->s.value;
1939
1940	mysids = malloc(maxnel * sizeof(sepol_security_id_t));
1941	if (!mysids) {
1942		rc = -ENOMEM;
1943		goto out;
1944	}
1945	memset(mysids, 0, maxnel * sizeof(sepol_security_id_t));
1946
1947	ebitmap_for_each_bit(&user->roles.roles, rnode, i) {
1948		if (!ebitmap_node_get_bit(rnode, i))
1949			continue;
1950		role = policydb->role_val_to_struct[i];
1951		usercon.role = i + 1;
1952		ebitmap_for_each_bit(&role->types.types, tnode, j) {
1953			if (!ebitmap_node_get_bit(tnode, j))
1954				continue;
1955			usercon.type = j + 1;
1956			if (usercon.type == fromcon->type)
1957				continue;
1958
1959			if (mls_setup_user_range
1960			    (fromcon, user, &usercon, policydb->mls))
1961				continue;
1962
1963			rc = context_struct_compute_av(fromcon, &usercon,
1964						       SECCLASS_PROCESS,
1965						       PROCESS__TRANSITION,
1966						       &avd, &reason, NULL, 0);
1967			if (rc || !(avd.allowed & PROCESS__TRANSITION))
1968				continue;
1969			rc = sepol_sidtab_context_to_sid(sidtab, &usercon,
1970							 &sid);
1971			if (rc) {
1972				free(mysids);
1973				goto out;
1974			}
1975			if (mynel < maxnel) {
1976				mysids[mynel++] = sid;
1977			} else {
1978				maxnel += SIDS_NEL;
1979				mysids2 =
1980				    malloc(maxnel *
1981					   sizeof(sepol_security_id_t));
1982
1983				if (!mysids2) {
1984					rc = -ENOMEM;
1985					free(mysids);
1986					goto out;
1987				}
1988				memset(mysids2, 0,
1989				       maxnel * sizeof(sepol_security_id_t));
1990				memcpy(mysids2, mysids,
1991				       mynel * sizeof(sepol_security_id_t));
1992				free(mysids);
1993				mysids = mysids2;
1994				mysids[mynel++] = sid;
1995			}
1996		}
1997	}
1998
1999	*sids = mysids;
2000	*nel = mynel;
2001
2002      out:
2003	return rc;
2004}
2005
2006/*
2007 * Return the SID to use for a file in a filesystem
2008 * that cannot support a persistent label mapping or use another
2009 * fixed labeling behavior like transition SIDs or task SIDs.
2010 */
2011int hidden sepol_genfs_sid(const char *fstype,
2012			   char *path,
2013			   sepol_security_class_t sclass,
2014			   sepol_security_id_t * sid)
2015{
2016	size_t len;
2017	genfs_t *genfs;
2018	ocontext_t *c;
2019	int rc = 0, cmp = 0;
2020
2021	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
2022		cmp = strcmp(fstype, genfs->fstype);
2023		if (cmp <= 0)
2024			break;
2025	}
2026
2027	if (!genfs || cmp) {
2028		*sid = SECINITSID_UNLABELED;
2029		rc = -ENOENT;
2030		goto out;
2031	}
2032
2033	for (c = genfs->head; c; c = c->next) {
2034		len = strlen(c->u.name);
2035		if ((!c->v.sclass || sclass == c->v.sclass) &&
2036		    (strncmp(c->u.name, path, len) == 0))
2037			break;
2038	}
2039
2040	if (!c) {
2041		*sid = SECINITSID_UNLABELED;
2042		rc = -ENOENT;
2043		goto out;
2044	}
2045
2046	if (!c->sid[0]) {
2047		rc = sepol_sidtab_context_to_sid(sidtab,
2048						 &c->context[0], &c->sid[0]);
2049		if (rc)
2050			goto out;
2051	}
2052
2053	*sid = c->sid[0];
2054      out:
2055	return rc;
2056}
2057
2058int hidden sepol_fs_use(const char *fstype,
2059			unsigned int *behavior, sepol_security_id_t * sid)
2060{
2061	int rc = 0;
2062	ocontext_t *c;
2063
2064	c = policydb->ocontexts[OCON_FSUSE];
2065	while (c) {
2066		if (strcmp(fstype, c->u.name) == 0)
2067			break;
2068		c = c->next;
2069	}
2070
2071	if (c) {
2072		*behavior = c->v.behavior;
2073		if (!c->sid[0]) {
2074			rc = sepol_sidtab_context_to_sid(sidtab,
2075							 &c->context[0],
2076							 &c->sid[0]);
2077			if (rc)
2078				goto out;
2079		}
2080		*sid = c->sid[0];
2081	} else {
2082		rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
2083		if (rc) {
2084			*behavior = SECURITY_FS_USE_NONE;
2085			rc = 0;
2086		} else {
2087			*behavior = SECURITY_FS_USE_GENFS;
2088		}
2089	}
2090
2091      out:
2092	return rc;
2093}
2094
2095/* FLASK */
2096