blob: 3bbb6034520905f4cb8080d206b528cc3de06d40 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* Authors: Karl MacMillan <kmacmillan@tresys.com>
Eric Paris7c2b2402008-04-18 17:38:29 -04002 * Frank Mayer <mayerf@tresys.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
5 * This program is free software; you can redistribute it and/or modify
Eric Paris7c2b2402008-04-18 17:38:29 -04006 * it under the terms of the GNU General Public License as published by
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/slab.h>
15
16#include "security.h"
17#include "conditional.h"
Jeff Vander Stoepfa1aa142015-07-10 17:19:56 -040018#include "services.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
20/*
21 * cond_evaluate_expr evaluates a conditional expr
22 * in reverse polish notation. It returns true (1), false (0),
23 * or undefined (-1). Undefined occurs when the expression
24 * exceeds the stack depth of COND_EXPR_MAXDEPTH.
25 */
26static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
27{
28
29 struct cond_expr *cur;
30 int s[COND_EXPR_MAXDEPTH];
31 int sp = -1;
32
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +030033 for (cur = expr; cur; cur = cur->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 switch (cur->expr_type) {
35 case COND_BOOL:
36 if (sp == (COND_EXPR_MAXDEPTH - 1))
37 return -1;
38 sp++;
39 s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
40 break;
41 case COND_NOT:
42 if (sp < 0)
43 return -1;
44 s[sp] = !s[sp];
45 break;
46 case COND_OR:
47 if (sp < 1)
48 return -1;
49 sp--;
50 s[sp] |= s[sp + 1];
51 break;
52 case COND_AND:
53 if (sp < 1)
54 return -1;
55 sp--;
56 s[sp] &= s[sp + 1];
57 break;
58 case COND_XOR:
59 if (sp < 1)
60 return -1;
61 sp--;
62 s[sp] ^= s[sp + 1];
63 break;
64 case COND_EQ:
65 if (sp < 1)
66 return -1;
67 sp--;
68 s[sp] = (s[sp] == s[sp + 1]);
69 break;
70 case COND_NEQ:
71 if (sp < 1)
72 return -1;
73 sp--;
74 s[sp] = (s[sp] != s[sp + 1]);
75 break;
76 default:
77 return -1;
78 }
79 }
80 return s[0];
81}
82
83/*
84 * evaluate_cond_node evaluates the conditional stored in
85 * a struct cond_node and if the result is different than the
86 * current state of the node it sets the rules in the true/false
87 * list appropriately. If the result of the expression is undefined
88 * all of the rules are disabled for safety.
89 */
90int evaluate_cond_node(struct policydb *p, struct cond_node *node)
91{
92 int new_state;
Eric Paris7c2b2402008-04-18 17:38:29 -040093 struct cond_av_list *cur;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95 new_state = cond_evaluate_expr(p, node->expr);
96 if (new_state != node->cur_state) {
97 node->cur_state = new_state;
98 if (new_state == -1)
peter enderborgab485762018-06-12 10:09:00 +020099 pr_err("SELinux: expression result was undefined - disabling all rules.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 /* turn the rules on or off */
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +0300101 for (cur = node->true_list; cur; cur = cur->next) {
Eric Paris7c2b2402008-04-18 17:38:29 -0400102 if (new_state <= 0)
Stephen Smalley782ebb92005-09-03 15:55:16 -0700103 cur->node->key.specified &= ~AVTAB_ENABLED;
Eric Paris7c2b2402008-04-18 17:38:29 -0400104 else
Stephen Smalley782ebb92005-09-03 15:55:16 -0700105 cur->node->key.specified |= AVTAB_ENABLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
107
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +0300108 for (cur = node->false_list; cur; cur = cur->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 /* -1 or 1 */
Eric Paris7c2b2402008-04-18 17:38:29 -0400110 if (new_state)
Stephen Smalley782ebb92005-09-03 15:55:16 -0700111 cur->node->key.specified &= ~AVTAB_ENABLED;
Eric Paris7c2b2402008-04-18 17:38:29 -0400112 else
Stephen Smalley782ebb92005-09-03 15:55:16 -0700113 cur->node->key.specified |= AVTAB_ENABLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 }
115 }
116 return 0;
117}
118
119int cond_policydb_init(struct policydb *p)
120{
Dan Carpenter38184c52010-06-12 20:55:01 +0200121 int rc;
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 p->bool_val_to_struct = NULL;
124 p->cond_list = NULL;
Dan Carpenter38184c52010-06-12 20:55:01 +0200125
126 rc = avtab_init(&p->te_cond_avtab);
127 if (rc)
128 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130 return 0;
131}
132
133static void cond_av_list_destroy(struct cond_av_list *list)
134{
135 struct cond_av_list *cur, *next;
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +0300136 for (cur = list; cur; cur = next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 next = cur->next;
138 /* the avtab_ptr_t node is destroy by the avtab */
139 kfree(cur);
140 }
141}
142
143static void cond_node_destroy(struct cond_node *node)
144{
145 struct cond_expr *cur_expr, *next_expr;
146
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +0300147 for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 next_expr = cur_expr->next;
149 kfree(cur_expr);
150 }
151 cond_av_list_destroy(node->true_list);
152 cond_av_list_destroy(node->false_list);
153 kfree(node);
154}
155
156static void cond_list_destroy(struct cond_node *list)
157{
158 struct cond_node *next, *cur;
159
160 if (list == NULL)
161 return;
162
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +0300163 for (cur = list; cur; cur = next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 next = cur->next;
165 cond_node_destroy(cur);
166 }
167}
168
169void cond_policydb_destroy(struct policydb *p)
170{
Jesper Juhl9a5f04b2005-06-25 14:58:51 -0700171 kfree(p->bool_val_to_struct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 avtab_destroy(&p->te_cond_avtab);
173 cond_list_destroy(p->cond_list);
174}
175
176int cond_init_bool_indexes(struct policydb *p)
177{
Jesper Juhl9a5f04b2005-06-25 14:58:51 -0700178 kfree(p->bool_val_to_struct);
Markus Elfringf6076f72017-01-14 10:48:28 +0100179 p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim,
180 sizeof(*p->bool_val_to_struct),
181 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 if (!p->bool_val_to_struct)
Davidlohr Bueso3ac285ff2011-01-21 12:28:04 -0300183 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 return 0;
185}
186
187int cond_destroy_bool(void *key, void *datum, void *p)
188{
Jesper Juhl9a5f04b2005-06-25 14:58:51 -0700189 kfree(key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 kfree(datum);
191 return 0;
192}
193
194int cond_index_bool(void *key, void *datum, void *datap)
195{
196 struct policydb *p;
197 struct cond_bool_datum *booldatum;
198
199 booldatum = datum;
200 p = datap;
201
202 if (!booldatum->value || booldatum->value > p->p_bools.nprim)
203 return -EINVAL;
204
Kent Overstreetacdf52d2019-03-11 23:31:10 -0700205 p->sym_val_to_name[SYM_BOOLS][booldatum->value - 1] = key;
Eric Paris7c2b2402008-04-18 17:38:29 -0400206 p->bool_val_to_struct[booldatum->value - 1] = booldatum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 return 0;
209}
210
211static int bool_isvalid(struct cond_bool_datum *b)
212{
213 if (!(b->state == 0 || b->state == 1))
214 return 0;
215 return 1;
216}
217
218int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
219{
220 char *key = NULL;
221 struct cond_bool_datum *booldatum;
Alexey Dobriyanb5bf6c52005-09-03 15:55:17 -0700222 __le32 buf[3];
223 u32 len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 int rc;
225
Markus Elfringfb13a312017-01-14 11:22:12 +0100226 booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 if (!booldatum)
Dan Carpenter338437f2010-06-12 20:56:01 +0200228 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 rc = next_entry(buf, fp, sizeof buf);
Dan Carpenter338437f2010-06-12 20:56:01 +0200231 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 goto err;
233
234 booldatum->value = le32_to_cpu(buf[0]);
235 booldatum->state = le32_to_cpu(buf[1]);
236
Dan Carpenter338437f2010-06-12 20:56:01 +0200237 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 if (!bool_isvalid(booldatum))
239 goto err;
240
241 len = le32_to_cpu(buf[2]);
William Roberts7c686af2016-08-30 09:28:11 -0700242 if (((len == 0) || (len == (u32)-1)))
243 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Dan Carpenter338437f2010-06-12 20:56:01 +0200245 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 key = kmalloc(len + 1, GFP_KERNEL);
247 if (!key)
248 goto err;
249 rc = next_entry(key, fp, len);
Dan Carpenter338437f2010-06-12 20:56:01 +0200250 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 goto err;
Vesa-Matti J Karidf4ea8652008-07-20 23:57:01 +0300252 key[len] = '\0';
Dan Carpenter338437f2010-06-12 20:56:01 +0200253 rc = hashtab_insert(h, key, booldatum);
254 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 goto err;
256
257 return 0;
258err:
259 cond_destroy_bool(key, booldatum, NULL);
Dan Carpenter338437f2010-06-12 20:56:01 +0200260 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262
Eric Paris7c2b2402008-04-18 17:38:29 -0400263struct cond_insertf_data {
Stephen Smalley782ebb92005-09-03 15:55:16 -0700264 struct policydb *p;
265 struct cond_av_list *other;
266 struct cond_av_list *head;
267 struct cond_av_list *tail;
268};
269
270static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
271{
272 struct cond_insertf_data *data = ptr;
273 struct policydb *p = data->p;
274 struct cond_av_list *other = data->other, *list, *cur;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 struct avtab_node *node_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 u8 found;
Dan Carpenter9d623b12010-06-12 20:52:19 +0200277 int rc = -EINVAL;
Stephen Smalley782ebb92005-09-03 15:55:16 -0700278
279 /*
280 * For type rules we have to make certain there aren't any
281 * conflicting rules by searching the te_avtab and the
282 * cond_te_avtab.
283 */
284 if (k->specified & AVTAB_TYPE) {
285 if (avtab_search(&p->te_avtab, k)) {
peter enderborgab485762018-06-12 10:09:00 +0200286 pr_err("SELinux: type rule already exists outside of a conditional.\n");
Stephen Smalley782ebb92005-09-03 15:55:16 -0700287 goto err;
288 }
289 /*
290 * If we are reading the false list other will be a pointer to
291 * the true list. We can have duplicate entries if there is only
292 * 1 other entry and it is in our true list.
293 *
294 * If we are reading the true list (other == NULL) there shouldn't
295 * be any other entries.
296 */
297 if (other) {
298 node_ptr = avtab_search_node(&p->te_cond_avtab, k);
299 if (node_ptr) {
300 if (avtab_search_node_next(node_ptr, k->specified)) {
peter enderborgab485762018-06-12 10:09:00 +0200301 pr_err("SELinux: too many conflicting type rules.\n");
Stephen Smalley782ebb92005-09-03 15:55:16 -0700302 goto err;
303 }
304 found = 0;
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +0300305 for (cur = other; cur; cur = cur->next) {
Stephen Smalley782ebb92005-09-03 15:55:16 -0700306 if (cur->node == node_ptr) {
307 found = 1;
308 break;
309 }
310 }
311 if (!found) {
peter enderborgab485762018-06-12 10:09:00 +0200312 pr_err("SELinux: conflicting type rules.\n");
Stephen Smalley782ebb92005-09-03 15:55:16 -0700313 goto err;
314 }
315 }
316 } else {
317 if (avtab_search(&p->te_cond_avtab, k)) {
peter enderborgab485762018-06-12 10:09:00 +0200318 pr_err("SELinux: conflicting type rules when adding type rule for true.\n");
Stephen Smalley782ebb92005-09-03 15:55:16 -0700319 goto err;
320 }
321 }
322 }
323
324 node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
325 if (!node_ptr) {
peter enderborgab485762018-06-12 10:09:00 +0200326 pr_err("SELinux: could not insert rule.\n");
Dan Carpenter9d623b12010-06-12 20:52:19 +0200327 rc = -ENOMEM;
Stephen Smalley782ebb92005-09-03 15:55:16 -0700328 goto err;
329 }
330
Markus Elfringfb13a312017-01-14 11:22:12 +0100331 list = kzalloc(sizeof(*list), GFP_KERNEL);
Dan Carpenter9d623b12010-06-12 20:52:19 +0200332 if (!list) {
333 rc = -ENOMEM;
Stephen Smalley782ebb92005-09-03 15:55:16 -0700334 goto err;
Dan Carpenter9d623b12010-06-12 20:52:19 +0200335 }
Stephen Smalley782ebb92005-09-03 15:55:16 -0700336
337 list->node = node_ptr;
338 if (!data->head)
339 data->head = list;
340 else
341 data->tail->next = list;
342 data->tail = list;
343 return 0;
344
345err:
346 cond_av_list_destroy(data->head);
347 data->head = NULL;
Dan Carpenter9d623b12010-06-12 20:52:19 +0200348 return rc;
Stephen Smalley782ebb92005-09-03 15:55:16 -0700349}
350
351static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
352{
353 int i, rc;
Alexey Dobriyanb5bf6c52005-09-03 15:55:17 -0700354 __le32 buf[1];
355 u32 len;
Stephen Smalley782ebb92005-09-03 15:55:16 -0700356 struct cond_insertf_data data;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 *ret_list = NULL;
359
Stephen Smalley782ebb92005-09-03 15:55:16 -0700360 rc = next_entry(buf, fp, sizeof(u32));
Dan Carpenter9d623b12010-06-12 20:52:19 +0200361 if (rc)
362 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 len = le32_to_cpu(buf[0]);
Eric Paris7c2b2402008-04-18 17:38:29 -0400365 if (len == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Stephen Smalley782ebb92005-09-03 15:55:16 -0700368 data.p = p;
369 data.other = other;
370 data.head = NULL;
371 data.tail = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 for (i = 0; i < len; i++) {
Stephen Smalley45e54212007-11-07 10:08:00 -0500373 rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
374 &data);
Stephen Smalley782ebb92005-09-03 15:55:16 -0700375 if (rc)
376 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
378
Stephen Smalley782ebb92005-09-03 15:55:16 -0700379 *ret_list = data.head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381}
382
383static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
384{
385 if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
peter enderborgab485762018-06-12 10:09:00 +0200386 pr_err("SELinux: conditional expressions uses unknown operator.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 return 0;
388 }
389
390 if (expr->bool > p->p_bools.nprim) {
peter enderborgab485762018-06-12 10:09:00 +0200391 pr_err("SELinux: conditional expressions uses unknown bool.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 return 0;
393 }
394 return 1;
395}
396
397static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
398{
Alexey Dobriyanb5bf6c52005-09-03 15:55:17 -0700399 __le32 buf[2];
400 u32 len, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 int rc;
402 struct cond_expr *expr = NULL, *last = NULL;
403
Namhyung Kimf004afe2014-06-15 01:19:01 +0900404 rc = next_entry(buf, fp, sizeof(u32) * 2);
Dan Carpenterfc5c1262010-06-12 20:53:46 +0200405 if (rc)
Namhyung Kim6e51f9c2014-06-15 01:19:02 +0900406 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
408 node->cur_state = le32_to_cpu(buf[0]);
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 /* expr */
Namhyung Kimf004afe2014-06-15 01:19:01 +0900411 len = le32_to_cpu(buf[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Eric Paris7c2b2402008-04-18 17:38:29 -0400413 for (i = 0; i < len; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 rc = next_entry(buf, fp, sizeof(u32) * 2);
Dan Carpenterfc5c1262010-06-12 20:53:46 +0200415 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 goto err;
417
Dan Carpenterfc5c1262010-06-12 20:53:46 +0200418 rc = -ENOMEM;
Markus Elfringfb13a312017-01-14 11:22:12 +0100419 expr = kzalloc(sizeof(*expr), GFP_KERNEL);
Eric Paris7c2b2402008-04-18 17:38:29 -0400420 if (!expr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
423 expr->expr_type = le32_to_cpu(buf[0]);
424 expr->bool = le32_to_cpu(buf[1]);
425
426 if (!expr_isvalid(p, expr)) {
Dan Carpenterfc5c1262010-06-12 20:53:46 +0200427 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 kfree(expr);
429 goto err;
430 }
431
Eric Paris7c2b2402008-04-18 17:38:29 -0400432 if (i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 node->expr = expr;
Eric Paris7c2b2402008-04-18 17:38:29 -0400434 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 last->next = expr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 last = expr;
437 }
438
Dan Carpenterfc5c1262010-06-12 20:53:46 +0200439 rc = cond_read_av_list(p, fp, &node->true_list, NULL);
440 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 goto err;
Dan Carpenterfc5c1262010-06-12 20:53:46 +0200442 rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
443 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 goto err;
445 return 0;
446err:
447 cond_node_destroy(node);
Dan Carpenterfc5c1262010-06-12 20:53:46 +0200448 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449}
450
451int cond_read_list(struct policydb *p, void *fp)
452{
453 struct cond_node *node, *last = NULL;
Alexey Dobriyanb5bf6c52005-09-03 15:55:17 -0700454 __le32 buf[1];
455 u32 i, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 int rc;
457
458 rc = next_entry(buf, fp, sizeof buf);
Dan Carpenter5241c102010-06-12 20:51:40 +0200459 if (rc)
460 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
462 len = le32_to_cpu(buf[0]);
463
Yuichi Nakamura3232c112007-08-24 11:55:11 +0900464 rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
465 if (rc)
466 goto err;
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 for (i = 0; i < len; i++) {
Dan Carpenter5241c102010-06-12 20:51:40 +0200469 rc = -ENOMEM;
Markus Elfringfb13a312017-01-14 11:22:12 +0100470 node = kzalloc(sizeof(*node), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if (!node)
472 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Dan Carpenter5241c102010-06-12 20:51:40 +0200474 rc = cond_read_node(p, node, fp);
475 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 goto err;
477
Eric Paris7c2b2402008-04-18 17:38:29 -0400478 if (i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 p->cond_list = node;
Eric Paris7c2b2402008-04-18 17:38:29 -0400480 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 last->next = node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 last = node;
483 }
484 return 0;
485err:
486 cond_list_destroy(p->cond_list);
Stephen Smalley782ebb92005-09-03 15:55:16 -0700487 p->cond_list = NULL;
Dan Carpenter5241c102010-06-12 20:51:40 +0200488 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
Eric Pariscee74f42010-10-13 17:50:25 -0400491int cond_write_bool(void *vkey, void *datum, void *ptr)
492{
493 char *key = vkey;
494 struct cond_bool_datum *booldatum = datum;
495 struct policy_data *pd = ptr;
496 void *fp = pd->fp;
497 __le32 buf[3];
498 u32 len;
499 int rc;
500
501 len = strlen(key);
502 buf[0] = cpu_to_le32(booldatum->value);
503 buf[1] = cpu_to_le32(booldatum->state);
504 buf[2] = cpu_to_le32(len);
505 rc = put_entry(buf, sizeof(u32), 3, fp);
506 if (rc)
507 return rc;
508 rc = put_entry(key, 1, len, fp);
509 if (rc)
510 return rc;
511 return 0;
512}
513
514/*
515 * cond_write_cond_av_list doesn't write out the av_list nodes.
516 * Instead it writes out the key/value pairs from the avtab. This
517 * is necessary because there is no way to uniquely identifying rules
518 * in the avtab so it is not possible to associate individual rules
519 * in the avtab with a conditional without saving them as part of
520 * the conditional. This means that the avtab with the conditional
521 * rules will not be saved but will be rebuilt on policy load.
522 */
523static int cond_write_av_list(struct policydb *p,
524 struct cond_av_list *list, struct policy_file *fp)
525{
526 __le32 buf[1];
527 struct cond_av_list *cur_list;
528 u32 len;
529 int rc;
530
531 len = 0;
532 for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
533 len++;
534
535 buf[0] = cpu_to_le32(len);
536 rc = put_entry(buf, sizeof(u32), 1, fp);
537 if (rc)
538 return rc;
539
540 if (len == 0)
541 return 0;
542
543 for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
544 rc = avtab_write_item(p, cur_list->node, fp);
545 if (rc)
546 return rc;
547 }
548
549 return 0;
550}
551
James Morris7b98a582011-08-30 12:52:32 +1000552static int cond_write_node(struct policydb *p, struct cond_node *node,
Eric Pariscee74f42010-10-13 17:50:25 -0400553 struct policy_file *fp)
554{
555 struct cond_expr *cur_expr;
556 __le32 buf[2];
557 int rc;
558 u32 len = 0;
559
560 buf[0] = cpu_to_le32(node->cur_state);
561 rc = put_entry(buf, sizeof(u32), 1, fp);
562 if (rc)
563 return rc;
564
565 for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
566 len++;
567
568 buf[0] = cpu_to_le32(len);
569 rc = put_entry(buf, sizeof(u32), 1, fp);
570 if (rc)
571 return rc;
572
573 for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
574 buf[0] = cpu_to_le32(cur_expr->expr_type);
575 buf[1] = cpu_to_le32(cur_expr->bool);
576 rc = put_entry(buf, sizeof(u32), 2, fp);
577 if (rc)
578 return rc;
579 }
580
581 rc = cond_write_av_list(p, node->true_list, fp);
582 if (rc)
583 return rc;
584 rc = cond_write_av_list(p, node->false_list, fp);
585 if (rc)
586 return rc;
587
588 return 0;
589}
590
591int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
592{
593 struct cond_node *cur;
594 u32 len;
595 __le32 buf[1];
596 int rc;
597
598 len = 0;
599 for (cur = list; cur != NULL; cur = cur->next)
600 len++;
601 buf[0] = cpu_to_le32(len);
602 rc = put_entry(buf, sizeof(u32), 1, fp);
603 if (rc)
604 return rc;
605
606 for (cur = list; cur != NULL; cur = cur->next) {
607 rc = cond_write_node(p, cur, fp);
608 if (rc)
609 return rc;
610 }
611
612 return 0;
613}
Jeff Vander Stoepfa1aa142015-07-10 17:19:56 -0400614
615void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
616 struct extended_perms_decision *xpermd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
618 struct avtab_node *node;
619
Jeff Vander Stoepfa1aa142015-07-10 17:19:56 -0400620 if (!ctab || !key || !xpermd)
621 return;
622
623 for (node = avtab_search_node(ctab, key); node;
624 node = avtab_search_node_next(node, key->specified)) {
625 if (node->key.specified & AVTAB_ENABLED)
626 services_compute_xperms_decision(xpermd, node);
627 }
628 return;
629
630}
631/* Determine whether additional permissions are granted by the conditional
632 * av table, and if so, add them to the result
633 */
634void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
635 struct av_decision *avd, struct extended_perms *xperms)
636{
637 struct avtab_node *node;
638
Stephen Smalleyf3bef672015-11-23 16:07:41 -0500639 if (!ctab || !key || !avd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return;
641
Vesa-Matti Karidbc74c62008-08-07 03:18:20 +0300642 for (node = avtab_search_node(ctab, key); node;
Stephen Smalley782ebb92005-09-03 15:55:16 -0700643 node = avtab_search_node_next(node, key->specified)) {
Eric Paris7c2b2402008-04-18 17:38:29 -0400644 if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
645 (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
Jeff Vander Stoepfa1aa142015-07-10 17:19:56 -0400646 avd->allowed |= node->datum.u.data;
Eric Paris7c2b2402008-04-18 17:38:29 -0400647 if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
648 (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 /* Since a '0' in an auditdeny mask represents a
650 * permission we do NOT want to audit (dontaudit), we use
651 * the '&' operand to ensure that all '0's in the mask
652 * are retained (much unlike the allow and auditallow cases).
653 */
Jeff Vander Stoepfa1aa142015-07-10 17:19:56 -0400654 avd->auditdeny &= node->datum.u.data;
Eric Paris7c2b2402008-04-18 17:38:29 -0400655 if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
656 (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
Jeff Vander Stoepfa1aa142015-07-10 17:19:56 -0400657 avd->auditallow |= node->datum.u.data;
Stephen Smalleyf3bef672015-11-23 16:07:41 -0500658 if (xperms && (node->key.specified & AVTAB_ENABLED) &&
Jeff Vander Stoepfa1aa142015-07-10 17:19:56 -0400659 (node->key.specified & AVTAB_XPERMS))
660 services_compute_xperms_drivers(xperms, node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}