1*2d543d20SAndroid Build Coastguard Worker /* Authors: Karl MacMillan <[email protected]>
2*2d543d20SAndroid Build Coastguard Worker * Frank Mayer <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker * David Caplan <[email protected]>
4*2d543d20SAndroid Build Coastguard Worker *
5*2d543d20SAndroid Build Coastguard Worker * Copyright (C) 2003 - 2005 Tresys Technology, LLC
6*2d543d20SAndroid Build Coastguard Worker *
7*2d543d20SAndroid Build Coastguard Worker * This library is free software; you can redistribute it and/or
8*2d543d20SAndroid Build Coastguard Worker * modify it under the terms of the GNU Lesser General Public
9*2d543d20SAndroid Build Coastguard Worker * License as published by the Free Software Foundation; either
10*2d543d20SAndroid Build Coastguard Worker * version 2.1 of the License, or (at your option) any later version.
11*2d543d20SAndroid Build Coastguard Worker *
12*2d543d20SAndroid Build Coastguard Worker * This library is distributed in the hope that it will be useful,
13*2d543d20SAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*2d543d20SAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15*2d543d20SAndroid Build Coastguard Worker * Lesser General Public License for more details.
16*2d543d20SAndroid Build Coastguard Worker *
17*2d543d20SAndroid Build Coastguard Worker * You should have received a copy of the GNU Lesser General Public
18*2d543d20SAndroid Build Coastguard Worker * License along with this library; if not, write to the Free Software
19*2d543d20SAndroid Build Coastguard Worker * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20*2d543d20SAndroid Build Coastguard Worker */
21*2d543d20SAndroid Build Coastguard Worker
22*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
23*2d543d20SAndroid Build Coastguard Worker
24*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/flask_types.h>
25*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/conditional.h>
26*2d543d20SAndroid Build Coastguard Worker
27*2d543d20SAndroid Build Coastguard Worker #include "private.h"
28*2d543d20SAndroid Build Coastguard Worker #include "debug.h"
29*2d543d20SAndroid Build Coastguard Worker
30*2d543d20SAndroid Build Coastguard Worker /* move all type rules to top of t/f lists to help kernel on evaluation */
cond_optimize(cond_av_list_t ** l)31*2d543d20SAndroid Build Coastguard Worker static void cond_optimize(cond_av_list_t ** l)
32*2d543d20SAndroid Build Coastguard Worker {
33*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *top, *p, *cur;
34*2d543d20SAndroid Build Coastguard Worker
35*2d543d20SAndroid Build Coastguard Worker top = p = cur = *l;
36*2d543d20SAndroid Build Coastguard Worker
37*2d543d20SAndroid Build Coastguard Worker while (cur) {
38*2d543d20SAndroid Build Coastguard Worker if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) {
39*2d543d20SAndroid Build Coastguard Worker p->next = cur->next;
40*2d543d20SAndroid Build Coastguard Worker cur->next = top;
41*2d543d20SAndroid Build Coastguard Worker top = cur;
42*2d543d20SAndroid Build Coastguard Worker cur = p->next;
43*2d543d20SAndroid Build Coastguard Worker } else {
44*2d543d20SAndroid Build Coastguard Worker p = cur;
45*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
46*2d543d20SAndroid Build Coastguard Worker }
47*2d543d20SAndroid Build Coastguard Worker }
48*2d543d20SAndroid Build Coastguard Worker *l = top;
49*2d543d20SAndroid Build Coastguard Worker }
50*2d543d20SAndroid Build Coastguard Worker
51*2d543d20SAndroid Build Coastguard Worker /* reorder t/f lists for kernel */
cond_optimize_lists(cond_list_t * cl)52*2d543d20SAndroid Build Coastguard Worker void cond_optimize_lists(cond_list_t * cl)
53*2d543d20SAndroid Build Coastguard Worker {
54*2d543d20SAndroid Build Coastguard Worker cond_list_t *n;
55*2d543d20SAndroid Build Coastguard Worker
56*2d543d20SAndroid Build Coastguard Worker for (n = cl; n != NULL; n = n->next) {
57*2d543d20SAndroid Build Coastguard Worker cond_optimize(&n->true_list);
58*2d543d20SAndroid Build Coastguard Worker cond_optimize(&n->false_list);
59*2d543d20SAndroid Build Coastguard Worker }
60*2d543d20SAndroid Build Coastguard Worker }
61*2d543d20SAndroid Build Coastguard Worker
bool_present(unsigned int target,unsigned int bools[],unsigned int num_bools)62*2d543d20SAndroid Build Coastguard Worker static int bool_present(unsigned int target, unsigned int bools[],
63*2d543d20SAndroid Build Coastguard Worker unsigned int num_bools)
64*2d543d20SAndroid Build Coastguard Worker {
65*2d543d20SAndroid Build Coastguard Worker unsigned int i = 0;
66*2d543d20SAndroid Build Coastguard Worker int ret = 1;
67*2d543d20SAndroid Build Coastguard Worker
68*2d543d20SAndroid Build Coastguard Worker if (num_bools > COND_MAX_BOOLS) {
69*2d543d20SAndroid Build Coastguard Worker return 0;
70*2d543d20SAndroid Build Coastguard Worker }
71*2d543d20SAndroid Build Coastguard Worker while (i < num_bools && target != bools[i])
72*2d543d20SAndroid Build Coastguard Worker i++;
73*2d543d20SAndroid Build Coastguard Worker if (i == num_bools)
74*2d543d20SAndroid Build Coastguard Worker ret = 0; /* got to end w/o match */
75*2d543d20SAndroid Build Coastguard Worker return ret;
76*2d543d20SAndroid Build Coastguard Worker }
77*2d543d20SAndroid Build Coastguard Worker
same_bools(cond_node_t * a,cond_node_t * b)78*2d543d20SAndroid Build Coastguard Worker static int same_bools(cond_node_t * a, cond_node_t * b)
79*2d543d20SAndroid Build Coastguard Worker {
80*2d543d20SAndroid Build Coastguard Worker unsigned int i, x;
81*2d543d20SAndroid Build Coastguard Worker
82*2d543d20SAndroid Build Coastguard Worker x = a->nbools;
83*2d543d20SAndroid Build Coastguard Worker
84*2d543d20SAndroid Build Coastguard Worker /* same number of bools? */
85*2d543d20SAndroid Build Coastguard Worker if (x != b->nbools)
86*2d543d20SAndroid Build Coastguard Worker return 0;
87*2d543d20SAndroid Build Coastguard Worker
88*2d543d20SAndroid Build Coastguard Worker /* make sure all the bools in a are also in b */
89*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < x; i++)
90*2d543d20SAndroid Build Coastguard Worker if (!bool_present(a->bool_ids[i], b->bool_ids, x))
91*2d543d20SAndroid Build Coastguard Worker return 0;
92*2d543d20SAndroid Build Coastguard Worker return 1;
93*2d543d20SAndroid Build Coastguard Worker }
94*2d543d20SAndroid Build Coastguard Worker
95*2d543d20SAndroid Build Coastguard Worker /*
96*2d543d20SAndroid Build Coastguard Worker * Determine if two conditional expressions are equal.
97*2d543d20SAndroid Build Coastguard Worker */
cond_expr_equal(cond_node_t * a,cond_node_t * b)98*2d543d20SAndroid Build Coastguard Worker int cond_expr_equal(cond_node_t * a, cond_node_t * b)
99*2d543d20SAndroid Build Coastguard Worker {
100*2d543d20SAndroid Build Coastguard Worker cond_expr_t *cur_a, *cur_b;
101*2d543d20SAndroid Build Coastguard Worker
102*2d543d20SAndroid Build Coastguard Worker if (a == NULL || b == NULL)
103*2d543d20SAndroid Build Coastguard Worker return 0;
104*2d543d20SAndroid Build Coastguard Worker
105*2d543d20SAndroid Build Coastguard Worker if (a->nbools != b->nbools)
106*2d543d20SAndroid Build Coastguard Worker return 0;
107*2d543d20SAndroid Build Coastguard Worker
108*2d543d20SAndroid Build Coastguard Worker /* if exprs have <= COND_MAX_BOOLS we can check the precompute values
109*2d543d20SAndroid Build Coastguard Worker * for the expressions.
110*2d543d20SAndroid Build Coastguard Worker */
111*2d543d20SAndroid Build Coastguard Worker if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) {
112*2d543d20SAndroid Build Coastguard Worker if (!same_bools(a, b))
113*2d543d20SAndroid Build Coastguard Worker return 0;
114*2d543d20SAndroid Build Coastguard Worker return (a->expr_pre_comp == b->expr_pre_comp);
115*2d543d20SAndroid Build Coastguard Worker }
116*2d543d20SAndroid Build Coastguard Worker
117*2d543d20SAndroid Build Coastguard Worker /* for long expressions we check for exactly the same expression */
118*2d543d20SAndroid Build Coastguard Worker cur_a = a->expr;
119*2d543d20SAndroid Build Coastguard Worker cur_b = b->expr;
120*2d543d20SAndroid Build Coastguard Worker while (1) {
121*2d543d20SAndroid Build Coastguard Worker if (cur_a == NULL && cur_b == NULL)
122*2d543d20SAndroid Build Coastguard Worker return 1;
123*2d543d20SAndroid Build Coastguard Worker else if (cur_a == NULL || cur_b == NULL)
124*2d543d20SAndroid Build Coastguard Worker return 0;
125*2d543d20SAndroid Build Coastguard Worker if (cur_a->expr_type != cur_b->expr_type)
126*2d543d20SAndroid Build Coastguard Worker return 0;
127*2d543d20SAndroid Build Coastguard Worker if (cur_a->expr_type == COND_BOOL) {
128*2d543d20SAndroid Build Coastguard Worker if (cur_a->boolean != cur_b->boolean)
129*2d543d20SAndroid Build Coastguard Worker return 0;
130*2d543d20SAndroid Build Coastguard Worker }
131*2d543d20SAndroid Build Coastguard Worker cur_a = cur_a->next;
132*2d543d20SAndroid Build Coastguard Worker cur_b = cur_b->next;
133*2d543d20SAndroid Build Coastguard Worker }
134*2d543d20SAndroid Build Coastguard Worker return 1;
135*2d543d20SAndroid Build Coastguard Worker }
136*2d543d20SAndroid Build Coastguard Worker
137*2d543d20SAndroid Build Coastguard Worker /* Create a new conditional node, optionally copying
138*2d543d20SAndroid Build Coastguard Worker * the conditional expression from an existing node.
139*2d543d20SAndroid Build Coastguard Worker * If node is NULL then a new node will be created
140*2d543d20SAndroid Build Coastguard Worker * with no conditional expression.
141*2d543d20SAndroid Build Coastguard Worker */
cond_node_create(policydb_t * p,cond_node_t * node)142*2d543d20SAndroid Build Coastguard Worker cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node)
143*2d543d20SAndroid Build Coastguard Worker {
144*2d543d20SAndroid Build Coastguard Worker cond_node_t *new_node;
145*2d543d20SAndroid Build Coastguard Worker unsigned int i;
146*2d543d20SAndroid Build Coastguard Worker
147*2d543d20SAndroid Build Coastguard Worker new_node = (cond_node_t *)malloc(sizeof(cond_node_t));
148*2d543d20SAndroid Build Coastguard Worker if (!new_node) {
149*2d543d20SAndroid Build Coastguard Worker return NULL;
150*2d543d20SAndroid Build Coastguard Worker }
151*2d543d20SAndroid Build Coastguard Worker memset(new_node, 0, sizeof(cond_node_t));
152*2d543d20SAndroid Build Coastguard Worker
153*2d543d20SAndroid Build Coastguard Worker if (node) {
154*2d543d20SAndroid Build Coastguard Worker new_node->expr = cond_copy_expr(node->expr);
155*2d543d20SAndroid Build Coastguard Worker if (!new_node->expr) {
156*2d543d20SAndroid Build Coastguard Worker free(new_node);
157*2d543d20SAndroid Build Coastguard Worker return NULL;
158*2d543d20SAndroid Build Coastguard Worker }
159*2d543d20SAndroid Build Coastguard Worker new_node->cur_state = cond_evaluate_expr(p, new_node->expr);
160*2d543d20SAndroid Build Coastguard Worker new_node->nbools = node->nbools;
161*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++)
162*2d543d20SAndroid Build Coastguard Worker new_node->bool_ids[i] = node->bool_ids[i];
163*2d543d20SAndroid Build Coastguard Worker new_node->expr_pre_comp = node->expr_pre_comp;
164*2d543d20SAndroid Build Coastguard Worker new_node->flags = node->flags;
165*2d543d20SAndroid Build Coastguard Worker }
166*2d543d20SAndroid Build Coastguard Worker
167*2d543d20SAndroid Build Coastguard Worker return new_node;
168*2d543d20SAndroid Build Coastguard Worker }
169*2d543d20SAndroid Build Coastguard Worker
170*2d543d20SAndroid Build Coastguard Worker /* Find a conditional (the needle) within a list of existing ones (the
171*2d543d20SAndroid Build Coastguard Worker * haystack) that has a matching expression. If found, return a
172*2d543d20SAndroid Build Coastguard Worker * pointer to the existing node, setting 'was_created' to 0.
173*2d543d20SAndroid Build Coastguard Worker * Otherwise create a new one and return it, setting 'was_created' to
174*2d543d20SAndroid Build Coastguard Worker * 1. */
cond_node_find(policydb_t * p,cond_node_t * needle,cond_node_t * haystack,int * was_created)175*2d543d20SAndroid Build Coastguard Worker cond_node_t *cond_node_find(policydb_t * p,
176*2d543d20SAndroid Build Coastguard Worker cond_node_t * needle, cond_node_t * haystack,
177*2d543d20SAndroid Build Coastguard Worker int *was_created)
178*2d543d20SAndroid Build Coastguard Worker {
179*2d543d20SAndroid Build Coastguard Worker while (haystack) {
180*2d543d20SAndroid Build Coastguard Worker if (cond_expr_equal(needle, haystack)) {
181*2d543d20SAndroid Build Coastguard Worker *was_created = 0;
182*2d543d20SAndroid Build Coastguard Worker return haystack;
183*2d543d20SAndroid Build Coastguard Worker }
184*2d543d20SAndroid Build Coastguard Worker haystack = haystack->next;
185*2d543d20SAndroid Build Coastguard Worker }
186*2d543d20SAndroid Build Coastguard Worker *was_created = 1;
187*2d543d20SAndroid Build Coastguard Worker
188*2d543d20SAndroid Build Coastguard Worker return cond_node_create(p, needle);
189*2d543d20SAndroid Build Coastguard Worker }
190*2d543d20SAndroid Build Coastguard Worker
191*2d543d20SAndroid Build Coastguard Worker /* return either a pre-existing matching node or create a new node */
cond_node_search(policydb_t * p,cond_node_t * list,cond_node_t * cn)192*2d543d20SAndroid Build Coastguard Worker cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
193*2d543d20SAndroid Build Coastguard Worker cond_node_t * cn)
194*2d543d20SAndroid Build Coastguard Worker {
195*2d543d20SAndroid Build Coastguard Worker int was_created;
196*2d543d20SAndroid Build Coastguard Worker cond_node_t *result = cond_node_find(p, cn, list, &was_created);
197*2d543d20SAndroid Build Coastguard Worker if (result != NULL && was_created) {
198*2d543d20SAndroid Build Coastguard Worker /* add conditional node to policy list */
199*2d543d20SAndroid Build Coastguard Worker result->next = p->cond_list;
200*2d543d20SAndroid Build Coastguard Worker p->cond_list = result;
201*2d543d20SAndroid Build Coastguard Worker }
202*2d543d20SAndroid Build Coastguard Worker return result;
203*2d543d20SAndroid Build Coastguard Worker }
204*2d543d20SAndroid Build Coastguard Worker
205*2d543d20SAndroid Build Coastguard Worker /*
206*2d543d20SAndroid Build Coastguard Worker * cond_evaluate_expr evaluates a conditional expr
207*2d543d20SAndroid Build Coastguard Worker * in reverse polish notation. It returns true (1), false (0),
208*2d543d20SAndroid Build Coastguard Worker * or undefined (-1). Undefined occurs when the expression
209*2d543d20SAndroid Build Coastguard Worker * exceeds the stack depth of COND_EXPR_MAXDEPTH.
210*2d543d20SAndroid Build Coastguard Worker */
cond_evaluate_expr(policydb_t * p,cond_expr_t * expr)211*2d543d20SAndroid Build Coastguard Worker int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr)
212*2d543d20SAndroid Build Coastguard Worker {
213*2d543d20SAndroid Build Coastguard Worker
214*2d543d20SAndroid Build Coastguard Worker cond_expr_t *cur;
215*2d543d20SAndroid Build Coastguard Worker int s[COND_EXPR_MAXDEPTH];
216*2d543d20SAndroid Build Coastguard Worker int sp = -1;
217*2d543d20SAndroid Build Coastguard Worker
218*2d543d20SAndroid Build Coastguard Worker s[0] = -1;
219*2d543d20SAndroid Build Coastguard Worker
220*2d543d20SAndroid Build Coastguard Worker for (cur = expr; cur != NULL; cur = cur->next) {
221*2d543d20SAndroid Build Coastguard Worker switch (cur->expr_type) {
222*2d543d20SAndroid Build Coastguard Worker case COND_BOOL:
223*2d543d20SAndroid Build Coastguard Worker if (sp == (COND_EXPR_MAXDEPTH - 1))
224*2d543d20SAndroid Build Coastguard Worker return -1;
225*2d543d20SAndroid Build Coastguard Worker sp++;
226*2d543d20SAndroid Build Coastguard Worker s[sp] = p->bool_val_to_struct[cur->boolean - 1]->state;
227*2d543d20SAndroid Build Coastguard Worker break;
228*2d543d20SAndroid Build Coastguard Worker case COND_NOT:
229*2d543d20SAndroid Build Coastguard Worker if (sp < 0)
230*2d543d20SAndroid Build Coastguard Worker return -1;
231*2d543d20SAndroid Build Coastguard Worker s[sp] = !s[sp];
232*2d543d20SAndroid Build Coastguard Worker break;
233*2d543d20SAndroid Build Coastguard Worker case COND_OR:
234*2d543d20SAndroid Build Coastguard Worker if (sp < 1)
235*2d543d20SAndroid Build Coastguard Worker return -1;
236*2d543d20SAndroid Build Coastguard Worker sp--;
237*2d543d20SAndroid Build Coastguard Worker s[sp] |= s[sp + 1];
238*2d543d20SAndroid Build Coastguard Worker break;
239*2d543d20SAndroid Build Coastguard Worker case COND_AND:
240*2d543d20SAndroid Build Coastguard Worker if (sp < 1)
241*2d543d20SAndroid Build Coastguard Worker return -1;
242*2d543d20SAndroid Build Coastguard Worker sp--;
243*2d543d20SAndroid Build Coastguard Worker s[sp] &= s[sp + 1];
244*2d543d20SAndroid Build Coastguard Worker break;
245*2d543d20SAndroid Build Coastguard Worker case COND_XOR:
246*2d543d20SAndroid Build Coastguard Worker if (sp < 1)
247*2d543d20SAndroid Build Coastguard Worker return -1;
248*2d543d20SAndroid Build Coastguard Worker sp--;
249*2d543d20SAndroid Build Coastguard Worker s[sp] ^= s[sp + 1];
250*2d543d20SAndroid Build Coastguard Worker break;
251*2d543d20SAndroid Build Coastguard Worker case COND_EQ:
252*2d543d20SAndroid Build Coastguard Worker if (sp < 1)
253*2d543d20SAndroid Build Coastguard Worker return -1;
254*2d543d20SAndroid Build Coastguard Worker sp--;
255*2d543d20SAndroid Build Coastguard Worker s[sp] = (s[sp] == s[sp + 1]);
256*2d543d20SAndroid Build Coastguard Worker break;
257*2d543d20SAndroid Build Coastguard Worker case COND_NEQ:
258*2d543d20SAndroid Build Coastguard Worker if (sp < 1)
259*2d543d20SAndroid Build Coastguard Worker return -1;
260*2d543d20SAndroid Build Coastguard Worker sp--;
261*2d543d20SAndroid Build Coastguard Worker s[sp] = (s[sp] != s[sp + 1]);
262*2d543d20SAndroid Build Coastguard Worker break;
263*2d543d20SAndroid Build Coastguard Worker default:
264*2d543d20SAndroid Build Coastguard Worker return -1;
265*2d543d20SAndroid Build Coastguard Worker }
266*2d543d20SAndroid Build Coastguard Worker }
267*2d543d20SAndroid Build Coastguard Worker return s[0];
268*2d543d20SAndroid Build Coastguard Worker }
269*2d543d20SAndroid Build Coastguard Worker
cond_copy_expr(cond_expr_t * expr)270*2d543d20SAndroid Build Coastguard Worker cond_expr_t *cond_copy_expr(cond_expr_t * expr)
271*2d543d20SAndroid Build Coastguard Worker {
272*2d543d20SAndroid Build Coastguard Worker cond_expr_t *cur, *head, *tail, *new_expr;
273*2d543d20SAndroid Build Coastguard Worker tail = head = NULL;
274*2d543d20SAndroid Build Coastguard Worker cur = expr;
275*2d543d20SAndroid Build Coastguard Worker while (cur) {
276*2d543d20SAndroid Build Coastguard Worker new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t));
277*2d543d20SAndroid Build Coastguard Worker if (!new_expr)
278*2d543d20SAndroid Build Coastguard Worker goto free_head;
279*2d543d20SAndroid Build Coastguard Worker memset(new_expr, 0, sizeof(cond_expr_t));
280*2d543d20SAndroid Build Coastguard Worker
281*2d543d20SAndroid Build Coastguard Worker new_expr->expr_type = cur->expr_type;
282*2d543d20SAndroid Build Coastguard Worker new_expr->boolean = cur->boolean;
283*2d543d20SAndroid Build Coastguard Worker
284*2d543d20SAndroid Build Coastguard Worker if (!head)
285*2d543d20SAndroid Build Coastguard Worker head = new_expr;
286*2d543d20SAndroid Build Coastguard Worker if (tail)
287*2d543d20SAndroid Build Coastguard Worker tail->next = new_expr;
288*2d543d20SAndroid Build Coastguard Worker tail = new_expr;
289*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
290*2d543d20SAndroid Build Coastguard Worker }
291*2d543d20SAndroid Build Coastguard Worker return head;
292*2d543d20SAndroid Build Coastguard Worker
293*2d543d20SAndroid Build Coastguard Worker free_head:
294*2d543d20SAndroid Build Coastguard Worker while (head) {
295*2d543d20SAndroid Build Coastguard Worker tail = head->next;
296*2d543d20SAndroid Build Coastguard Worker free(head);
297*2d543d20SAndroid Build Coastguard Worker head = tail;
298*2d543d20SAndroid Build Coastguard Worker }
299*2d543d20SAndroid Build Coastguard Worker return NULL;
300*2d543d20SAndroid Build Coastguard Worker }
301*2d543d20SAndroid Build Coastguard Worker
302*2d543d20SAndroid Build Coastguard Worker /*
303*2d543d20SAndroid Build Coastguard Worker * evaluate_cond_node evaluates the conditional stored in
304*2d543d20SAndroid Build Coastguard Worker * a cond_node_t and if the result is different than the
305*2d543d20SAndroid Build Coastguard Worker * current state of the node it sets the rules in the true/false
306*2d543d20SAndroid Build Coastguard Worker * list appropriately. If the result of the expression is undefined
307*2d543d20SAndroid Build Coastguard Worker * all of the rules are disabled for safety.
308*2d543d20SAndroid Build Coastguard Worker */
evaluate_cond_node(policydb_t * p,cond_node_t * node)309*2d543d20SAndroid Build Coastguard Worker static int evaluate_cond_node(policydb_t * p, cond_node_t * node)
310*2d543d20SAndroid Build Coastguard Worker {
311*2d543d20SAndroid Build Coastguard Worker int new_state;
312*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *cur;
313*2d543d20SAndroid Build Coastguard Worker
314*2d543d20SAndroid Build Coastguard Worker new_state = cond_evaluate_expr(p, node->expr);
315*2d543d20SAndroid Build Coastguard Worker if (new_state != node->cur_state) {
316*2d543d20SAndroid Build Coastguard Worker node->cur_state = new_state;
317*2d543d20SAndroid Build Coastguard Worker if (new_state == -1)
318*2d543d20SAndroid Build Coastguard Worker WARN(NULL, "expression result was undefined - disabling all rules.");
319*2d543d20SAndroid Build Coastguard Worker /* turn the rules on or off */
320*2d543d20SAndroid Build Coastguard Worker for (cur = node->true_list; cur != NULL; cur = cur->next) {
321*2d543d20SAndroid Build Coastguard Worker if (new_state <= 0) {
322*2d543d20SAndroid Build Coastguard Worker cur->node->key.specified &= ~AVTAB_ENABLED;
323*2d543d20SAndroid Build Coastguard Worker } else {
324*2d543d20SAndroid Build Coastguard Worker cur->node->key.specified |= AVTAB_ENABLED;
325*2d543d20SAndroid Build Coastguard Worker }
326*2d543d20SAndroid Build Coastguard Worker }
327*2d543d20SAndroid Build Coastguard Worker
328*2d543d20SAndroid Build Coastguard Worker for (cur = node->false_list; cur != NULL; cur = cur->next) {
329*2d543d20SAndroid Build Coastguard Worker /* -1 or 1 */
330*2d543d20SAndroid Build Coastguard Worker if (new_state) {
331*2d543d20SAndroid Build Coastguard Worker cur->node->key.specified &= ~AVTAB_ENABLED;
332*2d543d20SAndroid Build Coastguard Worker } else {
333*2d543d20SAndroid Build Coastguard Worker cur->node->key.specified |= AVTAB_ENABLED;
334*2d543d20SAndroid Build Coastguard Worker }
335*2d543d20SAndroid Build Coastguard Worker }
336*2d543d20SAndroid Build Coastguard Worker }
337*2d543d20SAndroid Build Coastguard Worker return 0;
338*2d543d20SAndroid Build Coastguard Worker }
339*2d543d20SAndroid Build Coastguard Worker
340*2d543d20SAndroid Build Coastguard Worker /* precompute and simplify an expression if possible. If left with !expression, change
341*2d543d20SAndroid Build Coastguard Worker * to expression and switch t and f. precompute expression for expressions with limited
342*2d543d20SAndroid Build Coastguard Worker * number of bools.
343*2d543d20SAndroid Build Coastguard Worker */
cond_normalize_expr(policydb_t * p,cond_node_t * cn)344*2d543d20SAndroid Build Coastguard Worker int cond_normalize_expr(policydb_t * p, cond_node_t * cn)
345*2d543d20SAndroid Build Coastguard Worker {
346*2d543d20SAndroid Build Coastguard Worker cond_expr_t *ne, *e;
347*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *tmp;
348*2d543d20SAndroid Build Coastguard Worker unsigned int i, j, orig_value[COND_MAX_BOOLS];
349*2d543d20SAndroid Build Coastguard Worker int k;
350*2d543d20SAndroid Build Coastguard Worker uint32_t test = 0x0;
351*2d543d20SAndroid Build Coastguard Worker avrule_t *tmp2;
352*2d543d20SAndroid Build Coastguard Worker
353*2d543d20SAndroid Build Coastguard Worker cn->nbools = 0;
354*2d543d20SAndroid Build Coastguard Worker
355*2d543d20SAndroid Build Coastguard Worker memset(cn->bool_ids, 0, sizeof(cn->bool_ids));
356*2d543d20SAndroid Build Coastguard Worker cn->expr_pre_comp = 0x0;
357*2d543d20SAndroid Build Coastguard Worker
358*2d543d20SAndroid Build Coastguard Worker /* take care of !expr case */
359*2d543d20SAndroid Build Coastguard Worker ne = NULL;
360*2d543d20SAndroid Build Coastguard Worker e = cn->expr;
361*2d543d20SAndroid Build Coastguard Worker
362*2d543d20SAndroid Build Coastguard Worker /* because it's RPN look at last element */
363*2d543d20SAndroid Build Coastguard Worker while (e->next != NULL) {
364*2d543d20SAndroid Build Coastguard Worker ne = e;
365*2d543d20SAndroid Build Coastguard Worker e = e->next;
366*2d543d20SAndroid Build Coastguard Worker }
367*2d543d20SAndroid Build Coastguard Worker if (e->expr_type == COND_NOT) {
368*2d543d20SAndroid Build Coastguard Worker if (ne) {
369*2d543d20SAndroid Build Coastguard Worker ne->next = NULL;
370*2d543d20SAndroid Build Coastguard Worker } else { /* ne should never be NULL */
371*2d543d20SAndroid Build Coastguard Worker ERR(NULL, "Found expr with no bools and only a ! - this should never happen.");
372*2d543d20SAndroid Build Coastguard Worker return -1;
373*2d543d20SAndroid Build Coastguard Worker }
374*2d543d20SAndroid Build Coastguard Worker /* swap the true and false lists */
375*2d543d20SAndroid Build Coastguard Worker tmp = cn->true_list;
376*2d543d20SAndroid Build Coastguard Worker cn->true_list = cn->false_list;
377*2d543d20SAndroid Build Coastguard Worker cn->false_list = tmp;
378*2d543d20SAndroid Build Coastguard Worker tmp2 = cn->avtrue_list;
379*2d543d20SAndroid Build Coastguard Worker cn->avtrue_list = cn->avfalse_list;
380*2d543d20SAndroid Build Coastguard Worker cn->avfalse_list = tmp2;
381*2d543d20SAndroid Build Coastguard Worker
382*2d543d20SAndroid Build Coastguard Worker /* free the "not" node in the list */
383*2d543d20SAndroid Build Coastguard Worker free(e);
384*2d543d20SAndroid Build Coastguard Worker }
385*2d543d20SAndroid Build Coastguard Worker
386*2d543d20SAndroid Build Coastguard Worker /* find all the bools in the expression */
387*2d543d20SAndroid Build Coastguard Worker for (e = cn->expr; e != NULL; e = e->next) {
388*2d543d20SAndroid Build Coastguard Worker switch (e->expr_type) {
389*2d543d20SAndroid Build Coastguard Worker case COND_BOOL:
390*2d543d20SAndroid Build Coastguard Worker /* see if we've already seen this bool */
391*2d543d20SAndroid Build Coastguard Worker if (!bool_present(e->boolean, cn->bool_ids, cn->nbools)) {
392*2d543d20SAndroid Build Coastguard Worker /* count em all but only record up to COND_MAX_BOOLS */
393*2d543d20SAndroid Build Coastguard Worker if (cn->nbools < COND_MAX_BOOLS)
394*2d543d20SAndroid Build Coastguard Worker cn->bool_ids[cn->nbools++] = e->boolean;
395*2d543d20SAndroid Build Coastguard Worker else
396*2d543d20SAndroid Build Coastguard Worker cn->nbools++;
397*2d543d20SAndroid Build Coastguard Worker }
398*2d543d20SAndroid Build Coastguard Worker break;
399*2d543d20SAndroid Build Coastguard Worker default:
400*2d543d20SAndroid Build Coastguard Worker break;
401*2d543d20SAndroid Build Coastguard Worker }
402*2d543d20SAndroid Build Coastguard Worker }
403*2d543d20SAndroid Build Coastguard Worker
404*2d543d20SAndroid Build Coastguard Worker /* only precompute for exprs with <= COND_AX_BOOLS */
405*2d543d20SAndroid Build Coastguard Worker if (cn->nbools <= COND_MAX_BOOLS) {
406*2d543d20SAndroid Build Coastguard Worker /* save the default values for the bools so we can play with them */
407*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < cn->nbools; i++) {
408*2d543d20SAndroid Build Coastguard Worker orig_value[i] =
409*2d543d20SAndroid Build Coastguard Worker p->bool_val_to_struct[cn->bool_ids[i] - 1]->state;
410*2d543d20SAndroid Build Coastguard Worker }
411*2d543d20SAndroid Build Coastguard Worker
412*2d543d20SAndroid Build Coastguard Worker /* loop through all possible combinations of values for bools in expression */
413*2d543d20SAndroid Build Coastguard Worker for (test = 0x0; test < (UINT32_C(1) << cn->nbools); test++) {
414*2d543d20SAndroid Build Coastguard Worker /* temporarily set the value for all the bools in the
415*2d543d20SAndroid Build Coastguard Worker * expression using the corr. bit in test */
416*2d543d20SAndroid Build Coastguard Worker for (j = 0; j < cn->nbools; j++) {
417*2d543d20SAndroid Build Coastguard Worker p->bool_val_to_struct[cn->bool_ids[j] -
418*2d543d20SAndroid Build Coastguard Worker 1]->state =
419*2d543d20SAndroid Build Coastguard Worker (test & (UINT32_C(1) << j)) ? 1 : 0;
420*2d543d20SAndroid Build Coastguard Worker }
421*2d543d20SAndroid Build Coastguard Worker k = cond_evaluate_expr(p, cn->expr);
422*2d543d20SAndroid Build Coastguard Worker if (k == -1) {
423*2d543d20SAndroid Build Coastguard Worker ERR(NULL, "While testing expression, expression result "
424*2d543d20SAndroid Build Coastguard Worker "was undefined - this should never happen.");
425*2d543d20SAndroid Build Coastguard Worker return -1;
426*2d543d20SAndroid Build Coastguard Worker }
427*2d543d20SAndroid Build Coastguard Worker /* set the bit if expression evaluates true */
428*2d543d20SAndroid Build Coastguard Worker if (k)
429*2d543d20SAndroid Build Coastguard Worker cn->expr_pre_comp |= UINT32_C(1) << test;
430*2d543d20SAndroid Build Coastguard Worker }
431*2d543d20SAndroid Build Coastguard Worker
432*2d543d20SAndroid Build Coastguard Worker /* restore bool default values */
433*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < cn->nbools; i++)
434*2d543d20SAndroid Build Coastguard Worker p->bool_val_to_struct[cn->bool_ids[i] - 1]->state =
435*2d543d20SAndroid Build Coastguard Worker orig_value[i];
436*2d543d20SAndroid Build Coastguard Worker }
437*2d543d20SAndroid Build Coastguard Worker return 0;
438*2d543d20SAndroid Build Coastguard Worker }
439*2d543d20SAndroid Build Coastguard Worker
evaluate_conds(policydb_t * p)440*2d543d20SAndroid Build Coastguard Worker int evaluate_conds(policydb_t * p)
441*2d543d20SAndroid Build Coastguard Worker {
442*2d543d20SAndroid Build Coastguard Worker int ret;
443*2d543d20SAndroid Build Coastguard Worker cond_node_t *cur;
444*2d543d20SAndroid Build Coastguard Worker
445*2d543d20SAndroid Build Coastguard Worker for (cur = p->cond_list; cur != NULL; cur = cur->next) {
446*2d543d20SAndroid Build Coastguard Worker ret = evaluate_cond_node(p, cur);
447*2d543d20SAndroid Build Coastguard Worker if (ret)
448*2d543d20SAndroid Build Coastguard Worker return ret;
449*2d543d20SAndroid Build Coastguard Worker }
450*2d543d20SAndroid Build Coastguard Worker return 0;
451*2d543d20SAndroid Build Coastguard Worker }
452*2d543d20SAndroid Build Coastguard Worker
cond_policydb_init(policydb_t * p)453*2d543d20SAndroid Build Coastguard Worker int cond_policydb_init(policydb_t * p)
454*2d543d20SAndroid Build Coastguard Worker {
455*2d543d20SAndroid Build Coastguard Worker p->bool_val_to_struct = NULL;
456*2d543d20SAndroid Build Coastguard Worker p->cond_list = NULL;
457*2d543d20SAndroid Build Coastguard Worker if (avtab_init(&p->te_cond_avtab))
458*2d543d20SAndroid Build Coastguard Worker return -1;
459*2d543d20SAndroid Build Coastguard Worker
460*2d543d20SAndroid Build Coastguard Worker return 0;
461*2d543d20SAndroid Build Coastguard Worker }
462*2d543d20SAndroid Build Coastguard Worker
cond_av_list_destroy(cond_av_list_t * list)463*2d543d20SAndroid Build Coastguard Worker void cond_av_list_destroy(cond_av_list_t * list)
464*2d543d20SAndroid Build Coastguard Worker {
465*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *cur, *next;
466*2d543d20SAndroid Build Coastguard Worker for (cur = list; cur != NULL; cur = next) {
467*2d543d20SAndroid Build Coastguard Worker next = cur->next;
468*2d543d20SAndroid Build Coastguard Worker /* the avtab_ptr_t node is destroy by the avtab */
469*2d543d20SAndroid Build Coastguard Worker free(cur);
470*2d543d20SAndroid Build Coastguard Worker }
471*2d543d20SAndroid Build Coastguard Worker }
472*2d543d20SAndroid Build Coastguard Worker
cond_expr_destroy(cond_expr_t * expr)473*2d543d20SAndroid Build Coastguard Worker void cond_expr_destroy(cond_expr_t * expr)
474*2d543d20SAndroid Build Coastguard Worker {
475*2d543d20SAndroid Build Coastguard Worker cond_expr_t *cur_expr, *next_expr;
476*2d543d20SAndroid Build Coastguard Worker
477*2d543d20SAndroid Build Coastguard Worker if (!expr)
478*2d543d20SAndroid Build Coastguard Worker return;
479*2d543d20SAndroid Build Coastguard Worker
480*2d543d20SAndroid Build Coastguard Worker for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) {
481*2d543d20SAndroid Build Coastguard Worker next_expr = cur_expr->next;
482*2d543d20SAndroid Build Coastguard Worker free(cur_expr);
483*2d543d20SAndroid Build Coastguard Worker }
484*2d543d20SAndroid Build Coastguard Worker }
485*2d543d20SAndroid Build Coastguard Worker
cond_node_destroy(cond_node_t * node)486*2d543d20SAndroid Build Coastguard Worker void cond_node_destroy(cond_node_t * node)
487*2d543d20SAndroid Build Coastguard Worker {
488*2d543d20SAndroid Build Coastguard Worker if (!node)
489*2d543d20SAndroid Build Coastguard Worker return;
490*2d543d20SAndroid Build Coastguard Worker
491*2d543d20SAndroid Build Coastguard Worker cond_expr_destroy(node->expr);
492*2d543d20SAndroid Build Coastguard Worker avrule_list_destroy(node->avtrue_list);
493*2d543d20SAndroid Build Coastguard Worker avrule_list_destroy(node->avfalse_list);
494*2d543d20SAndroid Build Coastguard Worker cond_av_list_destroy(node->true_list);
495*2d543d20SAndroid Build Coastguard Worker cond_av_list_destroy(node->false_list);
496*2d543d20SAndroid Build Coastguard Worker }
497*2d543d20SAndroid Build Coastguard Worker
cond_list_destroy(cond_list_t * list)498*2d543d20SAndroid Build Coastguard Worker void cond_list_destroy(cond_list_t * list)
499*2d543d20SAndroid Build Coastguard Worker {
500*2d543d20SAndroid Build Coastguard Worker cond_node_t *next, *cur;
501*2d543d20SAndroid Build Coastguard Worker
502*2d543d20SAndroid Build Coastguard Worker if (list == NULL)
503*2d543d20SAndroid Build Coastguard Worker return;
504*2d543d20SAndroid Build Coastguard Worker
505*2d543d20SAndroid Build Coastguard Worker for (cur = list; cur != NULL; cur = next) {
506*2d543d20SAndroid Build Coastguard Worker next = cur->next;
507*2d543d20SAndroid Build Coastguard Worker cond_node_destroy(cur);
508*2d543d20SAndroid Build Coastguard Worker free(cur);
509*2d543d20SAndroid Build Coastguard Worker }
510*2d543d20SAndroid Build Coastguard Worker }
511*2d543d20SAndroid Build Coastguard Worker
cond_policydb_destroy(policydb_t * p)512*2d543d20SAndroid Build Coastguard Worker void cond_policydb_destroy(policydb_t * p)
513*2d543d20SAndroid Build Coastguard Worker {
514*2d543d20SAndroid Build Coastguard Worker if (p->bool_val_to_struct != NULL)
515*2d543d20SAndroid Build Coastguard Worker free(p->bool_val_to_struct);
516*2d543d20SAndroid Build Coastguard Worker avtab_destroy(&p->te_cond_avtab);
517*2d543d20SAndroid Build Coastguard Worker cond_list_destroy(p->cond_list);
518*2d543d20SAndroid Build Coastguard Worker }
519*2d543d20SAndroid Build Coastguard Worker
cond_init_bool_indexes(policydb_t * p)520*2d543d20SAndroid Build Coastguard Worker int cond_init_bool_indexes(policydb_t * p)
521*2d543d20SAndroid Build Coastguard Worker {
522*2d543d20SAndroid Build Coastguard Worker if (p->bool_val_to_struct)
523*2d543d20SAndroid Build Coastguard Worker free(p->bool_val_to_struct);
524*2d543d20SAndroid Build Coastguard Worker p->bool_val_to_struct = (cond_bool_datum_t **)
525*2d543d20SAndroid Build Coastguard Worker calloc(p->p_bools.nprim, sizeof(cond_bool_datum_t *));
526*2d543d20SAndroid Build Coastguard Worker if (!p->bool_val_to_struct)
527*2d543d20SAndroid Build Coastguard Worker return -1;
528*2d543d20SAndroid Build Coastguard Worker return 0;
529*2d543d20SAndroid Build Coastguard Worker }
530*2d543d20SAndroid Build Coastguard Worker
cond_destroy_bool(hashtab_key_t key,hashtab_datum_t datum,void * p)531*2d543d20SAndroid Build Coastguard Worker int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
532*2d543d20SAndroid Build Coastguard Worker __attribute__ ((unused)))
533*2d543d20SAndroid Build Coastguard Worker {
534*2d543d20SAndroid Build Coastguard Worker if (key)
535*2d543d20SAndroid Build Coastguard Worker free(key);
536*2d543d20SAndroid Build Coastguard Worker free(datum);
537*2d543d20SAndroid Build Coastguard Worker return 0;
538*2d543d20SAndroid Build Coastguard Worker }
539*2d543d20SAndroid Build Coastguard Worker
cond_index_bool(hashtab_key_t key,hashtab_datum_t datum,void * datap)540*2d543d20SAndroid Build Coastguard Worker int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
541*2d543d20SAndroid Build Coastguard Worker {
542*2d543d20SAndroid Build Coastguard Worker policydb_t *p;
543*2d543d20SAndroid Build Coastguard Worker cond_bool_datum_t *booldatum;
544*2d543d20SAndroid Build Coastguard Worker
545*2d543d20SAndroid Build Coastguard Worker booldatum = datum;
546*2d543d20SAndroid Build Coastguard Worker p = datap;
547*2d543d20SAndroid Build Coastguard Worker
548*2d543d20SAndroid Build Coastguard Worker if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim)
549*2d543d20SAndroid Build Coastguard Worker return -EINVAL;
550*2d543d20SAndroid Build Coastguard Worker
551*2d543d20SAndroid Build Coastguard Worker if (p->p_bool_val_to_name[booldatum->s.value - 1] != NULL)
552*2d543d20SAndroid Build Coastguard Worker return -EINVAL;
553*2d543d20SAndroid Build Coastguard Worker
554*2d543d20SAndroid Build Coastguard Worker p->p_bool_val_to_name[booldatum->s.value - 1] = key;
555*2d543d20SAndroid Build Coastguard Worker p->bool_val_to_struct[booldatum->s.value - 1] = booldatum;
556*2d543d20SAndroid Build Coastguard Worker
557*2d543d20SAndroid Build Coastguard Worker return 0;
558*2d543d20SAndroid Build Coastguard Worker }
559*2d543d20SAndroid Build Coastguard Worker
bool_isvalid(cond_bool_datum_t * b)560*2d543d20SAndroid Build Coastguard Worker static int bool_isvalid(cond_bool_datum_t * b)
561*2d543d20SAndroid Build Coastguard Worker {
562*2d543d20SAndroid Build Coastguard Worker if (!(b->state == 0 || b->state == 1))
563*2d543d20SAndroid Build Coastguard Worker return 0;
564*2d543d20SAndroid Build Coastguard Worker return 1;
565*2d543d20SAndroid Build Coastguard Worker }
566*2d543d20SAndroid Build Coastguard Worker
cond_read_bool(policydb_t * p,hashtab_t h,struct policy_file * fp)567*2d543d20SAndroid Build Coastguard Worker int cond_read_bool(policydb_t * p,
568*2d543d20SAndroid Build Coastguard Worker hashtab_t h,
569*2d543d20SAndroid Build Coastguard Worker struct policy_file *fp)
570*2d543d20SAndroid Build Coastguard Worker {
571*2d543d20SAndroid Build Coastguard Worker char *key = 0;
572*2d543d20SAndroid Build Coastguard Worker cond_bool_datum_t *booldatum;
573*2d543d20SAndroid Build Coastguard Worker uint32_t buf[3], len;
574*2d543d20SAndroid Build Coastguard Worker int rc;
575*2d543d20SAndroid Build Coastguard Worker
576*2d543d20SAndroid Build Coastguard Worker booldatum = malloc(sizeof(cond_bool_datum_t));
577*2d543d20SAndroid Build Coastguard Worker if (!booldatum)
578*2d543d20SAndroid Build Coastguard Worker return -1;
579*2d543d20SAndroid Build Coastguard Worker memset(booldatum, 0, sizeof(cond_bool_datum_t));
580*2d543d20SAndroid Build Coastguard Worker
581*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
582*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
583*2d543d20SAndroid Build Coastguard Worker goto err;
584*2d543d20SAndroid Build Coastguard Worker
585*2d543d20SAndroid Build Coastguard Worker booldatum->s.value = le32_to_cpu(buf[0]);
586*2d543d20SAndroid Build Coastguard Worker booldatum->state = le32_to_cpu(buf[1]);
587*2d543d20SAndroid Build Coastguard Worker
588*2d543d20SAndroid Build Coastguard Worker if (!bool_isvalid(booldatum))
589*2d543d20SAndroid Build Coastguard Worker goto err;
590*2d543d20SAndroid Build Coastguard Worker
591*2d543d20SAndroid Build Coastguard Worker len = le32_to_cpu(buf[2]);
592*2d543d20SAndroid Build Coastguard Worker if (str_read(&key, fp, len))
593*2d543d20SAndroid Build Coastguard Worker goto err;
594*2d543d20SAndroid Build Coastguard Worker
595*2d543d20SAndroid Build Coastguard Worker if (p->policy_type != POLICY_KERN &&
596*2d543d20SAndroid Build Coastguard Worker p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
597*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t));
598*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
599*2d543d20SAndroid Build Coastguard Worker goto err;
600*2d543d20SAndroid Build Coastguard Worker booldatum->flags = le32_to_cpu(buf[0]);
601*2d543d20SAndroid Build Coastguard Worker }
602*2d543d20SAndroid Build Coastguard Worker
603*2d543d20SAndroid Build Coastguard Worker if (hashtab_insert(h, key, booldatum))
604*2d543d20SAndroid Build Coastguard Worker goto err;
605*2d543d20SAndroid Build Coastguard Worker
606*2d543d20SAndroid Build Coastguard Worker return 0;
607*2d543d20SAndroid Build Coastguard Worker err:
608*2d543d20SAndroid Build Coastguard Worker cond_destroy_bool(key, booldatum, 0);
609*2d543d20SAndroid Build Coastguard Worker return -1;
610*2d543d20SAndroid Build Coastguard Worker }
611*2d543d20SAndroid Build Coastguard Worker
612*2d543d20SAndroid Build Coastguard Worker struct cond_insertf_data {
613*2d543d20SAndroid Build Coastguard Worker struct policydb *p;
614*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *other;
615*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *head;
616*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *tail;
617*2d543d20SAndroid Build Coastguard Worker };
618*2d543d20SAndroid Build Coastguard Worker
cond_insertf(avtab_t * a,avtab_key_t * k,avtab_datum_t * d,void * ptr)619*2d543d20SAndroid Build Coastguard Worker static int cond_insertf(avtab_t * a
620*2d543d20SAndroid Build Coastguard Worker __attribute__ ((unused)), avtab_key_t * k,
621*2d543d20SAndroid Build Coastguard Worker avtab_datum_t * d, void *ptr)
622*2d543d20SAndroid Build Coastguard Worker {
623*2d543d20SAndroid Build Coastguard Worker struct cond_insertf_data *data = ptr;
624*2d543d20SAndroid Build Coastguard Worker struct policydb *p = data->p;
625*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *other = data->other, *list, *cur;
626*2d543d20SAndroid Build Coastguard Worker avtab_ptr_t node_ptr;
627*2d543d20SAndroid Build Coastguard Worker uint8_t found;
628*2d543d20SAndroid Build Coastguard Worker
629*2d543d20SAndroid Build Coastguard Worker /*
630*2d543d20SAndroid Build Coastguard Worker * For type rules we have to make certain there aren't any
631*2d543d20SAndroid Build Coastguard Worker * conflicting rules by searching the te_avtab and the
632*2d543d20SAndroid Build Coastguard Worker * cond_te_avtab.
633*2d543d20SAndroid Build Coastguard Worker */
634*2d543d20SAndroid Build Coastguard Worker if (k->specified & AVTAB_TYPE) {
635*2d543d20SAndroid Build Coastguard Worker if (avtab_search(&p->te_avtab, k)) {
636*2d543d20SAndroid Build Coastguard Worker WARN(NULL, "security: type rule already exists outside of a conditional.");
637*2d543d20SAndroid Build Coastguard Worker return -1;
638*2d543d20SAndroid Build Coastguard Worker }
639*2d543d20SAndroid Build Coastguard Worker /*
640*2d543d20SAndroid Build Coastguard Worker * If we are reading the false list other will be a pointer to
641*2d543d20SAndroid Build Coastguard Worker * the true list. We can have duplicate entries if there is only
642*2d543d20SAndroid Build Coastguard Worker * 1 other entry and it is in our true list.
643*2d543d20SAndroid Build Coastguard Worker *
644*2d543d20SAndroid Build Coastguard Worker * If we are reading the true list (other == NULL) there shouldn't
645*2d543d20SAndroid Build Coastguard Worker * be any other entries.
646*2d543d20SAndroid Build Coastguard Worker */
647*2d543d20SAndroid Build Coastguard Worker if (other) {
648*2d543d20SAndroid Build Coastguard Worker node_ptr = avtab_search_node(&p->te_cond_avtab, k);
649*2d543d20SAndroid Build Coastguard Worker if (node_ptr) {
650*2d543d20SAndroid Build Coastguard Worker if (avtab_search_node_next
651*2d543d20SAndroid Build Coastguard Worker (node_ptr, k->specified)) {
652*2d543d20SAndroid Build Coastguard Worker ERR(NULL, "security: too many conflicting type rules.");
653*2d543d20SAndroid Build Coastguard Worker return -1;
654*2d543d20SAndroid Build Coastguard Worker }
655*2d543d20SAndroid Build Coastguard Worker found = 0;
656*2d543d20SAndroid Build Coastguard Worker for (cur = other; cur != NULL; cur = cur->next) {
657*2d543d20SAndroid Build Coastguard Worker if (cur->node == node_ptr) {
658*2d543d20SAndroid Build Coastguard Worker found = 1;
659*2d543d20SAndroid Build Coastguard Worker break;
660*2d543d20SAndroid Build Coastguard Worker }
661*2d543d20SAndroid Build Coastguard Worker }
662*2d543d20SAndroid Build Coastguard Worker if (!found) {
663*2d543d20SAndroid Build Coastguard Worker ERR(NULL, "security: conflicting type rules.");
664*2d543d20SAndroid Build Coastguard Worker return -1;
665*2d543d20SAndroid Build Coastguard Worker }
666*2d543d20SAndroid Build Coastguard Worker }
667*2d543d20SAndroid Build Coastguard Worker } else {
668*2d543d20SAndroid Build Coastguard Worker if (avtab_search(&p->te_cond_avtab, k)) {
669*2d543d20SAndroid Build Coastguard Worker ERR(NULL, "security: conflicting type rules when adding type rule for true.");
670*2d543d20SAndroid Build Coastguard Worker return -1;
671*2d543d20SAndroid Build Coastguard Worker }
672*2d543d20SAndroid Build Coastguard Worker }
673*2d543d20SAndroid Build Coastguard Worker }
674*2d543d20SAndroid Build Coastguard Worker
675*2d543d20SAndroid Build Coastguard Worker node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
676*2d543d20SAndroid Build Coastguard Worker if (!node_ptr) {
677*2d543d20SAndroid Build Coastguard Worker ERR(NULL, "security: could not insert rule.");
678*2d543d20SAndroid Build Coastguard Worker return -1;
679*2d543d20SAndroid Build Coastguard Worker }
680*2d543d20SAndroid Build Coastguard Worker node_ptr->parse_context = (void *)1;
681*2d543d20SAndroid Build Coastguard Worker
682*2d543d20SAndroid Build Coastguard Worker list = malloc(sizeof(cond_av_list_t));
683*2d543d20SAndroid Build Coastguard Worker if (!list)
684*2d543d20SAndroid Build Coastguard Worker return -1;
685*2d543d20SAndroid Build Coastguard Worker memset(list, 0, sizeof(cond_av_list_t));
686*2d543d20SAndroid Build Coastguard Worker
687*2d543d20SAndroid Build Coastguard Worker list->node = node_ptr;
688*2d543d20SAndroid Build Coastguard Worker if (!data->head)
689*2d543d20SAndroid Build Coastguard Worker data->head = list;
690*2d543d20SAndroid Build Coastguard Worker else
691*2d543d20SAndroid Build Coastguard Worker data->tail->next = list;
692*2d543d20SAndroid Build Coastguard Worker data->tail = list;
693*2d543d20SAndroid Build Coastguard Worker return 0;
694*2d543d20SAndroid Build Coastguard Worker }
695*2d543d20SAndroid Build Coastguard Worker
cond_read_av_list(policydb_t * p,void * fp,cond_av_list_t ** ret_list,cond_av_list_t * other)696*2d543d20SAndroid Build Coastguard Worker static int cond_read_av_list(policydb_t * p, void *fp,
697*2d543d20SAndroid Build Coastguard Worker cond_av_list_t ** ret_list, cond_av_list_t * other)
698*2d543d20SAndroid Build Coastguard Worker {
699*2d543d20SAndroid Build Coastguard Worker unsigned int i;
700*2d543d20SAndroid Build Coastguard Worker int rc;
701*2d543d20SAndroid Build Coastguard Worker uint32_t buf[1], len;
702*2d543d20SAndroid Build Coastguard Worker struct cond_insertf_data data;
703*2d543d20SAndroid Build Coastguard Worker
704*2d543d20SAndroid Build Coastguard Worker *ret_list = NULL;
705*2d543d20SAndroid Build Coastguard Worker
706*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t));
707*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
708*2d543d20SAndroid Build Coastguard Worker return -1;
709*2d543d20SAndroid Build Coastguard Worker
710*2d543d20SAndroid Build Coastguard Worker len = le32_to_cpu(buf[0]);
711*2d543d20SAndroid Build Coastguard Worker if (len == 0) {
712*2d543d20SAndroid Build Coastguard Worker return 0;
713*2d543d20SAndroid Build Coastguard Worker }
714*2d543d20SAndroid Build Coastguard Worker
715*2d543d20SAndroid Build Coastguard Worker data.p = p;
716*2d543d20SAndroid Build Coastguard Worker data.other = other;
717*2d543d20SAndroid Build Coastguard Worker data.head = NULL;
718*2d543d20SAndroid Build Coastguard Worker data.tail = NULL;
719*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
720*2d543d20SAndroid Build Coastguard Worker rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab,
721*2d543d20SAndroid Build Coastguard Worker cond_insertf, &data);
722*2d543d20SAndroid Build Coastguard Worker if (rc) {
723*2d543d20SAndroid Build Coastguard Worker cond_av_list_destroy(data.head);
724*2d543d20SAndroid Build Coastguard Worker return rc;
725*2d543d20SAndroid Build Coastguard Worker }
726*2d543d20SAndroid Build Coastguard Worker
727*2d543d20SAndroid Build Coastguard Worker }
728*2d543d20SAndroid Build Coastguard Worker
729*2d543d20SAndroid Build Coastguard Worker *ret_list = data.head;
730*2d543d20SAndroid Build Coastguard Worker return 0;
731*2d543d20SAndroid Build Coastguard Worker }
732*2d543d20SAndroid Build Coastguard Worker
expr_isvalid(policydb_t * p,cond_expr_t * expr)733*2d543d20SAndroid Build Coastguard Worker static int expr_isvalid(policydb_t * p, cond_expr_t * expr)
734*2d543d20SAndroid Build Coastguard Worker {
735*2d543d20SAndroid Build Coastguard Worker if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
736*2d543d20SAndroid Build Coastguard Worker WARN(NULL, "security: conditional expressions uses unknown operator.");
737*2d543d20SAndroid Build Coastguard Worker return 0;
738*2d543d20SAndroid Build Coastguard Worker }
739*2d543d20SAndroid Build Coastguard Worker
740*2d543d20SAndroid Build Coastguard Worker if (expr->boolean > p->p_bools.nprim) {
741*2d543d20SAndroid Build Coastguard Worker WARN(NULL, "security: conditional expressions uses unknown bool.");
742*2d543d20SAndroid Build Coastguard Worker return 0;
743*2d543d20SAndroid Build Coastguard Worker }
744*2d543d20SAndroid Build Coastguard Worker return 1;
745*2d543d20SAndroid Build Coastguard Worker }
746*2d543d20SAndroid Build Coastguard Worker
cond_read_node(policydb_t * p,cond_node_t * node,void * fp)747*2d543d20SAndroid Build Coastguard Worker static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp)
748*2d543d20SAndroid Build Coastguard Worker {
749*2d543d20SAndroid Build Coastguard Worker uint32_t buf[2], i, len;
750*2d543d20SAndroid Build Coastguard Worker int rc;
751*2d543d20SAndroid Build Coastguard Worker cond_expr_t *expr = NULL, *last = NULL;
752*2d543d20SAndroid Build Coastguard Worker
753*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t));
754*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
755*2d543d20SAndroid Build Coastguard Worker goto err;
756*2d543d20SAndroid Build Coastguard Worker
757*2d543d20SAndroid Build Coastguard Worker node->cur_state = le32_to_cpu(buf[0]);
758*2d543d20SAndroid Build Coastguard Worker
759*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t));
760*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
761*2d543d20SAndroid Build Coastguard Worker goto err;
762*2d543d20SAndroid Build Coastguard Worker
763*2d543d20SAndroid Build Coastguard Worker /* expr */
764*2d543d20SAndroid Build Coastguard Worker len = le32_to_cpu(buf[0]);
765*2d543d20SAndroid Build Coastguard Worker
766*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
767*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
768*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
769*2d543d20SAndroid Build Coastguard Worker goto err;
770*2d543d20SAndroid Build Coastguard Worker
771*2d543d20SAndroid Build Coastguard Worker expr = malloc(sizeof(cond_expr_t));
772*2d543d20SAndroid Build Coastguard Worker if (!expr) {
773*2d543d20SAndroid Build Coastguard Worker goto err;
774*2d543d20SAndroid Build Coastguard Worker }
775*2d543d20SAndroid Build Coastguard Worker memset(expr, 0, sizeof(cond_expr_t));
776*2d543d20SAndroid Build Coastguard Worker
777*2d543d20SAndroid Build Coastguard Worker expr->expr_type = le32_to_cpu(buf[0]);
778*2d543d20SAndroid Build Coastguard Worker expr->boolean = le32_to_cpu(buf[1]);
779*2d543d20SAndroid Build Coastguard Worker
780*2d543d20SAndroid Build Coastguard Worker if (!expr_isvalid(p, expr)) {
781*2d543d20SAndroid Build Coastguard Worker free(expr);
782*2d543d20SAndroid Build Coastguard Worker goto err;
783*2d543d20SAndroid Build Coastguard Worker }
784*2d543d20SAndroid Build Coastguard Worker
785*2d543d20SAndroid Build Coastguard Worker if (i == 0) {
786*2d543d20SAndroid Build Coastguard Worker node->expr = expr;
787*2d543d20SAndroid Build Coastguard Worker } else {
788*2d543d20SAndroid Build Coastguard Worker last->next = expr;
789*2d543d20SAndroid Build Coastguard Worker }
790*2d543d20SAndroid Build Coastguard Worker last = expr;
791*2d543d20SAndroid Build Coastguard Worker }
792*2d543d20SAndroid Build Coastguard Worker
793*2d543d20SAndroid Build Coastguard Worker if (p->policy_type == POLICY_KERN) {
794*2d543d20SAndroid Build Coastguard Worker if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
795*2d543d20SAndroid Build Coastguard Worker goto err;
796*2d543d20SAndroid Build Coastguard Worker if (cond_read_av_list(p, fp, &node->false_list, node->true_list)
797*2d543d20SAndroid Build Coastguard Worker != 0)
798*2d543d20SAndroid Build Coastguard Worker goto err;
799*2d543d20SAndroid Build Coastguard Worker } else {
800*2d543d20SAndroid Build Coastguard Worker if (avrule_read_list(p, &node->avtrue_list, fp))
801*2d543d20SAndroid Build Coastguard Worker goto err;
802*2d543d20SAndroid Build Coastguard Worker if (avrule_read_list(p, &node->avfalse_list, fp))
803*2d543d20SAndroid Build Coastguard Worker goto err;
804*2d543d20SAndroid Build Coastguard Worker }
805*2d543d20SAndroid Build Coastguard Worker
806*2d543d20SAndroid Build Coastguard Worker if (p->policy_type != POLICY_KERN &&
807*2d543d20SAndroid Build Coastguard Worker p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
808*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t));
809*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
810*2d543d20SAndroid Build Coastguard Worker goto err;
811*2d543d20SAndroid Build Coastguard Worker node->flags = le32_to_cpu(buf[0]);
812*2d543d20SAndroid Build Coastguard Worker }
813*2d543d20SAndroid Build Coastguard Worker
814*2d543d20SAndroid Build Coastguard Worker return 0;
815*2d543d20SAndroid Build Coastguard Worker err:
816*2d543d20SAndroid Build Coastguard Worker cond_node_destroy(node);
817*2d543d20SAndroid Build Coastguard Worker free(node);
818*2d543d20SAndroid Build Coastguard Worker return -1;
819*2d543d20SAndroid Build Coastguard Worker }
820*2d543d20SAndroid Build Coastguard Worker
cond_read_list(policydb_t * p,cond_list_t ** list,void * fp)821*2d543d20SAndroid Build Coastguard Worker int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp)
822*2d543d20SAndroid Build Coastguard Worker {
823*2d543d20SAndroid Build Coastguard Worker cond_node_t *node, *last = NULL;
824*2d543d20SAndroid Build Coastguard Worker uint32_t buf[1], i, len;
825*2d543d20SAndroid Build Coastguard Worker int rc;
826*2d543d20SAndroid Build Coastguard Worker
827*2d543d20SAndroid Build Coastguard Worker rc = next_entry(buf, fp, sizeof(uint32_t));
828*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
829*2d543d20SAndroid Build Coastguard Worker return -1;
830*2d543d20SAndroid Build Coastguard Worker
831*2d543d20SAndroid Build Coastguard Worker len = le32_to_cpu(buf[0]);
832*2d543d20SAndroid Build Coastguard Worker
833*2d543d20SAndroid Build Coastguard Worker rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
834*2d543d20SAndroid Build Coastguard Worker if (rc)
835*2d543d20SAndroid Build Coastguard Worker goto err;
836*2d543d20SAndroid Build Coastguard Worker
837*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
838*2d543d20SAndroid Build Coastguard Worker node = malloc(sizeof(cond_node_t));
839*2d543d20SAndroid Build Coastguard Worker if (!node)
840*2d543d20SAndroid Build Coastguard Worker goto err;
841*2d543d20SAndroid Build Coastguard Worker memset(node, 0, sizeof(cond_node_t));
842*2d543d20SAndroid Build Coastguard Worker
843*2d543d20SAndroid Build Coastguard Worker if (cond_read_node(p, node, fp) != 0)
844*2d543d20SAndroid Build Coastguard Worker goto err;
845*2d543d20SAndroid Build Coastguard Worker
846*2d543d20SAndroid Build Coastguard Worker if (i == 0) {
847*2d543d20SAndroid Build Coastguard Worker *list = node;
848*2d543d20SAndroid Build Coastguard Worker } else {
849*2d543d20SAndroid Build Coastguard Worker last->next = node;
850*2d543d20SAndroid Build Coastguard Worker }
851*2d543d20SAndroid Build Coastguard Worker last = node;
852*2d543d20SAndroid Build Coastguard Worker }
853*2d543d20SAndroid Build Coastguard Worker return 0;
854*2d543d20SAndroid Build Coastguard Worker err:
855*2d543d20SAndroid Build Coastguard Worker return -1;
856*2d543d20SAndroid Build Coastguard Worker }
857*2d543d20SAndroid Build Coastguard Worker
858*2d543d20SAndroid Build Coastguard Worker /* Determine whether additional permissions are granted by the conditional
859*2d543d20SAndroid Build Coastguard Worker * av table, and if so, add them to the result
860*2d543d20SAndroid Build Coastguard Worker */
cond_compute_av(avtab_t * ctab,avtab_key_t * key,struct sepol_av_decision * avd)861*2d543d20SAndroid Build Coastguard Worker void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
862*2d543d20SAndroid Build Coastguard Worker struct sepol_av_decision *avd)
863*2d543d20SAndroid Build Coastguard Worker {
864*2d543d20SAndroid Build Coastguard Worker avtab_ptr_t node;
865*2d543d20SAndroid Build Coastguard Worker
866*2d543d20SAndroid Build Coastguard Worker if (!ctab || !key || !avd)
867*2d543d20SAndroid Build Coastguard Worker return;
868*2d543d20SAndroid Build Coastguard Worker
869*2d543d20SAndroid Build Coastguard Worker for (node = avtab_search_node(ctab, key); node != NULL;
870*2d543d20SAndroid Build Coastguard Worker node = avtab_search_node_next(node, key->specified)) {
871*2d543d20SAndroid Build Coastguard Worker if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) ==
872*2d543d20SAndroid Build Coastguard Worker (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
873*2d543d20SAndroid Build Coastguard Worker avd->allowed |= node->datum.data;
874*2d543d20SAndroid Build Coastguard Worker if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) ==
875*2d543d20SAndroid Build Coastguard Worker (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
876*2d543d20SAndroid Build Coastguard Worker /* Since a '0' in an auditdeny mask represents a
877*2d543d20SAndroid Build Coastguard Worker * permission we do NOT want to audit (dontaudit), we use
878*2d543d20SAndroid Build Coastguard Worker * the '&' operand to ensure that all '0's in the mask
879*2d543d20SAndroid Build Coastguard Worker * are retained (much unlike the allow and auditallow cases).
880*2d543d20SAndroid Build Coastguard Worker */
881*2d543d20SAndroid Build Coastguard Worker avd->auditdeny &= node->datum.data;
882*2d543d20SAndroid Build Coastguard Worker if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
883*2d543d20SAndroid Build Coastguard Worker (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
884*2d543d20SAndroid Build Coastguard Worker avd->auditallow |= node->datum.data;
885*2d543d20SAndroid Build Coastguard Worker }
886*2d543d20SAndroid Build Coastguard Worker return;
887*2d543d20SAndroid Build Coastguard Worker }
888*2d543d20SAndroid Build Coastguard Worker
cond_av_list_search(avtab_key_t * key,cond_av_list_t * cond_list)889*2d543d20SAndroid Build Coastguard Worker avtab_datum_t *cond_av_list_search(avtab_key_t * key,
890*2d543d20SAndroid Build Coastguard Worker cond_av_list_t * cond_list)
891*2d543d20SAndroid Build Coastguard Worker {
892*2d543d20SAndroid Build Coastguard Worker
893*2d543d20SAndroid Build Coastguard Worker cond_av_list_t *cur_av;
894*2d543d20SAndroid Build Coastguard Worker
895*2d543d20SAndroid Build Coastguard Worker for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
896*2d543d20SAndroid Build Coastguard Worker
897*2d543d20SAndroid Build Coastguard Worker if (cur_av->node->key.source_type == key->source_type &&
898*2d543d20SAndroid Build Coastguard Worker cur_av->node->key.target_type == key->target_type &&
899*2d543d20SAndroid Build Coastguard Worker cur_av->node->key.target_class == key->target_class)
900*2d543d20SAndroid Build Coastguard Worker
901*2d543d20SAndroid Build Coastguard Worker return &cur_av->node->datum;
902*2d543d20SAndroid Build Coastguard Worker
903*2d543d20SAndroid Build Coastguard Worker }
904*2d543d20SAndroid Build Coastguard Worker return NULL;
905*2d543d20SAndroid Build Coastguard Worker
906*2d543d20SAndroid Build Coastguard Worker }
907