/src/selinux/libsepol/cil/src/cil_deny.c
Line | Count | Source |
1 | | /* |
2 | | * This file is public domain software, i.e. not copyrighted. |
3 | | * |
4 | | * Warranty Exclusion |
5 | | * ------------------ |
6 | | * You agree that this software is a non-commercially developed program |
7 | | * that may contain "bugs" (as that term is used in the industry) and |
8 | | * that it may not function as intended. The software is licensed |
9 | | * "as is". NSA makes no, and hereby expressly disclaims all, warranties, |
10 | | * express, implied, statutory, or otherwise with respect to the software, |
11 | | * including noninfringement and the implied warranties of merchantability |
12 | | * and fitness for a particular purpose. |
13 | | * |
14 | | * Limitation of Liability |
15 | | *----------------------- |
16 | | * In no event will NSA be liable for any damages, including loss of data, |
17 | | * lost profits, cost of cover, or other special, incidental, consequential, |
18 | | * direct or indirect damages arising from the software or the use thereof, |
19 | | * however caused and on any theory of liability. This limitation will apply |
20 | | * even if NSA has been advised of the possibility of such damage. You |
21 | | * acknowledge that this is a reasonable allocation of risk. |
22 | | * |
23 | | * Original author: James Carter |
24 | | */ |
25 | | |
26 | | #include <sepol/policydb/ebitmap.h> |
27 | | |
28 | | #include "cil_internal.h" |
29 | | #include "cil_find.h" |
30 | | #include "cil_flavor.h" |
31 | | #include "cil_list.h" |
32 | | #include "cil_strpool.h" |
33 | | #include "cil_log.h" |
34 | | #include "cil_symtab.h" |
35 | | #include "cil_build_ast.h" |
36 | | #include "cil_copy_ast.h" |
37 | | #include "cil_deny.h" |
38 | | |
39 | 0 | #define CIL_DENY_ATTR_PREFIX "deny_rule_attr" |
40 | | |
41 | | /* |
42 | | * A deny rule is like a neverallow rule, except that permissions are |
43 | | * removed rather than an error reported. |
44 | | * |
45 | | * (allow S1 T1 P1) |
46 | | * (deny S2 T2 P2) |
47 | | * |
48 | | * First, write the allow rule with all of the permissions not in the deny rule |
49 | | * P3 = P1 and not P2 |
50 | | * (allow S1 T1 P3) |
51 | | * |
52 | | * Obviously, the rule is only written if P3 is not an empty list. This goes |
53 | | * for the rest of the rules as well--they are only written if the source and |
54 | | * target exist. |
55 | | * |
56 | | * The remaining rules will only involve the common permissions |
57 | | * P4 = P1 and P2 |
58 | | * |
59 | | * Next, write the allow rule for any types in S1 that are not in S2 |
60 | | * S3 = S1 and not S2 |
61 | | * (allow S3 T1 P4) |
62 | | * |
63 | | * Finally, write any allow rules needed to cover the types in T1 that are |
64 | | * not in T2. Since, T1 and T2 might be "self", "notself", or "other", this |
65 | | * requires more complicated handling. Any rule with "self" will not match |
66 | | * a rule with either "notself" or "other". |
67 | | * |
68 | | * if (T1 is self and T2 is self) or (T1 is notself and T2 is notself) then |
69 | | * Nothing more needs to be done. |
70 | | * |
71 | | * The rest of the rules will depend on the intersection of S1 and S2 |
72 | | * which cannot be the empty set since the allow and deny rules match. |
73 | | * S4 = S1 and S2 |
74 | | * |
75 | | * if T1 is notself or T1 is other or T2 is notself or T2 is other then |
76 | | * if T1 is notself then |
77 | | * if T2 is other then |
78 | | * T = ALL and not S2 |
79 | | * (allow S4 T P4) |
80 | | * else [T2 is not self, notself, or other] |
81 | | * S5 = S4 and not T2 |
82 | | * S6 = S4 and T2 |
83 | | * TA = ALL and not T2 |
84 | | * TB = TA and not S4 |
85 | | * (allow S6 TA P4) |
86 | | * (allow S5 TB P4) |
87 | | * if cardinality(S5) > 1 then |
88 | | * (allow S5 other P4) |
89 | | * else if T1 is other then |
90 | | * (allow S3 S4 P4) |
91 | | * if T2 is notself then |
92 | | * [Nothing else is needed] |
93 | | * else if T2 is other then |
94 | | * (allow S4 S3 P4) |
95 | | * else [T2 is not self, notself, or other] |
96 | | * S5 = S4 and not T2 |
97 | | * S6 = S4 and T2 |
98 | | * TC = S1 and not T2 |
99 | | * TD = S3 and not T2 |
100 | | * (allow S6 TC P4) |
101 | | * (allow S5 TD P4) |
102 | | * if cardinality(S5) > 1 then |
103 | | * (allow S5 other P4) |
104 | | * else [T1 is not self, notself, or other] |
105 | | * S8 = S4 and T1 |
106 | | * (allow S8 self P4) |
107 | | * if T2 is notself then |
108 | | * [Nothing else is needed] |
109 | | * else [T2 is other] |
110 | | * T = T1 and not S2 |
111 | | * (allow S4 T P4) |
112 | | * else [Neither T1 nor T2 are notself or other] |
113 | | * if T1 is self and T2 is not self then |
114 | | * S5 = S4 and not T2 |
115 | | * (allow S5 self P4) |
116 | | * else if T1 is not self and T2 is self then |
117 | | * S7 = S4 and not T1 |
118 | | * S8 = S4 and T1 |
119 | | * T8 = T1 and not S4 |
120 | | * (allow S7 T1 P4) |
121 | | * (allow S8 T8 P4) |
122 | | * if cardinality(S8) > 1 then |
123 | | * (allow S8 other P4) |
124 | | * else [Neither T1 nor T2 is self] |
125 | | * T3 = T1 and not T2 |
126 | | * (allow S4 T3 P4) |
127 | | */ |
128 | | |
129 | | static int cil_perm_match(const struct cil_perm *p1, const struct cil_list *pl2) |
130 | 0 | { |
131 | 0 | struct cil_list_item *curr; |
132 | |
|
133 | 0 | cil_list_for_each(curr, pl2) { |
134 | 0 | struct cil_perm *p = curr->data; |
135 | 0 | if (p == p1) { |
136 | 0 | return CIL_TRUE; |
137 | 0 | } |
138 | 0 | } |
139 | 0 | return CIL_FALSE; |
140 | 0 | } |
141 | | |
142 | | static int cil_class_perm_match(const struct cil_class *c1, const struct cil_perm *p1, const struct cil_list *cpl2) |
143 | 0 | { |
144 | 0 | struct cil_list_item *curr; |
145 | |
|
146 | 0 | cil_list_for_each(curr, cpl2) { |
147 | 0 | if (curr->flavor == CIL_CLASSPERMS) { |
148 | 0 | struct cil_classperms *cp = curr->data; |
149 | 0 | if (FLAVOR(cp->class) == CIL_CLASS) { |
150 | 0 | if (cp->class == c1) { |
151 | 0 | if (cil_perm_match(p1, cp->perms)) { |
152 | 0 | return CIL_TRUE; |
153 | 0 | } |
154 | 0 | } |
155 | 0 | } else { /* MAP */ |
156 | 0 | struct cil_list_item *p; |
157 | 0 | cil_list_for_each(p, cp->perms) { |
158 | 0 | struct cil_perm *cmp = p->data; |
159 | 0 | if (cil_class_perm_match(c1, p1, cmp->classperms)) { |
160 | 0 | return CIL_TRUE; |
161 | 0 | } |
162 | 0 | } |
163 | 0 | } |
164 | 0 | } else { /* SET */ |
165 | 0 | struct cil_classperms_set *cp_set = curr->data; |
166 | 0 | struct cil_classpermission *cp = cp_set->set; |
167 | 0 | if (cil_class_perm_match(c1, p1, cp->classperms)) { |
168 | 0 | return CIL_TRUE; |
169 | 0 | } |
170 | 0 | } |
171 | 0 | } |
172 | 0 | return CIL_FALSE; |
173 | 0 | } |
174 | | |
175 | | static int cil_classperms_match_any(const struct cil_classperms *cp1, const struct cil_list *cpl2) |
176 | 0 | { |
177 | 0 | struct cil_list_item *curr; |
178 | |
|
179 | 0 | cil_list_for_each(curr, cp1->perms) { |
180 | 0 | struct cil_perm *perm = curr->data; |
181 | 0 | if (cil_class_perm_match(cp1->class, perm, cpl2)) { |
182 | 0 | return CIL_TRUE; |
183 | 0 | } |
184 | 0 | } |
185 | 0 | return CIL_FALSE; |
186 | 0 | } |
187 | | |
188 | | int cil_classperms_list_match_any(const struct cil_list *cpl1, const struct cil_list *cpl2) |
189 | 0 | { |
190 | 0 | struct cil_list_item *curr; |
191 | |
|
192 | 0 | if (!cpl1 || !cpl2) { |
193 | 0 | return (!cpl1 && !cpl2) ? CIL_TRUE : CIL_FALSE; |
194 | 0 | } |
195 | | |
196 | 0 | cil_list_for_each(curr, cpl1) { |
197 | 0 | if (curr->flavor == CIL_CLASSPERMS) { |
198 | 0 | struct cil_classperms *cp = curr->data; |
199 | 0 | if (FLAVOR(cp->class) == CIL_CLASS) { |
200 | 0 | if (cil_classperms_match_any(cp, cpl2)) { |
201 | 0 | return CIL_TRUE; |
202 | 0 | } |
203 | 0 | } else { /* MAP */ |
204 | 0 | struct cil_list_item *p; |
205 | 0 | cil_list_for_each(p, cp->perms) { |
206 | 0 | struct cil_perm *cmp = p->data; |
207 | 0 | if (cil_classperms_list_match_any(cmp->classperms, cpl2)) { |
208 | 0 | return CIL_TRUE; |
209 | 0 | } |
210 | 0 | } |
211 | 0 | } |
212 | 0 | } else { /* SET */ |
213 | 0 | struct cil_classperms_set *cp_set = curr->data; |
214 | 0 | struct cil_classpermission *cp = cp_set->set; |
215 | 0 | if (cil_classperms_list_match_any(cp->classperms, cpl2)) { |
216 | 0 | return CIL_TRUE; |
217 | 0 | } |
218 | 0 | } |
219 | 0 | } |
220 | 0 | return CIL_FALSE; |
221 | 0 | } |
222 | | |
223 | | static int cil_classperms_match_all(const struct cil_classperms *cp1, const struct cil_list *cpl2) |
224 | 0 | { |
225 | 0 | struct cil_list_item *curr; |
226 | |
|
227 | 0 | cil_list_for_each(curr, cp1->perms) { |
228 | 0 | struct cil_perm *perm = curr->data; |
229 | 0 | if (!cil_class_perm_match(cp1->class, perm, cpl2)) { |
230 | 0 | return CIL_FALSE; |
231 | 0 | } |
232 | 0 | } |
233 | 0 | return CIL_TRUE; |
234 | 0 | } |
235 | | |
236 | | int cil_classperms_list_match_all(const struct cil_list *cpl1, const struct cil_list *cpl2) |
237 | 0 | { |
238 | 0 | struct cil_list_item *curr; |
239 | |
|
240 | 0 | if (!cpl1 || !cpl2) { |
241 | 0 | return (!cpl1 && !cpl2) ? CIL_TRUE : CIL_FALSE; |
242 | 0 | } |
243 | | |
244 | 0 | cil_list_for_each(curr, cpl1) { |
245 | 0 | if (curr->flavor == CIL_CLASSPERMS) { |
246 | 0 | struct cil_classperms *cp = curr->data; |
247 | 0 | if (FLAVOR(cp->class) == CIL_CLASS) { |
248 | 0 | if (!cil_classperms_match_all(cp, cpl2)) { |
249 | 0 | return CIL_FALSE; |
250 | 0 | } |
251 | 0 | } else { /* MAP */ |
252 | 0 | struct cil_list_item *p; |
253 | 0 | cil_list_for_each(p, cp->perms) { |
254 | 0 | struct cil_perm *cmp = p->data; |
255 | 0 | if (!cil_classperms_list_match_all(cmp->classperms, cpl2)) { |
256 | 0 | return CIL_FALSE; |
257 | 0 | } |
258 | 0 | } |
259 | 0 | } |
260 | 0 | } else { /* SET */ |
261 | 0 | struct cil_classperms_set *cp_set = curr->data; |
262 | 0 | struct cil_classpermission *cp = cp_set->set; |
263 | 0 | if (!cil_classperms_list_match_all(cp->classperms, cpl2)) { |
264 | 0 | return CIL_FALSE; |
265 | 0 | } |
266 | 0 | } |
267 | 0 | } |
268 | 0 | return CIL_TRUE; |
269 | 0 | } |
270 | | |
271 | | static void cil_classperms_copy(struct cil_classperms **new, const struct cil_classperms *old) |
272 | 0 | { |
273 | 0 | cil_classperms_init(new); |
274 | 0 | (*new)->class_str = old->class_str; |
275 | 0 | (*new)->class = old->class; |
276 | 0 | cil_copy_list(old->perm_strs, &(*new)->perm_strs); |
277 | 0 | cil_copy_list(old->perms, &(*new)->perms); |
278 | 0 | } |
279 | | |
280 | | static void cil_classperms_set_copy(struct cil_classperms_set **new, const struct cil_classperms_set *old) |
281 | 0 | { |
282 | 0 | cil_classperms_set_init(new); |
283 | 0 | (*new)->set_str = old->set_str; |
284 | 0 | (*new)->set = old->set; |
285 | 0 | } |
286 | | |
287 | | void cil_classperms_list_copy(struct cil_list **new, const struct cil_list *old) |
288 | 0 | { |
289 | 0 | struct cil_list_item *curr; |
290 | |
|
291 | 0 | if (!new) { |
292 | 0 | return; |
293 | 0 | } |
294 | | |
295 | 0 | if (!old) { |
296 | 0 | *new = NULL; |
297 | 0 | return; |
298 | 0 | } |
299 | | |
300 | 0 | cil_list_init(new, CIL_LIST); |
301 | |
|
302 | 0 | cil_list_for_each(curr, old) { |
303 | 0 | if (curr->flavor == CIL_CLASSPERMS) { |
304 | 0 | struct cil_classperms *new_cp; |
305 | 0 | cil_classperms_copy(&new_cp, curr->data); |
306 | 0 | cil_list_append(*new, CIL_CLASSPERMS, new_cp); |
307 | 0 | } else { /* SET */ |
308 | 0 | struct cil_classperms_set *new_cps; |
309 | 0 | cil_classperms_set_copy(&new_cps, curr->data); |
310 | 0 | cil_list_append(*new, CIL_CLASSPERMS_SET, new_cps); |
311 | 0 | } |
312 | 0 | } |
313 | |
|
314 | 0 | if (cil_list_is_empty(*new)) { |
315 | 0 | cil_list_destroy(new, CIL_FALSE); |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | | /* Append cp1 and cpl2 to result */ |
320 | | static void cil_classperms_and(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2) |
321 | 0 | { |
322 | 0 | struct cil_classperms *new_cp = NULL; |
323 | 0 | struct cil_list_item *curr; |
324 | |
|
325 | 0 | if (cil_classperms_match_all(cp1, cpl2)) { |
326 | 0 | cil_classperms_copy(&new_cp, cp1); |
327 | 0 | cil_list_append(*result, CIL_CLASSPERMS, new_cp); |
328 | 0 | return; |
329 | 0 | } |
330 | | |
331 | 0 | cil_list_for_each(curr, cp1->perms) { |
332 | 0 | struct cil_perm *perm = curr->data; |
333 | 0 | if (cil_class_perm_match(cp1->class, perm, cpl2)) { |
334 | 0 | if (new_cp == NULL) { |
335 | 0 | cil_classperms_init(&new_cp); |
336 | 0 | new_cp->class_str = cp1->class_str; |
337 | 0 | new_cp->class = cp1->class; |
338 | 0 | cil_list_init(&new_cp->perm_strs, CIL_PERM); |
339 | 0 | cil_list_init(&new_cp->perms, CIL_PERM); |
340 | 0 | cil_list_append(*result, CIL_CLASSPERMS, new_cp); |
341 | 0 | } |
342 | 0 | cil_list_append(new_cp->perm_strs, CIL_STRING, perm->datum.fqn); |
343 | 0 | cil_list_append(new_cp->perms, CIL_DATUM, perm); |
344 | 0 | } |
345 | 0 | } |
346 | 0 | } |
347 | | |
348 | | /* Append cp1 and cpl2 to result */ |
349 | | static void cil_classperms_map_and(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2) |
350 | 0 | { |
351 | 0 | struct cil_classperms *new_cp = NULL; |
352 | 0 | struct cil_list_item *p; |
353 | |
|
354 | 0 | cil_list_for_each(p, cp1->perms) { |
355 | 0 | struct cil_perm *map_perm = p->data; |
356 | 0 | if (cil_classperms_list_match_all(map_perm->classperms, cpl2)) { |
357 | 0 | if (new_cp == NULL) { |
358 | 0 | cil_classperms_init(&new_cp); |
359 | 0 | new_cp->class_str = cp1->class_str; |
360 | 0 | new_cp->class = cp1->class; |
361 | 0 | cil_list_init(&new_cp->perm_strs, CIL_PERM); |
362 | 0 | cil_list_init(&new_cp->perms, CIL_PERM); |
363 | 0 | cil_list_append(*result, CIL_CLASSPERMS, new_cp); |
364 | 0 | } |
365 | 0 | cil_list_append(new_cp->perm_strs, CIL_STRING, map_perm->datum.fqn); |
366 | 0 | cil_list_append(new_cp->perms, CIL_DATUM, map_perm); |
367 | 0 | } else { |
368 | 0 | struct cil_list *new_cpl = NULL; |
369 | 0 | cil_classperms_list_and(&new_cpl, map_perm->classperms, cpl2); |
370 | 0 | if (new_cpl) { |
371 | 0 | struct cil_list_item *i; |
372 | 0 | cil_list_for_each(i, new_cpl) { |
373 | 0 | cil_list_append(*result, i->flavor, i->data); |
374 | 0 | } |
375 | 0 | cil_list_destroy(&new_cpl, CIL_FALSE); |
376 | 0 | } |
377 | 0 | } |
378 | 0 | } |
379 | 0 | } |
380 | | |
381 | | /* Append cps1 and cpl2 to result */ |
382 | | static void cil_classperms_set_and(struct cil_list **result, const struct cil_classperms_set *cps1, const struct cil_list *cpl2) |
383 | 0 | { |
384 | 0 | struct cil_classpermission *cp = cps1->set; |
385 | |
|
386 | 0 | if (cil_classperms_list_match_all(cp->classperms, cpl2)) { |
387 | 0 | struct cil_classperms_set *new_cps; |
388 | 0 | cil_classperms_set_copy(&new_cps, cps1); |
389 | 0 | cil_list_append(*result, CIL_CLASSPERMS_SET, new_cps); |
390 | 0 | } else { |
391 | 0 | struct cil_list *new_cpl; |
392 | 0 | cil_classperms_list_and(&new_cpl, cp->classperms, cpl2); |
393 | 0 | if (new_cpl) { |
394 | 0 | struct cil_list_item *i; |
395 | 0 | cil_list_for_each(i, new_cpl) { |
396 | 0 | cil_list_append(*result, i->flavor, i->data); |
397 | 0 | } |
398 | 0 | cil_list_destroy(&new_cpl, CIL_FALSE); |
399 | 0 | } |
400 | 0 | } |
401 | 0 | } |
402 | | |
403 | | /* result = cpl1 and cpl2 */ |
404 | | void cil_classperms_list_and(struct cil_list **result, const struct cil_list *cpl1, const struct cil_list *cpl2) |
405 | 0 | { |
406 | 0 | struct cil_list_item *curr; |
407 | |
|
408 | 0 | if (!result) { |
409 | 0 | return; |
410 | 0 | } |
411 | | |
412 | 0 | if (!cpl1 || !cpl2) { |
413 | 0 | *result = NULL; |
414 | 0 | return; |
415 | 0 | } |
416 | | |
417 | 0 | if (cil_classperms_list_match_all(cpl1, cpl2)) { |
418 | 0 | cil_classperms_list_copy(result, cpl1); |
419 | 0 | return; |
420 | 0 | } |
421 | | |
422 | 0 | cil_list_init(result, CIL_LIST); |
423 | |
|
424 | 0 | cil_list_for_each(curr, cpl1) { |
425 | 0 | if (curr->flavor == CIL_CLASSPERMS) { |
426 | 0 | struct cil_classperms *cp = curr->data; |
427 | 0 | if (FLAVOR(cp->class) == CIL_CLASS) { |
428 | 0 | cil_classperms_and(result, cp, cpl2); |
429 | 0 | } else { /* MAP */ |
430 | 0 | cil_classperms_map_and(result, cp, cpl2); |
431 | 0 | } |
432 | 0 | } else { /* SET */ |
433 | 0 | struct cil_classperms_set *cps = curr->data; |
434 | 0 | cil_classperms_set_and(result, cps, cpl2); |
435 | 0 | } |
436 | 0 | } |
437 | |
|
438 | 0 | if (cil_list_is_empty(*result)) { |
439 | 0 | cil_list_destroy(result, CIL_FALSE); |
440 | 0 | } |
441 | 0 | } |
442 | | |
443 | | /* Append cp1 and not cpl2 to result */ |
444 | | static void cil_classperms_andnot(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2) |
445 | 0 | { |
446 | 0 | struct cil_classperms *new_cp = NULL; |
447 | 0 | struct cil_list_item *curr; |
448 | |
|
449 | 0 | if (!cil_classperms_match_any(cp1, cpl2)) { |
450 | 0 | cil_classperms_copy(&new_cp, cp1); |
451 | 0 | cil_list_append(*result, CIL_CLASSPERMS, new_cp); |
452 | 0 | return; |
453 | 0 | } |
454 | | |
455 | 0 | cil_list_for_each(curr, cp1->perms) { |
456 | 0 | struct cil_perm *perm = curr->data; |
457 | 0 | if (!cil_class_perm_match(cp1->class, perm, cpl2)) { |
458 | 0 | if (new_cp == NULL) { |
459 | 0 | cil_classperms_init(&new_cp); |
460 | 0 | new_cp->class_str = cp1->class_str; |
461 | 0 | new_cp->class = cp1->class; |
462 | 0 | cil_list_init(&new_cp->perm_strs, CIL_PERM); |
463 | 0 | cil_list_init(&new_cp->perms, CIL_PERM); |
464 | 0 | cil_list_append(*result, CIL_CLASSPERMS, new_cp); |
465 | 0 | } |
466 | 0 | cil_list_append(new_cp->perm_strs, CIL_STRING, perm->datum.fqn); |
467 | 0 | cil_list_append(new_cp->perms, CIL_DATUM, perm); |
468 | 0 | } |
469 | 0 | } |
470 | 0 | } |
471 | | |
472 | | /* Append cp1 and not cpl2 to result */ |
473 | | static void cil_classperms_map_andnot(struct cil_list **result, const struct cil_classperms *cp1, const struct cil_list *cpl2) |
474 | 0 | { |
475 | 0 | struct cil_classperms *new_cp = NULL; |
476 | 0 | struct cil_list_item *p; |
477 | |
|
478 | 0 | cil_list_for_each(p, cp1->perms) { |
479 | 0 | struct cil_perm *map_perm = p->data; |
480 | 0 | if (!cil_classperms_list_match_any(map_perm->classperms, cpl2)) { |
481 | 0 | if (new_cp == NULL) { |
482 | 0 | cil_classperms_init(&new_cp); |
483 | 0 | new_cp->class_str = cp1->class_str; |
484 | 0 | new_cp->class = cp1->class; |
485 | 0 | cil_list_init(&new_cp->perm_strs, CIL_PERM); |
486 | 0 | cil_list_init(&new_cp->perms, CIL_PERM); |
487 | 0 | cil_list_append(*result, CIL_CLASSPERMS, new_cp); |
488 | 0 | } |
489 | 0 | cil_list_append(new_cp->perm_strs, CIL_STRING, map_perm->datum.fqn); |
490 | 0 | cil_list_append(new_cp->perms, CIL_DATUM, map_perm); |
491 | 0 | } else { |
492 | 0 | struct cil_list *new_cpl = NULL; |
493 | 0 | cil_classperms_list_andnot(&new_cpl, map_perm->classperms, cpl2); |
494 | 0 | if (new_cpl) { |
495 | 0 | struct cil_list_item *i; |
496 | 0 | cil_list_for_each(i, new_cpl) { |
497 | 0 | cil_list_append(*result, i->flavor, i->data); |
498 | 0 | } |
499 | 0 | cil_list_destroy(&new_cpl, CIL_FALSE); |
500 | 0 | } |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | | /* Append cps1 and not cpl2 to result */ |
506 | | static void cil_classperms_set_andnot(struct cil_list **result, const struct cil_classperms_set *cps1, const struct cil_list *cpl2) |
507 | 0 | { |
508 | 0 | struct cil_classpermission *cp = cps1->set; |
509 | |
|
510 | 0 | if (!cil_classperms_list_match_any(cp->classperms, cpl2)) { |
511 | 0 | struct cil_classperms_set *new_cps; |
512 | 0 | cil_classperms_set_copy(&new_cps, cps1); |
513 | 0 | cil_list_append(*result, CIL_CLASSPERMS_SET, new_cps); |
514 | 0 | } else { |
515 | 0 | struct cil_list *new_cpl; |
516 | 0 | cil_classperms_list_andnot(&new_cpl, cp->classperms, cpl2); |
517 | 0 | if (new_cpl) { |
518 | 0 | struct cil_list_item *i; |
519 | 0 | cil_list_for_each(i, new_cpl) { |
520 | 0 | cil_list_append(*result, i->flavor, i->data); |
521 | 0 | } |
522 | 0 | cil_list_destroy(&new_cpl, CIL_FALSE); |
523 | 0 | } |
524 | 0 | } |
525 | 0 | } |
526 | | |
527 | | /* result = cpl1 and not cpl2 */ |
528 | | void cil_classperms_list_andnot(struct cil_list **result, const struct cil_list *cpl1, const struct cil_list *cpl2) |
529 | 0 | { |
530 | 0 | struct cil_list_item *curr; |
531 | |
|
532 | 0 | if (!result) { |
533 | 0 | return; |
534 | 0 | } |
535 | | |
536 | 0 | if (!cpl1) { |
537 | 0 | *result = NULL; |
538 | 0 | return; |
539 | 0 | } |
540 | | |
541 | 0 | if (!cpl2 || !cil_classperms_list_match_any(cpl1, cpl2)) { |
542 | 0 | cil_classperms_list_copy(result, cpl1); |
543 | 0 | return; |
544 | 0 | } |
545 | | |
546 | 0 | cil_list_init(result, CIL_LIST); |
547 | |
|
548 | 0 | cil_list_for_each(curr, cpl1) { |
549 | 0 | if (curr->flavor == CIL_CLASSPERMS) { |
550 | 0 | struct cil_classperms *cp = curr->data; |
551 | 0 | if (FLAVOR(cp->class) == CIL_CLASS) { |
552 | 0 | cil_classperms_andnot(result, cp, cpl2); |
553 | 0 | } else { /* MAP */ |
554 | 0 | cil_classperms_map_andnot(result, cp, cpl2); |
555 | 0 | } |
556 | 0 | } else { /* SET */ |
557 | 0 | struct cil_classperms_set *cps = curr->data; |
558 | 0 | cil_classperms_set_andnot(result, cps, cpl2); |
559 | 0 | } |
560 | 0 | } |
561 | |
|
562 | 0 | if (cil_list_is_empty(*result)) { |
563 | 0 | cil_list_destroy(result, CIL_FALSE); |
564 | 0 | } |
565 | 0 | } |
566 | | |
567 | | static int cil_datum_cardinality(const struct cil_symtab_datum *d) |
568 | 0 | { |
569 | 0 | if (!d) { |
570 | 0 | return 0; |
571 | 0 | } |
572 | 0 | if (FLAVOR(d) != CIL_TYPEATTRIBUTE) { |
573 | 0 | return 1; |
574 | 0 | } else { |
575 | 0 | struct cil_typeattribute *a = (struct cil_typeattribute *)d; |
576 | 0 | return ebitmap_cardinality(a->types); |
577 | 0 | } |
578 | 0 | } |
579 | | |
580 | | /* result = ALL and not d2 */ |
581 | | static int cil_datum_not(ebitmap_t *result, const struct cil_symtab_datum *d, int max) |
582 | 0 | { |
583 | 0 | int rc = SEPOL_OK; |
584 | |
|
585 | 0 | if (FLAVOR(d) != CIL_TYPEATTRIBUTE) { |
586 | 0 | struct cil_type *t = (struct cil_type *)d; |
587 | 0 | ebitmap_t e; |
588 | |
|
589 | 0 | ebitmap_init(&e); |
590 | 0 | rc = ebitmap_set_bit(&e, t->value, 1); |
591 | 0 | if (rc != SEPOL_OK) { |
592 | 0 | ebitmap_destroy(&e); |
593 | 0 | goto exit; |
594 | 0 | } |
595 | | |
596 | 0 | ebitmap_init(result); |
597 | 0 | rc = ebitmap_not(result, &e, max); |
598 | 0 | if (rc != SEPOL_OK) { |
599 | 0 | ebitmap_destroy(&e); |
600 | 0 | ebitmap_destroy(result); |
601 | 0 | goto exit; |
602 | 0 | } |
603 | 0 | ebitmap_destroy(&e); |
604 | 0 | } else { |
605 | 0 | struct cil_typeattribute *a = (struct cil_typeattribute *)d; |
606 | |
|
607 | 0 | ebitmap_init(result); |
608 | 0 | rc = ebitmap_not(result, a->types, max); |
609 | 0 | if (rc != SEPOL_OK) { |
610 | 0 | ebitmap_destroy(result); |
611 | 0 | goto exit; |
612 | 0 | } |
613 | 0 | } |
614 | 0 | exit: |
615 | 0 | return rc; |
616 | 0 | } |
617 | | |
618 | | /* result = d1 and d2 */ |
619 | | static int cil_datums_and(ebitmap_t *result, const struct cil_symtab_datum *d1, const struct cil_symtab_datum *d2) |
620 | 0 | { |
621 | 0 | int rc = SEPOL_OK; |
622 | 0 | enum cil_flavor f1 = FLAVOR(d1); |
623 | 0 | enum cil_flavor f2 = FLAVOR(d2); |
624 | |
|
625 | 0 | if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) { |
626 | 0 | struct cil_type *t1 = (struct cil_type *)d1; |
627 | 0 | struct cil_type *t2 = (struct cil_type *)d2; |
628 | 0 | ebitmap_init(result); |
629 | 0 | if (t1->value == t2->value) { |
630 | 0 | rc = ebitmap_set_bit(result, t1->value, 1); |
631 | 0 | if (rc != SEPOL_OK) { |
632 | 0 | ebitmap_destroy(result); |
633 | 0 | goto exit; |
634 | 0 | } |
635 | 0 | } |
636 | 0 | } else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) { |
637 | 0 | struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1; |
638 | 0 | struct cil_type *t2 = (struct cil_type *)d2; |
639 | 0 | ebitmap_init(result); |
640 | 0 | if (ebitmap_get_bit(a1->types, t2->value)) { |
641 | 0 | rc = ebitmap_set_bit(result, t2->value, 1); |
642 | 0 | if (rc != SEPOL_OK) { |
643 | 0 | ebitmap_destroy(result); |
644 | 0 | goto exit; |
645 | 0 | } |
646 | 0 | } |
647 | 0 | } else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) { |
648 | 0 | struct cil_type *t1 = (struct cil_type *)d1; |
649 | 0 | struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2; |
650 | 0 | ebitmap_init(result); |
651 | 0 | if (ebitmap_get_bit(a2->types, t1->value)) { |
652 | 0 | rc = ebitmap_set_bit(result, t1->value, 1); |
653 | 0 | if (rc != SEPOL_OK) { |
654 | 0 | ebitmap_destroy(result); |
655 | 0 | goto exit; |
656 | 0 | } |
657 | 0 | } |
658 | 0 | } else { |
659 | | /* Both are attributes */ |
660 | 0 | struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1; |
661 | 0 | struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2; |
662 | 0 | rc = ebitmap_and(result, a1->types, a2->types); |
663 | 0 | if (rc != SEPOL_OK) { |
664 | 0 | ebitmap_destroy(result); |
665 | 0 | goto exit; |
666 | 0 | } |
667 | 0 | } |
668 | 0 | exit: |
669 | 0 | return rc; |
670 | 0 | } |
671 | | |
672 | | /* result = d1 and not d2 */ |
673 | | static int cil_datums_andnot(ebitmap_t *result, const struct cil_symtab_datum *d1, const struct cil_symtab_datum *d2) |
674 | 0 | { |
675 | 0 | int rc = SEPOL_OK; |
676 | 0 | enum cil_flavor f1 = FLAVOR(d1); |
677 | 0 | enum cil_flavor f2 = FLAVOR(d2); |
678 | |
|
679 | 0 | if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) { |
680 | 0 | struct cil_type *t1 = (struct cil_type *)d1; |
681 | 0 | struct cil_type *t2 = (struct cil_type *)d2; |
682 | 0 | ebitmap_init(result); |
683 | 0 | if (t1->value != t2->value) { |
684 | 0 | rc = ebitmap_set_bit(result, t1->value, 1); |
685 | 0 | if (rc != SEPOL_OK) { |
686 | 0 | ebitmap_destroy(result); |
687 | 0 | goto exit; |
688 | 0 | } |
689 | 0 | } |
690 | 0 | } else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) { |
691 | 0 | struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1; |
692 | 0 | struct cil_type *t2 = (struct cil_type *)d2; |
693 | 0 | rc = ebitmap_cpy(result, a1->types); |
694 | 0 | if (rc != SEPOL_OK) { |
695 | 0 | goto exit; |
696 | 0 | } |
697 | 0 | rc = ebitmap_set_bit(result, t2->value, 0); |
698 | 0 | if (rc != SEPOL_OK) { |
699 | 0 | ebitmap_destroy(result); |
700 | 0 | goto exit; |
701 | 0 | } |
702 | 0 | } else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) { |
703 | 0 | struct cil_type *t1 = (struct cil_type *)d1; |
704 | 0 | struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2; |
705 | 0 | ebitmap_init(result); |
706 | 0 | if (!ebitmap_get_bit(a2->types, t1->value)) { |
707 | 0 | rc = ebitmap_set_bit(result, t1->value, 1); |
708 | 0 | if (rc != SEPOL_OK) { |
709 | 0 | ebitmap_destroy(result); |
710 | 0 | goto exit; |
711 | 0 | } |
712 | 0 | } |
713 | 0 | } else { |
714 | | /* Both are attributes */ |
715 | 0 | struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1; |
716 | 0 | struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2; |
717 | 0 | rc = ebitmap_andnot(result, a1->types, a2->types, a1->types->highbit); |
718 | 0 | if (rc != SEPOL_OK) { |
719 | 0 | ebitmap_destroy(result); |
720 | 0 | goto exit; |
721 | 0 | } |
722 | 0 | } |
723 | 0 | exit: |
724 | 0 | return rc; |
725 | 0 | } |
726 | | |
727 | | static size_t num_digits(unsigned n) |
728 | 0 | { |
729 | 0 | size_t num = 1; |
730 | 0 | while (n >= 10) { |
731 | 0 | n /= 10; |
732 | 0 | num++; |
733 | 0 | } |
734 | 0 | return num; |
735 | 0 | } |
736 | | |
737 | | static char *cil_create_new_attribute_name(unsigned num) |
738 | 0 | { |
739 | 0 | char *s1 = NULL; |
740 | 0 | char *s2 = NULL; |
741 | 0 | size_t len_num = num_digits(num); |
742 | 0 | size_t len = strlen(CIL_DENY_ATTR_PREFIX) + 1 + len_num + 1; |
743 | 0 | int rc; |
744 | |
|
745 | 0 | if (len >= CIL_MAX_NAME_LENGTH) { |
746 | 0 | cil_log(CIL_ERR, "Name length greater than max name length of %d", |
747 | 0 | CIL_MAX_NAME_LENGTH); |
748 | 0 | goto exit; |
749 | 0 | } |
750 | | |
751 | 0 | s1 = cil_malloc(len); |
752 | 0 | rc = snprintf(s1, len, "%s_%u", CIL_DENY_ATTR_PREFIX, num); |
753 | 0 | if (rc < 0 || (size_t)rc >= len) { |
754 | 0 | cil_log(CIL_ERR, "Error creating new attribute name"); |
755 | 0 | free(s1); |
756 | 0 | goto exit; |
757 | 0 | } |
758 | | |
759 | 0 | s2 = cil_strpool_add(s1); |
760 | 0 | free(s1); |
761 | |
|
762 | 0 | exit: |
763 | 0 | return s2; |
764 | 0 | } |
765 | | |
766 | | static struct cil_list *cil_create_and_expr_list(enum cil_flavor f1, void *v1, enum cil_flavor f2, void *v2) |
767 | 0 | { |
768 | 0 | struct cil_list *expr; |
769 | |
|
770 | 0 | cil_list_init(&expr, CIL_TYPE); |
771 | 0 | cil_list_append(expr, CIL_OP, (void *)CIL_AND); |
772 | 0 | cil_list_append(expr, f1, v1); |
773 | 0 | cil_list_append(expr, f2, v2); |
774 | |
|
775 | 0 | return expr; |
776 | 0 | } |
777 | | |
778 | | static struct cil_list *cil_create_andnot_expr_list(enum cil_flavor f1, void *v1, enum cil_flavor f2, void *v2) |
779 | 0 | { |
780 | 0 | struct cil_list *expr, *sub_expr; |
781 | |
|
782 | 0 | cil_list_init(&expr, CIL_TYPE); |
783 | 0 | cil_list_append(expr, CIL_OP, (void *)CIL_AND); |
784 | 0 | cil_list_append(expr, f1, v1); |
785 | 0 | cil_list_init(&sub_expr, CIL_TYPE); |
786 | 0 | cil_list_append(sub_expr, CIL_OP, (void *)CIL_NOT); |
787 | 0 | cil_list_append(sub_expr, f2, v2); |
788 | 0 | cil_list_append(expr, CIL_LIST, sub_expr); |
789 | |
|
790 | 0 | return expr; |
791 | 0 | } |
792 | | |
793 | | static struct cil_tree_node *cil_create_and_insert_node(struct cil_tree_node *prev, enum cil_flavor flavor, void *data) |
794 | 0 | { |
795 | 0 | struct cil_tree_node *new; |
796 | |
|
797 | 0 | cil_tree_node_init(&new); |
798 | 0 | new->parent = prev->parent; |
799 | 0 | new->line = prev->line; |
800 | 0 | new->hll_offset = prev->hll_offset; |
801 | 0 | new->flavor = flavor; |
802 | 0 | new->data = data; |
803 | 0 | new->next = prev->next; |
804 | 0 | prev->next = new; |
805 | |
|
806 | 0 | return new; |
807 | 0 | } |
808 | | |
809 | | static int cil_create_and_insert_attribute_and_set(struct cil_db *db, struct cil_tree_node *prev, struct cil_list *str_expr, struct cil_list *datum_expr, ebitmap_t *types, struct cil_symtab_datum **d) |
810 | 0 | { |
811 | 0 | struct cil_tree_node *attr_node = NULL; |
812 | 0 | char *name; |
813 | 0 | struct cil_typeattribute *attr = NULL; |
814 | 0 | struct cil_tree_node *attrset_node = NULL; |
815 | 0 | struct cil_typeattributeset *attrset = NULL; |
816 | 0 | symtab_t *symtab = NULL; |
817 | 0 | int rc = SEPOL_ERR; |
818 | |
|
819 | 0 | name = cil_create_new_attribute_name(db->num_types_and_attrs); |
820 | 0 | if (!name) { |
821 | 0 | goto exit; |
822 | 0 | } |
823 | | |
824 | 0 | cil_typeattributeset_init(&attrset); |
825 | 0 | attrset->attr_str = name; |
826 | 0 | attrset->str_expr = str_expr; |
827 | 0 | attrset->datum_expr = datum_expr; |
828 | |
|
829 | 0 | cil_typeattribute_init(&attr); |
830 | 0 | cil_list_init(&attr->expr_list, CIL_TYPE); |
831 | 0 | cil_list_append(attr->expr_list, CIL_LIST, datum_expr); |
832 | 0 | attr->types = types; |
833 | 0 | attr->used = CIL_ATTR_AVRULE; |
834 | 0 | attr->keep = (ebitmap_cardinality(types) < db->attrs_expand_size) ? CIL_FALSE : CIL_TRUE; |
835 | |
|
836 | 0 | attr_node = cil_create_and_insert_node(prev, CIL_TYPEATTRIBUTE, attr); |
837 | 0 | attrset_node = cil_create_and_insert_node(attr_node, CIL_TYPEATTRIBUTESET, attrset); |
838 | |
|
839 | 0 | rc = cil_get_symtab(prev->parent, &symtab, CIL_SYM_TYPES); |
840 | 0 | if (rc != SEPOL_OK) { |
841 | 0 | goto exit; |
842 | 0 | } |
843 | | |
844 | 0 | rc = cil_symtab_insert(symtab, name, &attr->datum, attr_node); |
845 | 0 | if (rc != SEPOL_OK) { |
846 | 0 | goto exit; |
847 | 0 | } |
848 | | |
849 | 0 | db->num_types_and_attrs++; |
850 | |
|
851 | 0 | *d = &attr->datum; |
852 | |
|
853 | 0 | return SEPOL_OK; |
854 | | |
855 | 0 | exit: |
856 | 0 | if (attr_node) { |
857 | 0 | cil_destroy_typeattribute(attr_node->data); // This will not destroy datum_expr |
858 | 0 | free(attr_node); |
859 | 0 | } |
860 | 0 | if (attrset_node) { |
861 | 0 | prev->next = attrset_node->next; |
862 | 0 | free(attrset_node); |
863 | 0 | } |
864 | 0 | return rc; |
865 | 0 | } |
866 | | |
867 | | struct attr_symtab_map_data { |
868 | | struct cil_symtab_datum *d; |
869 | | ebitmap_t *types; |
870 | | }; |
871 | | |
872 | | static int cil_check_attribute_in_symtab(__attribute__((unused))hashtab_key_t k, hashtab_datum_t d, void *args) |
873 | 0 | { |
874 | 0 | struct attr_symtab_map_data *data = args; |
875 | |
|
876 | 0 | if (FLAVOR(d) == CIL_TYPEATTRIBUTE) { |
877 | 0 | struct cil_typeattribute *attr = (struct cil_typeattribute *)d; |
878 | 0 | if (ebitmap_cmp(data->types, attr->types)) { |
879 | 0 | data->d = d; |
880 | 0 | } |
881 | 0 | } |
882 | 0 | return SEPOL_OK; |
883 | 0 | } |
884 | | |
885 | | static struct cil_symtab_datum *cil_check_for_previously_defined_attribute(struct cil_db *db, ebitmap_t *types, struct cil_symtab_datum *d) |
886 | 0 | { |
887 | 0 | symtab_t *local_symtab, *root_symtab; |
888 | 0 | struct attr_symtab_map_data data; |
889 | 0 | int rc; |
890 | |
|
891 | 0 | data.d = NULL; |
892 | 0 | data.types = types; |
893 | |
|
894 | 0 | local_symtab = d->symtab; |
895 | 0 | root_symtab = &((struct cil_root *)db->ast->root->data)->symtab[CIL_SYM_TYPES]; |
896 | |
|
897 | 0 | if (local_symtab != root_symtab) { |
898 | 0 | rc = cil_symtab_map(local_symtab, cil_check_attribute_in_symtab, &data); |
899 | 0 | if (rc != SEPOL_OK) { |
900 | 0 | return NULL; |
901 | 0 | } |
902 | 0 | } |
903 | | |
904 | 0 | if (!data.d) { |
905 | 0 | rc = cil_symtab_map(root_symtab, cil_check_attribute_in_symtab, &data); |
906 | 0 | if (rc != SEPOL_OK) { |
907 | 0 | return NULL; |
908 | 0 | } |
909 | 0 | } |
910 | | |
911 | 0 | return data.d; |
912 | 0 | } |
913 | | |
914 | | static int cil_create_attribute_all_and_not_d(struct cil_db *db, struct cil_symtab_datum *d, struct cil_symtab_datum **d3) |
915 | 0 | { |
916 | 0 | struct cil_list *str_expr; |
917 | 0 | struct cil_list *datum_expr; |
918 | 0 | ebitmap_t *types; |
919 | 0 | int rc; |
920 | |
|
921 | 0 | *d3 = NULL; |
922 | |
|
923 | 0 | if (!d) { |
924 | 0 | return SEPOL_ERR; |
925 | 0 | } |
926 | | |
927 | 0 | str_expr = cil_create_andnot_expr_list(CIL_OP, (void *)CIL_ALL, CIL_STRING, d->fqn); |
928 | 0 | datum_expr = cil_create_andnot_expr_list(CIL_OP, (void *)CIL_ALL, CIL_DATUM, d); |
929 | |
|
930 | 0 | types = cil_malloc(sizeof(*types)); |
931 | 0 | rc = cil_datum_not(types, d, db->num_types); |
932 | 0 | if (rc != SEPOL_OK) { |
933 | 0 | goto exit; |
934 | 0 | } |
935 | | |
936 | 0 | if (ebitmap_is_empty(types)) { |
937 | 0 | rc = SEPOL_OK; |
938 | 0 | goto exit; |
939 | 0 | } |
940 | | |
941 | 0 | if (ebitmap_cardinality(types) == 1) { |
942 | 0 | unsigned i = ebitmap_highest_set_bit(types); |
943 | 0 | *d3 = DATUM(db->val_to_type[i]); |
944 | 0 | ebitmap_destroy(types); |
945 | 0 | rc = SEPOL_OK; |
946 | 0 | goto exit; |
947 | 0 | } |
948 | | |
949 | 0 | *d3 = cil_check_for_previously_defined_attribute(db, types, d); |
950 | 0 | if (*d3) { |
951 | 0 | ebitmap_destroy(types); |
952 | 0 | rc = SEPOL_OK; |
953 | 0 | goto exit; |
954 | 0 | } |
955 | | |
956 | 0 | rc = cil_create_and_insert_attribute_and_set(db, NODE(d), str_expr, datum_expr, types, d3); |
957 | 0 | if (rc != SEPOL_OK) { |
958 | 0 | goto exit; |
959 | 0 | } |
960 | | |
961 | 0 | return SEPOL_OK; |
962 | | |
963 | 0 | exit: |
964 | 0 | cil_list_destroy(&str_expr, CIL_FALSE); |
965 | 0 | cil_list_destroy(&datum_expr, CIL_FALSE); |
966 | 0 | free(types); |
967 | 0 | return rc; |
968 | 0 | } |
969 | | |
970 | | static int cil_create_attribute_d1_and_not_d2(struct cil_db *db, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2, struct cil_symtab_datum **d3) |
971 | 0 | { |
972 | 0 | struct cil_list *str_expr; |
973 | 0 | struct cil_list *datum_expr; |
974 | 0 | ebitmap_t *types; |
975 | 0 | int rc; |
976 | |
|
977 | 0 | if (!d2) { |
978 | 0 | *d3 = d1; |
979 | 0 | return SEPOL_OK; |
980 | 0 | } |
981 | | |
982 | 0 | *d3 = NULL; |
983 | |
|
984 | 0 | if (!d1 || d1 == d2) { |
985 | 0 | return SEPOL_OK; |
986 | 0 | } |
987 | | |
988 | 0 | str_expr = cil_create_andnot_expr_list(CIL_STRING, d1->fqn, CIL_STRING, d2->fqn); |
989 | 0 | datum_expr = cil_create_andnot_expr_list(CIL_DATUM, d1, CIL_DATUM, d2); |
990 | |
|
991 | 0 | types = cil_malloc(sizeof(*types)); |
992 | 0 | rc = cil_datums_andnot(types, d1, d2); |
993 | 0 | if (rc != SEPOL_OK) { |
994 | 0 | goto exit; |
995 | 0 | } |
996 | 0 | if (ebitmap_is_empty(types)) { |
997 | 0 | rc = SEPOL_OK; |
998 | 0 | goto exit; |
999 | 0 | } |
1000 | | |
1001 | 0 | if (ebitmap_cardinality(types) == 1) { |
1002 | 0 | unsigned i = ebitmap_highest_set_bit(types); |
1003 | 0 | *d3 = DATUM(db->val_to_type[i]); |
1004 | 0 | ebitmap_destroy(types); |
1005 | 0 | rc = SEPOL_OK; |
1006 | 0 | goto exit; |
1007 | 0 | } |
1008 | | |
1009 | 0 | *d3 = cil_check_for_previously_defined_attribute(db, types, d1); |
1010 | 0 | if (*d3) { |
1011 | 0 | ebitmap_destroy(types); |
1012 | 0 | rc = SEPOL_OK; |
1013 | 0 | goto exit; |
1014 | 0 | } |
1015 | | |
1016 | 0 | rc = cil_create_and_insert_attribute_and_set(db, NODE(d1), str_expr, datum_expr, types, d3); |
1017 | 0 | if (rc != SEPOL_OK) { |
1018 | 0 | goto exit; |
1019 | 0 | } |
1020 | | |
1021 | 0 | return SEPOL_OK; |
1022 | | |
1023 | 0 | exit: |
1024 | 0 | cil_list_destroy(&str_expr, CIL_FALSE); |
1025 | 0 | cil_list_destroy(&datum_expr, CIL_FALSE); |
1026 | 0 | free(types); |
1027 | 0 | return rc; |
1028 | 0 | } |
1029 | | |
1030 | | static int cil_create_attribute_d1_and_d2(struct cil_db *db, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2, struct cil_symtab_datum **d3) |
1031 | 0 | { |
1032 | 0 | struct cil_list *str_expr; |
1033 | 0 | struct cil_list *datum_expr; |
1034 | 0 | ebitmap_t *types; |
1035 | 0 | int rc; |
1036 | |
|
1037 | 0 | if (d1 == d2) { |
1038 | 0 | *d3 = d1; |
1039 | 0 | return SEPOL_OK; |
1040 | 0 | } |
1041 | | |
1042 | 0 | *d3 = NULL; |
1043 | |
|
1044 | 0 | if (!d1 || !d2) { |
1045 | 0 | return SEPOL_OK; |
1046 | 0 | } |
1047 | | |
1048 | 0 | str_expr = cil_create_and_expr_list(CIL_STRING, d1->fqn, CIL_STRING, d2->fqn); |
1049 | 0 | datum_expr = cil_create_and_expr_list(CIL_DATUM, d1, CIL_DATUM, d2); |
1050 | |
|
1051 | 0 | types = cil_malloc(sizeof(*types)); |
1052 | 0 | rc = cil_datums_and(types, d1, d2); |
1053 | 0 | if (rc != SEPOL_OK) { |
1054 | 0 | goto exit; |
1055 | 0 | } |
1056 | 0 | if (ebitmap_is_empty(types)) { |
1057 | 0 | rc = SEPOL_OK; |
1058 | 0 | goto exit; |
1059 | 0 | } |
1060 | | |
1061 | 0 | if (ebitmap_cardinality(types) == 1) { |
1062 | 0 | unsigned i = ebitmap_highest_set_bit(types); |
1063 | 0 | *d3 = DATUM(db->val_to_type[i]); |
1064 | 0 | ebitmap_destroy(types); |
1065 | 0 | rc = SEPOL_OK; |
1066 | 0 | goto exit; |
1067 | 0 | } |
1068 | | |
1069 | 0 | *d3 = cil_check_for_previously_defined_attribute(db, types, d1); |
1070 | 0 | if (*d3) { |
1071 | 0 | ebitmap_destroy(types); |
1072 | 0 | rc = SEPOL_OK; |
1073 | 0 | goto exit; |
1074 | 0 | } |
1075 | | |
1076 | 0 | rc = cil_create_and_insert_attribute_and_set(db, NODE(d1), str_expr, datum_expr, types, d3); |
1077 | 0 | if (rc != SEPOL_OK) { |
1078 | 0 | goto exit; |
1079 | 0 | } |
1080 | | |
1081 | 0 | return SEPOL_OK; |
1082 | | |
1083 | 0 | exit: |
1084 | 0 | cil_list_destroy(&str_expr, CIL_FALSE); |
1085 | 0 | cil_list_destroy(&datum_expr, CIL_FALSE); |
1086 | 0 | free(types); |
1087 | 0 | return rc; |
1088 | 0 | } |
1089 | | |
1090 | | static struct cil_avrule *cil_create_avrule(struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms) |
1091 | 0 | { |
1092 | 0 | struct cil_avrule *new; |
1093 | |
|
1094 | 0 | cil_avrule_init(&new); |
1095 | 0 | new->is_extended = CIL_FALSE; |
1096 | 0 | new->rule_kind = CIL_AVRULE_ALLOWED; |
1097 | 0 | new->src_str = src->name; |
1098 | 0 | new->src = src; |
1099 | 0 | new->tgt_str = tgt->name; |
1100 | 0 | new->tgt = tgt; |
1101 | 0 | new->perms.classperms = classperms; |
1102 | |
|
1103 | 0 | return new; |
1104 | 0 | } |
1105 | | |
1106 | | static struct cil_tree_node *cil_create_and_add_avrule(struct cil_tree_node *curr, struct cil_symtab_datum *src, struct cil_symtab_datum *tgt, struct cil_list *classperms) |
1107 | 0 | { |
1108 | 0 | struct cil_avrule *new_avrule; |
1109 | 0 | struct cil_list *new_cp_list; |
1110 | |
|
1111 | 0 | if (!src || !tgt) { |
1112 | 0 | return curr; |
1113 | 0 | } |
1114 | | |
1115 | 0 | cil_classperms_list_copy(&new_cp_list, classperms); |
1116 | 0 | new_avrule = cil_create_avrule(src, tgt, new_cp_list); |
1117 | 0 | return cil_create_and_insert_node(curr, CIL_AVRULE, new_avrule); |
1118 | 0 | } |
1119 | | |
1120 | | static int cil_remove_permissions_from_special_rule(struct cil_db *db, struct cil_tree_node *curr, struct cil_symtab_datum *s1, struct cil_symtab_datum *t1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2, struct cil_list *p4, struct cil_symtab_datum *s3, struct cil_symtab_datum *s4) |
1121 | 0 | { |
1122 | 0 | int rc; |
1123 | |
|
1124 | 0 | if (t1 == DATUM(db->notselftype)) { |
1125 | 0 | if (t2 == DATUM(db->othertype)) { |
1126 | 0 | struct cil_symtab_datum *t; |
1127 | 0 | rc = cil_create_attribute_all_and_not_d(db, s2, &t); |
1128 | 0 | if (rc != SEPOL_OK) { |
1129 | 0 | goto exit; |
1130 | 0 | } |
1131 | 0 | curr = cil_create_and_add_avrule(curr, s4, t, p4); |
1132 | 0 | } else { |
1133 | 0 | struct cil_symtab_datum *s5, *s6, *ta, *tb; |
1134 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, s4, t2, &s5); |
1135 | 0 | if (rc != SEPOL_OK) { |
1136 | 0 | goto exit; |
1137 | 0 | } |
1138 | 0 | rc = cil_create_attribute_d1_and_d2(db, s4, t2, &s6); |
1139 | 0 | if (rc != SEPOL_OK) { |
1140 | 0 | goto exit; |
1141 | 0 | } |
1142 | 0 | rc = cil_create_attribute_all_and_not_d(db, t2, &ta); |
1143 | 0 | if (rc != SEPOL_OK) { |
1144 | 0 | goto exit; |
1145 | 0 | } |
1146 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, ta, s4, &tb); |
1147 | 0 | if (rc != SEPOL_OK) { |
1148 | 0 | goto exit; |
1149 | 0 | } |
1150 | 0 | curr = cil_create_and_add_avrule(curr, s6, ta, p4); |
1151 | 0 | curr = cil_create_and_add_avrule(curr, s5, tb, p4); |
1152 | 0 | if (cil_datum_cardinality(s5) > 1) { |
1153 | 0 | curr = cil_create_and_add_avrule(curr, s5, DATUM(db->othertype), p4); |
1154 | 0 | } |
1155 | 0 | } |
1156 | 0 | } else if (t1 == DATUM(db->othertype)) { |
1157 | 0 | curr = cil_create_and_add_avrule(curr, s3, s4, p4); |
1158 | 0 | if (t2 == DATUM(db->notselftype)) { |
1159 | | /* Nothing else is needed */ |
1160 | 0 | } else if (t2 == DATUM(db->othertype)) { |
1161 | 0 | curr = cil_create_and_add_avrule(curr, s4, s3, p4); |
1162 | 0 | } else { |
1163 | 0 | struct cil_symtab_datum *s5, *s6, *tc, *td; |
1164 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, s4, t2, &s5); |
1165 | 0 | if (rc != SEPOL_OK) { |
1166 | 0 | goto exit; |
1167 | 0 | } |
1168 | 0 | rc = cil_create_attribute_d1_and_d2(db, s4, t2, &s6); |
1169 | 0 | if (rc != SEPOL_OK) { |
1170 | 0 | goto exit; |
1171 | 0 | } |
1172 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, s1, t2, &tc); |
1173 | 0 | if (rc != SEPOL_OK) { |
1174 | 0 | goto exit; |
1175 | 0 | } |
1176 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, s3, t2, &td); |
1177 | 0 | if (rc != SEPOL_OK) { |
1178 | 0 | goto exit; |
1179 | 0 | } |
1180 | 0 | curr = cil_create_and_add_avrule(curr, s6, tc, p4); |
1181 | 0 | curr = cil_create_and_add_avrule(curr, s5, td, p4); |
1182 | 0 | if (cil_datum_cardinality(s5) > 1) { |
1183 | 0 | curr = cil_create_and_add_avrule(curr, s5, DATUM(db->othertype), p4); |
1184 | 0 | } |
1185 | 0 | } |
1186 | 0 | } else { |
1187 | 0 | struct cil_symtab_datum *s8; |
1188 | 0 | rc = cil_create_attribute_d1_and_d2(db, s4, t1, &s8); |
1189 | 0 | if (rc != SEPOL_OK) { |
1190 | 0 | goto exit; |
1191 | 0 | } |
1192 | 0 | curr = cil_create_and_add_avrule(curr, s8, DATUM(db->selftype), p4); |
1193 | 0 | if (t2 == DATUM(db->notselftype)) { |
1194 | | /* Nothing else is needed */ |
1195 | 0 | } else { /* t2 == DATUM(db->othertype) */ |
1196 | 0 | struct cil_symtab_datum *t; |
1197 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, t1, s2, &t); |
1198 | 0 | if (rc != SEPOL_OK) { |
1199 | 0 | goto exit; |
1200 | 0 | } |
1201 | 0 | curr = cil_create_and_add_avrule(curr, s4, t, p4); |
1202 | 0 | } |
1203 | 0 | } |
1204 | 0 | return SEPOL_OK; |
1205 | | |
1206 | 0 | exit: |
1207 | 0 | return rc; |
1208 | 0 | } |
1209 | | |
1210 | | static int cil_remove_permissions_from_rule(struct cil_db *db, struct cil_tree_node *allow_node, const struct cil_tree_node *deny_node) |
1211 | 0 | { |
1212 | 0 | struct cil_avrule *allow_rule = allow_node->data; |
1213 | 0 | struct cil_deny_rule *deny_rule = deny_node->data; |
1214 | 0 | struct cil_symtab_datum *s1 = allow_rule->src; |
1215 | 0 | struct cil_symtab_datum *t1 = allow_rule->tgt; |
1216 | 0 | struct cil_list *p1 = allow_rule->perms.classperms; |
1217 | 0 | struct cil_symtab_datum *s2 = deny_rule->src; |
1218 | 0 | struct cil_symtab_datum *t2 = deny_rule->tgt; |
1219 | 0 | struct cil_list *p2 = deny_rule->classperms; |
1220 | 0 | struct cil_list *p3 = NULL; |
1221 | 0 | struct cil_list *p4 = NULL; |
1222 | 0 | struct cil_symtab_datum *s3, *s4; |
1223 | 0 | struct cil_tree_node *curr = allow_node; |
1224 | 0 | int rc; |
1225 | |
|
1226 | 0 | cil_classperms_list_andnot(&p3, p1, p2); |
1227 | 0 | if (!cil_list_is_empty(p3)) {; |
1228 | 0 | curr = cil_create_and_add_avrule(curr, s1, t1, p3); |
1229 | 0 | } |
1230 | 0 | cil_destroy_classperms_list(&p3); |
1231 | 0 | p3 = NULL; |
1232 | |
|
1233 | 0 | cil_classperms_list_and(&p4, p1, p2); |
1234 | 0 | if (cil_list_is_empty(p4)) { |
1235 | 0 | cil_tree_log(allow_node, CIL_ERR, "Allow rule did not match deny rule: No matching class and permissions"); |
1236 | 0 | cil_tree_log((struct cil_tree_node *)deny_node, CIL_ERR, "Deny rule"); |
1237 | 0 | rc = SEPOL_ERR; |
1238 | 0 | goto exit; |
1239 | 0 | } |
1240 | | |
1241 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, s1, s2, &s3); |
1242 | 0 | if (rc != SEPOL_OK) { |
1243 | 0 | goto exit; |
1244 | 0 | } |
1245 | 0 | curr = cil_create_and_add_avrule(curr, s3, t1, p4); |
1246 | |
|
1247 | 0 | if ((t1 == DATUM(db->selftype) && t2 == DATUM(db->selftype)) || |
1248 | 0 | (t1 == DATUM(db->notselftype) && t2 == DATUM(db->notselftype))) { |
1249 | | /* Nothing more needs to be done */ |
1250 | 0 | rc = SEPOL_OK; |
1251 | 0 | goto exit; |
1252 | 0 | } |
1253 | | |
1254 | 0 | rc = cil_create_attribute_d1_and_d2(db, s1, s2, &s4); |
1255 | 0 | if (rc != SEPOL_OK) { |
1256 | 0 | goto exit; |
1257 | 0 | } |
1258 | | |
1259 | 0 | if (t1 == DATUM(db->notselftype) || t1 == DATUM(db->othertype) || |
1260 | 0 | t2 == DATUM(db->notselftype) || t2 == DATUM(db->othertype)) { |
1261 | 0 | rc = cil_remove_permissions_from_special_rule(db, curr, s1, t1, s2, t2, p4, s3, s4); |
1262 | 0 | goto exit; |
1263 | 0 | } |
1264 | | |
1265 | 0 | if (t1 == DATUM(db->selftype) && t2 != DATUM(db->selftype)) { |
1266 | 0 | struct cil_symtab_datum *s5; |
1267 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, s4, t2, &s5); |
1268 | 0 | if (rc != SEPOL_OK) { |
1269 | 0 | goto exit; |
1270 | 0 | } |
1271 | 0 | curr = cil_create_and_add_avrule(curr, s5, DATUM(db->selftype), p4); |
1272 | 0 | } else if (t1 != DATUM(db->selftype) && t2 == DATUM(db->selftype)) { |
1273 | 0 | struct cil_symtab_datum *s7, *s8, *t8; |
1274 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, s4, t1, &s7); |
1275 | 0 | if (rc != SEPOL_OK) { |
1276 | 0 | goto exit; |
1277 | 0 | } |
1278 | 0 | rc = cil_create_attribute_d1_and_d2(db, s4, t1, &s8); |
1279 | 0 | if (rc != SEPOL_OK) { |
1280 | 0 | goto exit; |
1281 | 0 | } |
1282 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, t1, s4, &t8); |
1283 | 0 | if (rc != SEPOL_OK) { |
1284 | 0 | goto exit; |
1285 | 0 | } |
1286 | 0 | curr = cil_create_and_add_avrule(curr, s7, t1, p4); |
1287 | 0 | curr = cil_create_and_add_avrule(curr, s8, t8, p4); |
1288 | 0 | if (cil_datum_cardinality(s8) > 1) { |
1289 | 0 | curr = cil_create_and_add_avrule(curr, s8, DATUM(db->othertype), p4); |
1290 | 0 | } |
1291 | 0 | } else { |
1292 | 0 | struct cil_symtab_datum *t3; |
1293 | 0 | rc = cil_create_attribute_d1_and_not_d2(db, t1, t2, &t3); |
1294 | 0 | if (rc != SEPOL_OK) { |
1295 | 0 | goto exit; |
1296 | 0 | } |
1297 | 0 | curr = cil_create_and_add_avrule(curr, s4, t3, p4); |
1298 | 0 | } |
1299 | | |
1300 | 0 | exit: |
1301 | 0 | if (p4) { |
1302 | 0 | cil_destroy_classperms_list(&p4); |
1303 | 0 | } |
1304 | 0 | return rc; |
1305 | 0 | } |
1306 | | |
1307 | | static int cil_find_matching_allow_rules(struct cil_list *matching, struct cil_tree_node *start, struct cil_tree_node *deny_node) |
1308 | 0 | { |
1309 | 0 | struct cil_deny_rule *deny_rule = deny_node->data; |
1310 | 0 | struct cil_avrule target; |
1311 | |
|
1312 | 0 | target.rule_kind = CIL_AVRULE_ALLOWED; |
1313 | 0 | target.is_extended = CIL_FALSE; |
1314 | 0 | target.src = deny_rule->src; |
1315 | 0 | target.tgt = deny_rule->tgt; |
1316 | 0 | target.perms.classperms = deny_rule->classperms; |
1317 | |
|
1318 | 0 | return cil_find_matching_avrule_in_ast(start, CIL_AVRULE, &target, matching, CIL_FALSE); |
1319 | 0 | } |
1320 | | |
1321 | | static int cil_process_deny_rule(struct cil_db *db, struct cil_tree_node *start, struct cil_tree_node *deny_node) |
1322 | 0 | { |
1323 | 0 | struct cil_list *matching; |
1324 | 0 | struct cil_list_item *item; |
1325 | 0 | int rc; |
1326 | |
|
1327 | 0 | cil_list_init(&matching, CIL_NODE); |
1328 | |
|
1329 | 0 | rc = cil_find_matching_allow_rules(matching, start, deny_node); |
1330 | 0 | if (rc != SEPOL_OK) { |
1331 | 0 | goto exit; |
1332 | 0 | } |
1333 | | |
1334 | 0 | cil_list_for_each(item, matching) { |
1335 | 0 | struct cil_tree_node *allow_node = item->data; |
1336 | 0 | rc = cil_remove_permissions_from_rule(db, allow_node, deny_node); |
1337 | 0 | cil_tree_node_remove(allow_node); |
1338 | 0 | if (rc != SEPOL_OK) { |
1339 | 0 | goto exit; |
1340 | 0 | } |
1341 | |
|
1342 | 0 | } |
1343 | | |
1344 | 0 | exit: |
1345 | 0 | cil_list_destroy(&matching, CIL_FALSE); |
1346 | 0 | return rc; |
1347 | 0 | } |
1348 | | |
1349 | | static int cil_process_deny_rules(struct cil_db *db, struct cil_tree_node *start, struct cil_list *deny_rules) |
1350 | 6 | { |
1351 | 6 | struct cil_list_item *item; |
1352 | 6 | int rc = SEPOL_OK; |
1353 | | |
1354 | 6 | cil_list_for_each(item, deny_rules) { |
1355 | 0 | struct cil_tree_node *deny_node = item->data; |
1356 | 0 | rc = cil_process_deny_rule(db, start, deny_node); |
1357 | 0 | if (rc != SEPOL_OK) { |
1358 | 0 | goto exit; |
1359 | 0 | } |
1360 | 0 | cil_tree_node_remove(deny_node); |
1361 | 0 | } |
1362 | | |
1363 | 6 | exit: |
1364 | 6 | return rc; |
1365 | 6 | } |
1366 | | |
1367 | | static int __cil_find_deny_rules(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
1368 | 36 | { |
1369 | 36 | struct cil_list *deny_rules = extra_args; |
1370 | | |
1371 | 36 | if (node->flavor == CIL_BLOCK) { |
1372 | 0 | struct cil_block *block = node->data; |
1373 | 0 | if (block->is_abstract == CIL_TRUE) { |
1374 | 0 | *finished = CIL_TREE_SKIP_HEAD; |
1375 | 0 | } |
1376 | 36 | } else if (node->flavor == CIL_MACRO) { |
1377 | 0 | *finished = CIL_TREE_SKIP_HEAD; |
1378 | 36 | } else if (node->flavor == CIL_DENY_RULE) { |
1379 | 0 | cil_list_append(deny_rules, CIL_DENY_RULE, node); |
1380 | 0 | } |
1381 | 36 | return SEPOL_OK; |
1382 | 36 | } |
1383 | | |
1384 | | int cil_process_deny_rules_in_ast(struct cil_db *db) |
1385 | 6 | { |
1386 | 6 | struct cil_tree_node *start; |
1387 | 6 | struct cil_list *deny_rules; |
1388 | 6 | int rc = SEPOL_ERR; |
1389 | | |
1390 | 6 | cil_list_init(&deny_rules, CIL_DENY_RULE); |
1391 | | |
1392 | 6 | if (!db) { |
1393 | 0 | cil_log(CIL_ERR, "No CIL db provided to process deny rules\n"); |
1394 | 0 | goto exit; |
1395 | 0 | } |
1396 | | |
1397 | 6 | start = db->ast->root; |
1398 | 6 | rc = cil_tree_walk(start, __cil_find_deny_rules, NULL, NULL, deny_rules); |
1399 | 6 | if (rc != SEPOL_OK) { |
1400 | 0 | cil_log(CIL_ERR, "An error occurred while getting deny rules\n"); |
1401 | 0 | goto exit; |
1402 | 0 | } |
1403 | | |
1404 | 6 | rc = cil_process_deny_rules(db, start, deny_rules); |
1405 | 6 | if (rc != SEPOL_OK) { |
1406 | 0 | cil_log(CIL_ERR, "An error occurred while processing deny rules\n"); |
1407 | 0 | goto exit; |
1408 | 0 | } |
1409 | | |
1410 | 6 | exit: |
1411 | 6 | cil_list_destroy(&deny_rules, CIL_FALSE); |
1412 | 6 | return rc; |
1413 | 6 | } |