xref: /linux/security/selinux/ss/conditional.c (revision bcefe12eff5dca6fdfa94ed85e5bee66380d5cd9)
1 /* Authors: Karl MacMillan <kmacmillan@tresys.com>
2  *	    Frank Mayer <mayerf@tresys.com>
3  *
4  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
5  *	This program is free software; you can redistribute it and/or modify
6  *	it under the terms of the GNU General Public License as published by
7  *	the Free Software Foundation, version 2.
8  */
9 
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/string.h>
13 #include <linux/spinlock.h>
14 #include <linux/slab.h>
15 
16 #include "security.h"
17 #include "conditional.h"
18 
19 /*
20  * cond_evaluate_expr evaluates a conditional expr
21  * in reverse polish notation. It returns true (1), false (0),
22  * or undefined (-1). Undefined occurs when the expression
23  * exceeds the stack depth of COND_EXPR_MAXDEPTH.
24  */
25 static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
26 {
27 
28 	struct cond_expr *cur;
29 	int s[COND_EXPR_MAXDEPTH];
30 	int sp = -1;
31 
32 	for (cur = expr; cur; cur = cur->next) {
33 		switch (cur->expr_type) {
34 		case COND_BOOL:
35 			if (sp == (COND_EXPR_MAXDEPTH - 1))
36 				return -1;
37 			sp++;
38 			s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
39 			break;
40 		case COND_NOT:
41 			if (sp < 0)
42 				return -1;
43 			s[sp] = !s[sp];
44 			break;
45 		case COND_OR:
46 			if (sp < 1)
47 				return -1;
48 			sp--;
49 			s[sp] |= s[sp + 1];
50 			break;
51 		case COND_AND:
52 			if (sp < 1)
53 				return -1;
54 			sp--;
55 			s[sp] &= s[sp + 1];
56 			break;
57 		case COND_XOR:
58 			if (sp < 1)
59 				return -1;
60 			sp--;
61 			s[sp] ^= s[sp + 1];
62 			break;
63 		case COND_EQ:
64 			if (sp < 1)
65 				return -1;
66 			sp--;
67 			s[sp] = (s[sp] == s[sp + 1]);
68 			break;
69 		case COND_NEQ:
70 			if (sp < 1)
71 				return -1;
72 			sp--;
73 			s[sp] = (s[sp] != s[sp + 1]);
74 			break;
75 		default:
76 			return -1;
77 		}
78 	}
79 	return s[0];
80 }
81 
82 /*
83  * evaluate_cond_node evaluates the conditional stored in
84  * a struct cond_node and if the result is different than the
85  * current state of the node it sets the rules in the true/false
86  * list appropriately. If the result of the expression is undefined
87  * all of the rules are disabled for safety.
88  */
89 int evaluate_cond_node(struct policydb *p, struct cond_node *node)
90 {
91 	int new_state;
92 	struct cond_av_list *cur;
93 
94 	new_state = cond_evaluate_expr(p, node->expr);
95 	if (new_state != node->cur_state) {
96 		node->cur_state = new_state;
97 		if (new_state == -1)
98 			printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n");
99 		/* turn the rules on or off */
100 		for (cur = node->true_list; cur; cur = cur->next) {
101 			if (new_state <= 0)
102 				cur->node->key.specified &= ~AVTAB_ENABLED;
103 			else
104 				cur->node->key.specified |= AVTAB_ENABLED;
105 		}
106 
107 		for (cur = node->false_list; cur; cur = cur->next) {
108 			/* -1 or 1 */
109 			if (new_state)
110 				cur->node->key.specified &= ~AVTAB_ENABLED;
111 			else
112 				cur->node->key.specified |= AVTAB_ENABLED;
113 		}
114 	}
115 	return 0;
116 }
117 
118 int cond_policydb_init(struct policydb *p)
119 {
120 	p->bool_val_to_struct = NULL;
121 	p->cond_list = NULL;
122 	if (avtab_init(&p->te_cond_avtab))
123 		return -1;
124 
125 	return 0;
126 }
127 
128 static void cond_av_list_destroy(struct cond_av_list *list)
129 {
130 	struct cond_av_list *cur, *next;
131 	for (cur = list; cur; cur = next) {
132 		next = cur->next;
133 		/* the avtab_ptr_t node is destroy by the avtab */
134 		kfree(cur);
135 	}
136 }
137 
138 static void cond_node_destroy(struct cond_node *node)
139 {
140 	struct cond_expr *cur_expr, *next_expr;
141 
142 	for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
143 		next_expr = cur_expr->next;
144 		kfree(cur_expr);
145 	}
146 	cond_av_list_destroy(node->true_list);
147 	cond_av_list_destroy(node->false_list);
148 	kfree(node);
149 }
150 
151 static void cond_list_destroy(struct cond_node *list)
152 {
153 	struct cond_node *next, *cur;
154 
155 	if (list == NULL)
156 		return;
157 
158 	for (cur = list; cur; cur = next) {
159 		next = cur->next;
160 		cond_node_destroy(cur);
161 	}
162 }
163 
164 void cond_policydb_destroy(struct policydb *p)
165 {
166 	kfree(p->bool_val_to_struct);
167 	avtab_destroy(&p->te_cond_avtab);
168 	cond_list_destroy(p->cond_list);
169 }
170 
171 int cond_init_bool_indexes(struct policydb *p)
172 {
173 	kfree(p->bool_val_to_struct);
174 	p->bool_val_to_struct = (struct cond_bool_datum **)
175 		kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
176 	if (!p->bool_val_to_struct)
177 		return -1;
178 	return 0;
179 }
180 
181 int cond_destroy_bool(void *key, void *datum, void *p)
182 {
183 	kfree(key);
184 	kfree(datum);
185 	return 0;
186 }
187 
188 int cond_index_bool(void *key, void *datum, void *datap)
189 {
190 	struct policydb *p;
191 	struct cond_bool_datum *booldatum;
192 
193 	booldatum = datum;
194 	p = datap;
195 
196 	if (!booldatum->value || booldatum->value > p->p_bools.nprim)
197 		return -EINVAL;
198 
199 	p->p_bool_val_to_name[booldatum->value - 1] = key;
200 	p->bool_val_to_struct[booldatum->value - 1] = booldatum;
201 
202 	return 0;
203 }
204 
205 static int bool_isvalid(struct cond_bool_datum *b)
206 {
207 	if (!(b->state == 0 || b->state == 1))
208 		return 0;
209 	return 1;
210 }
211 
212 int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
213 {
214 	char *key = NULL;
215 	struct cond_bool_datum *booldatum;
216 	__le32 buf[3];
217 	u32 len;
218 	int rc;
219 
220 	booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
221 	if (!booldatum)
222 		return -1;
223 
224 	rc = next_entry(buf, fp, sizeof buf);
225 	if (rc < 0)
226 		goto err;
227 
228 	booldatum->value = le32_to_cpu(buf[0]);
229 	booldatum->state = le32_to_cpu(buf[1]);
230 
231 	if (!bool_isvalid(booldatum))
232 		goto err;
233 
234 	len = le32_to_cpu(buf[2]);
235 
236 	key = kmalloc(len + 1, GFP_KERNEL);
237 	if (!key)
238 		goto err;
239 	rc = next_entry(key, fp, len);
240 	if (rc < 0)
241 		goto err;
242 	key[len] = '\0';
243 	if (hashtab_insert(h, key, booldatum))
244 		goto err;
245 
246 	return 0;
247 err:
248 	cond_destroy_bool(key, booldatum, NULL);
249 	return -1;
250 }
251 
252 struct cond_insertf_data {
253 	struct policydb *p;
254 	struct cond_av_list *other;
255 	struct cond_av_list *head;
256 	struct cond_av_list *tail;
257 };
258 
259 static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
260 {
261 	struct cond_insertf_data *data = ptr;
262 	struct policydb *p = data->p;
263 	struct cond_av_list *other = data->other, *list, *cur;
264 	struct avtab_node *node_ptr;
265 	u8 found;
266 
267 
268 	/*
269 	 * For type rules we have to make certain there aren't any
270 	 * conflicting rules by searching the te_avtab and the
271 	 * cond_te_avtab.
272 	 */
273 	if (k->specified & AVTAB_TYPE) {
274 		if (avtab_search(&p->te_avtab, k)) {
275 			printk(KERN_ERR "SELinux: type rule already exists outside of a conditional.\n");
276 			goto err;
277 		}
278 		/*
279 		 * If we are reading the false list other will be a pointer to
280 		 * the true list. We can have duplicate entries if there is only
281 		 * 1 other entry and it is in our true list.
282 		 *
283 		 * If we are reading the true list (other == NULL) there shouldn't
284 		 * be any other entries.
285 		 */
286 		if (other) {
287 			node_ptr = avtab_search_node(&p->te_cond_avtab, k);
288 			if (node_ptr) {
289 				if (avtab_search_node_next(node_ptr, k->specified)) {
290 					printk(KERN_ERR "SELinux: too many conflicting type rules.\n");
291 					goto err;
292 				}
293 				found = 0;
294 				for (cur = other; cur; cur = cur->next) {
295 					if (cur->node == node_ptr) {
296 						found = 1;
297 						break;
298 					}
299 				}
300 				if (!found) {
301 					printk(KERN_ERR "SELinux: conflicting type rules.\n");
302 					goto err;
303 				}
304 			}
305 		} else {
306 			if (avtab_search(&p->te_cond_avtab, k)) {
307 				printk(KERN_ERR "SELinux: conflicting type rules when adding type rule for true.\n");
308 				goto err;
309 			}
310 		}
311 	}
312 
313 	node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
314 	if (!node_ptr) {
315 		printk(KERN_ERR "SELinux: could not insert rule.\n");
316 		goto err;
317 	}
318 
319 	list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL);
320 	if (!list)
321 		goto err;
322 
323 	list->node = node_ptr;
324 	if (!data->head)
325 		data->head = list;
326 	else
327 		data->tail->next = list;
328 	data->tail = list;
329 	return 0;
330 
331 err:
332 	cond_av_list_destroy(data->head);
333 	data->head = NULL;
334 	return -1;
335 }
336 
337 static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
338 {
339 	int i, rc;
340 	__le32 buf[1];
341 	u32 len;
342 	struct cond_insertf_data data;
343 
344 	*ret_list = NULL;
345 
346 	len = 0;
347 	rc = next_entry(buf, fp, sizeof(u32));
348 	if (rc < 0)
349 		return -1;
350 
351 	len = le32_to_cpu(buf[0]);
352 	if (len == 0)
353 		return 0;
354 
355 	data.p = p;
356 	data.other = other;
357 	data.head = NULL;
358 	data.tail = NULL;
359 	for (i = 0; i < len; i++) {
360 		rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
361 				     &data);
362 		if (rc)
363 			return rc;
364 
365 	}
366 
367 	*ret_list = data.head;
368 	return 0;
369 }
370 
371 static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
372 {
373 	if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
374 		printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n");
375 		return 0;
376 	}
377 
378 	if (expr->bool > p->p_bools.nprim) {
379 		printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n");
380 		return 0;
381 	}
382 	return 1;
383 }
384 
385 static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
386 {
387 	__le32 buf[2];
388 	u32 len, i;
389 	int rc;
390 	struct cond_expr *expr = NULL, *last = NULL;
391 
392 	rc = next_entry(buf, fp, sizeof(u32));
393 	if (rc < 0)
394 		return -1;
395 
396 	node->cur_state = le32_to_cpu(buf[0]);
397 
398 	len = 0;
399 	rc = next_entry(buf, fp, sizeof(u32));
400 	if (rc < 0)
401 		return -1;
402 
403 	/* expr */
404 	len = le32_to_cpu(buf[0]);
405 
406 	for (i = 0; i < len; i++) {
407 		rc = next_entry(buf, fp, sizeof(u32) * 2);
408 		if (rc < 0)
409 			goto err;
410 
411 		expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
412 		if (!expr)
413 			goto err;
414 
415 		expr->expr_type = le32_to_cpu(buf[0]);
416 		expr->bool = le32_to_cpu(buf[1]);
417 
418 		if (!expr_isvalid(p, expr)) {
419 			kfree(expr);
420 			goto err;
421 		}
422 
423 		if (i == 0)
424 			node->expr = expr;
425 		else
426 			last->next = expr;
427 		last = expr;
428 	}
429 
430 	if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
431 		goto err;
432 	if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
433 		goto err;
434 	return 0;
435 err:
436 	cond_node_destroy(node);
437 	return -1;
438 }
439 
440 int cond_read_list(struct policydb *p, void *fp)
441 {
442 	struct cond_node *node, *last = NULL;
443 	__le32 buf[1];
444 	u32 i, len;
445 	int rc;
446 
447 	rc = next_entry(buf, fp, sizeof buf);
448 	if (rc < 0)
449 		return -1;
450 
451 	len = le32_to_cpu(buf[0]);
452 
453 	rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
454 	if (rc)
455 		goto err;
456 
457 	for (i = 0; i < len; i++) {
458 		node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
459 		if (!node)
460 			goto err;
461 
462 		if (cond_read_node(p, node, fp) != 0)
463 			goto err;
464 
465 		if (i == 0)
466 			p->cond_list = node;
467 		else
468 			last->next = node;
469 		last = node;
470 	}
471 	return 0;
472 err:
473 	cond_list_destroy(p->cond_list);
474 	p->cond_list = NULL;
475 	return -1;
476 }
477 
478 /* Determine whether additional permissions are granted by the conditional
479  * av table, and if so, add them to the result
480  */
481 void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
482 {
483 	struct avtab_node *node;
484 
485 	if (!ctab || !key || !avd)
486 		return;
487 
488 	for (node = avtab_search_node(ctab, key); node;
489 				node = avtab_search_node_next(node, key->specified)) {
490 		if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
491 		    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
492 			avd->allowed |= node->datum.data;
493 		if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
494 		    (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
495 			/* Since a '0' in an auditdeny mask represents a
496 			 * permission we do NOT want to audit (dontaudit), we use
497 			 * the '&' operand to ensure that all '0's in the mask
498 			 * are retained (much unlike the allow and auditallow cases).
499 			 */
500 			avd->auditdeny &= node->datum.data;
501 		if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
502 		    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
503 			avd->auditallow |= node->datum.data;
504 	}
505 	return;
506 }
507