/src/selinux/libsepol/src/assertion.c
Line | Count | Source |
1 | | /* Authors: Joshua Brindle <jbrindle@tresys.com> |
2 | | * |
3 | | * Assertion checker for avtab entries, taken from |
4 | | * checkpolicy.c by Stephen Smalley <stephen.smalley.work@gmail.com> |
5 | | * |
6 | | * Copyright (C) 2005 Tresys Technology, LLC |
7 | | * |
8 | | * This library is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public |
10 | | * License as published by the Free Software Foundation; either |
11 | | * version 2.1 of the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public |
19 | | * License along with this library; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | #include <stdbool.h> |
24 | | #include <sepol/policydb/avtab.h> |
25 | | #include <sepol/policydb/policydb.h> |
26 | | #include <sepol/policydb/expand.h> |
27 | | #include <sepol/policydb/util.h> |
28 | | |
29 | | #include "private.h" |
30 | | #include "debug.h" |
31 | | |
32 | | struct avtab_match_args { |
33 | | sepol_handle_t *handle; |
34 | | policydb_t *p; |
35 | | const avrule_t *narule; |
36 | | unsigned long errors; |
37 | | bool conditional; |
38 | | }; |
39 | | |
40 | | static const char *policy_name(const policydb_t *p) |
41 | 0 | { |
42 | 0 | return p->name ?: "policy.conf"; |
43 | 0 | } |
44 | | |
45 | | static void report_failure(sepol_handle_t *handle, const policydb_t *p, |
46 | | const avrule_t *narule, unsigned int stype, |
47 | | unsigned int ttype, const class_perm_node_t *curperm, |
48 | | uint32_t perms) |
49 | 0 | { |
50 | 0 | char *permstr = sepol_av_to_string(p, curperm->tclass, perms); |
51 | |
|
52 | 0 | if (narule->source_filename) { |
53 | 0 | ERR(handle, |
54 | 0 | "neverallow on line %lu of %s (or line %lu of %s) violated by allow %s %s:%s {%s };", |
55 | 0 | narule->source_line, narule->source_filename, narule->line, |
56 | 0 | policy_name(p), p->p_type_val_to_name[stype], |
57 | 0 | p->p_type_val_to_name[ttype], |
58 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
59 | 0 | permstr ?: "<format-failure>"); |
60 | 0 | } else if (narule->line) { |
61 | 0 | ERR(handle, |
62 | 0 | "neverallow on line %lu violated by allow %s %s:%s {%s };", |
63 | 0 | narule->line, p->p_type_val_to_name[stype], |
64 | 0 | p->p_type_val_to_name[ttype], |
65 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
66 | 0 | permstr ?: "<format-failure>"); |
67 | 0 | } else { |
68 | 0 | ERR(handle, "neverallow violated by allow %s %s:%s {%s };", |
69 | 0 | p->p_type_val_to_name[stype], p->p_type_val_to_name[ttype], |
70 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
71 | 0 | permstr ?: "<format-failure>"); |
72 | 0 | } |
73 | |
|
74 | 0 | free(permstr); |
75 | 0 | } |
76 | | |
77 | | static bool match_any_class_permissions(const class_perm_node_t *cp, |
78 | | uint32_t class, uint32_t data) |
79 | 0 | { |
80 | 0 | for (; cp; cp = cp->next) { |
81 | 0 | if ((cp->tclass == class) && (cp->data & data)) |
82 | 0 | return true; |
83 | 0 | } |
84 | | |
85 | 0 | return false; |
86 | 0 | } |
87 | | |
88 | | static bool extended_permissions_and(const uint32_t *perms1, |
89 | | const uint32_t *perms2) |
90 | 0 | { |
91 | 0 | size_t i; |
92 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) { |
93 | 0 | if (perms1[i] & perms2[i]) |
94 | 0 | return true; |
95 | 0 | } |
96 | | |
97 | 0 | return false; |
98 | 0 | } |
99 | | |
100 | | static bool check_extended_permissions(const av_extended_perms_t *neverallow, |
101 | | const avtab_extended_perms_t *allow) |
102 | 0 | { |
103 | 0 | bool rc = false; |
104 | 0 | if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) && |
105 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
106 | 0 | if (neverallow->driver == allow->driver) |
107 | 0 | rc = extended_permissions_and(neverallow->perms, |
108 | 0 | allow->perms); |
109 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) && |
110 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
111 | 0 | rc = xperm_test(neverallow->driver, allow->perms); |
112 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) && |
113 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
114 | 0 | rc = xperm_test(allow->driver, neverallow->perms); |
115 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) && |
116 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
117 | 0 | rc = extended_permissions_and(neverallow->perms, allow->perms); |
118 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_NLMSG) && |
119 | 0 | (allow->specified == AVTAB_XPERMS_NLMSG)) { |
120 | 0 | if (neverallow->driver == allow->driver) |
121 | 0 | rc = extended_permissions_and(neverallow->perms, |
122 | 0 | allow->perms); |
123 | 0 | } |
124 | |
|
125 | 0 | return rc; |
126 | 0 | } |
127 | | |
128 | | /* Compute which allowed extended permissions violate the neverallow rule */ |
129 | | static void extended_permissions_violated(avtab_extended_perms_t *result, |
130 | | const av_extended_perms_t *neverallow, |
131 | | const avtab_extended_perms_t *allow) |
132 | 0 | { |
133 | 0 | size_t i; |
134 | 0 | if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) && |
135 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
136 | 0 | result->specified = AVTAB_XPERMS_IOCTLFUNCTION; |
137 | 0 | result->driver = allow->driver; |
138 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) |
139 | 0 | result->perms[i] = neverallow->perms[i] & |
140 | 0 | allow->perms[i]; |
141 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) && |
142 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
143 | 0 | result->specified = AVTAB_XPERMS_IOCTLFUNCTION; |
144 | 0 | result->driver = neverallow->driver; |
145 | 0 | memcpy(result->perms, neverallow->perms, sizeof(result->perms)); |
146 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) && |
147 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
148 | 0 | result->specified = AVTAB_XPERMS_IOCTLFUNCTION; |
149 | 0 | result->driver = allow->driver; |
150 | 0 | memcpy(result->perms, allow->perms, sizeof(result->perms)); |
151 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) && |
152 | 0 | (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
153 | 0 | result->specified = AVTAB_XPERMS_IOCTLDRIVER; |
154 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) |
155 | 0 | result->perms[i] = neverallow->perms[i] & |
156 | 0 | allow->perms[i]; |
157 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_NLMSG) && |
158 | 0 | (allow->specified == AVTAB_XPERMS_NLMSG)) { |
159 | 0 | result->specified = AVTAB_XPERMS_NLMSG; |
160 | 0 | result->driver = allow->driver; |
161 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) |
162 | 0 | result->perms[i] = neverallow->perms[i] & |
163 | 0 | allow->perms[i]; |
164 | 0 | } |
165 | 0 | } |
166 | | |
167 | | static bool match_node_key(const struct avtab_node *node, |
168 | | const avtab_key_t *key) |
169 | 0 | { |
170 | 0 | return node->key.source_type == key->source_type && |
171 | 0 | node->key.target_type == key->target_type && |
172 | 0 | node->key.target_class == key->target_class; |
173 | 0 | } |
174 | | |
175 | | /* Same scenarios of interest as check_assertion_extended_permissions */ |
176 | | static int report_assertion_extended_permissions( |
177 | | sepol_handle_t *handle, policydb_t *p, const avrule_t *narule, |
178 | | unsigned int stype, unsigned int ttype, |
179 | | const class_perm_node_t *curperm, uint32_t perms, const avtab_key_t *k, |
180 | | bool conditional) |
181 | 0 | { |
182 | 0 | avtab_ptr_t node; |
183 | 0 | avtab_key_t tmp_key; |
184 | 0 | avtab_extended_perms_t *xperms; |
185 | 0 | avtab_extended_perms_t error; |
186 | 0 | const ebitmap_t *sattr = &p->type_attr_map[stype]; |
187 | 0 | const ebitmap_t *tattr = &p->type_attr_map[ttype]; |
188 | 0 | ebitmap_node_t *snode, *tnode; |
189 | 0 | unsigned int i, j; |
190 | 0 | bool found_xperm = false, found_cond_conflict = false; |
191 | 0 | int errors = 0; |
192 | |
|
193 | 0 | memcpy(&tmp_key, k, sizeof(avtab_key_t)); |
194 | 0 | tmp_key.specified = AVTAB_XPERMS_ALLOWED; |
195 | |
|
196 | 0 | ebitmap_for_each_positive_bit(sattr, snode, i) { |
197 | 0 | tmp_key.source_type = i + 1; |
198 | 0 | ebitmap_for_each_positive_bit(tattr, tnode, j) { |
199 | 0 | tmp_key.target_type = j + 1; |
200 | 0 | for (node = avtab_search_node(&p->te_avtab, &tmp_key); |
201 | 0 | node; node = avtab_search_node_next( |
202 | 0 | node, tmp_key.specified)) { |
203 | 0 | xperms = node->datum.xperms; |
204 | 0 | if ((xperms->specified != |
205 | 0 | AVTAB_XPERMS_IOCTLFUNCTION) && |
206 | 0 | (xperms->specified != |
207 | 0 | AVTAB_XPERMS_IOCTLDRIVER) && |
208 | 0 | (xperms->specified != AVTAB_XPERMS_NLMSG)) |
209 | 0 | continue; |
210 | 0 | found_xperm = true; |
211 | | /* failure on the extended permission check_extended_permissions */ |
212 | 0 | if (check_extended_permissions(narule->xperms, |
213 | 0 | xperms)) { |
214 | 0 | char *permstring; |
215 | |
|
216 | 0 | extended_permissions_violated( |
217 | 0 | &error, narule->xperms, xperms); |
218 | 0 | permstring = |
219 | 0 | sepol_extended_perms_to_string( |
220 | 0 | &error); |
221 | |
|
222 | 0 | ERR(handle, |
223 | 0 | "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
224 | 0 | " allowxperm %s %s:%s %s;", |
225 | 0 | narule->source_line, |
226 | 0 | narule->source_filename, |
227 | 0 | narule->line, policy_name(p), |
228 | 0 | p->p_type_val_to_name[i], |
229 | 0 | p->p_type_val_to_name[j], |
230 | 0 | p->p_class_val_to_name |
231 | 0 | [curperm->tclass - 1], |
232 | 0 | permstring ?: "<format-failure>"); |
233 | |
|
234 | 0 | free(permstring); |
235 | 0 | errors++; |
236 | 0 | } |
237 | 0 | } |
238 | |
|
239 | 0 | for (const cond_list_t *cl = p->cond_list; cl; |
240 | 0 | cl = cl->next) { |
241 | 0 | bool found_true_base = false, |
242 | 0 | found_true_xperm = false; |
243 | 0 | bool found_false_base = false, |
244 | 0 | found_false_xperm = false; |
245 | |
|
246 | 0 | for (const cond_av_list_t *cal = cl->true_list; |
247 | 0 | cal; cal = cal->next) { |
248 | 0 | node = cal->node; /* node->next is not from the same condition */ |
249 | 0 | if (!node) |
250 | 0 | continue; |
251 | | |
252 | 0 | if (!match_node_key(node, &tmp_key)) |
253 | 0 | continue; |
254 | | |
255 | 0 | if (match_any_class_permissions( |
256 | 0 | narule->perms, |
257 | 0 | node->key.target_class, |
258 | 0 | node->datum.data)) { |
259 | 0 | found_true_base = true; |
260 | 0 | continue; |
261 | 0 | } |
262 | | |
263 | 0 | if (!(node->key.specified & |
264 | 0 | AVTAB_XPERMS_ALLOWED)) |
265 | 0 | continue; |
266 | | |
267 | 0 | xperms = node->datum.xperms; |
268 | 0 | if ((xperms->specified != |
269 | 0 | AVTAB_XPERMS_IOCTLFUNCTION) && |
270 | 0 | (xperms->specified != |
271 | 0 | AVTAB_XPERMS_IOCTLDRIVER) && |
272 | 0 | (xperms->specified != |
273 | 0 | AVTAB_XPERMS_NLMSG)) |
274 | 0 | continue; |
275 | 0 | found_true_xperm = true; |
276 | | /* failure on the extended permission check_extended_permissions */ |
277 | 0 | if (check_extended_permissions( |
278 | 0 | narule->xperms, xperms)) { |
279 | 0 | char *permstring; |
280 | |
|
281 | 0 | extended_permissions_violated( |
282 | 0 | &error, narule->xperms, |
283 | 0 | xperms); |
284 | 0 | permstring = |
285 | 0 | sepol_extended_perms_to_string( |
286 | 0 | &error); |
287 | |
|
288 | 0 | ERR(handle, |
289 | 0 | "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
290 | 0 | " allowxperm %s %s:%s %s;", |
291 | 0 | narule->source_line, |
292 | 0 | narule->source_filename, |
293 | 0 | narule->line, |
294 | 0 | policy_name(p), |
295 | 0 | p->p_type_val_to_name[i], |
296 | 0 | p->p_type_val_to_name[j], |
297 | 0 | p->p_class_val_to_name |
298 | 0 | [curperm->tclass - |
299 | 0 | 1], |
300 | 0 | permstring ?: |
301 | 0 | "<format-failure>"); |
302 | |
|
303 | 0 | free(permstring); |
304 | 0 | errors++; |
305 | 0 | } |
306 | 0 | } |
307 | |
|
308 | 0 | for (const cond_av_list_t *cal = cl->false_list; |
309 | 0 | cal; cal = cal->next) { |
310 | 0 | node = cal->node; /* node->next is not from the same condition */ |
311 | 0 | if (!node) |
312 | 0 | continue; |
313 | | |
314 | 0 | if (!match_node_key(node, &tmp_key)) |
315 | 0 | continue; |
316 | | |
317 | 0 | if (match_any_class_permissions( |
318 | 0 | narule->perms, |
319 | 0 | node->key.target_class, |
320 | 0 | node->datum.data)) { |
321 | 0 | found_false_base = true; |
322 | 0 | continue; |
323 | 0 | } |
324 | | |
325 | 0 | if (!(node->key.specified & |
326 | 0 | AVTAB_XPERMS_ALLOWED)) |
327 | 0 | continue; |
328 | | |
329 | 0 | xperms = node->datum.xperms; |
330 | 0 | if ((xperms->specified != |
331 | 0 | AVTAB_XPERMS_IOCTLFUNCTION) && |
332 | 0 | (xperms->specified != |
333 | 0 | AVTAB_XPERMS_IOCTLDRIVER) && |
334 | 0 | (xperms->specified != |
335 | 0 | AVTAB_XPERMS_NLMSG)) |
336 | 0 | continue; |
337 | 0 | found_false_xperm = true; |
338 | | /* failure on the extended permission check_extended_permissions */ |
339 | 0 | if (check_extended_permissions( |
340 | 0 | narule->xperms, xperms)) { |
341 | 0 | char *permstring; |
342 | |
|
343 | 0 | extended_permissions_violated( |
344 | 0 | &error, narule->xperms, |
345 | 0 | xperms); |
346 | 0 | permstring = |
347 | 0 | sepol_extended_perms_to_string( |
348 | 0 | &error); |
349 | |
|
350 | 0 | ERR(handle, |
351 | 0 | "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
352 | 0 | " allowxperm %s %s:%s %s;", |
353 | 0 | narule->source_line, |
354 | 0 | narule->source_filename, |
355 | 0 | narule->line, |
356 | 0 | policy_name(p), |
357 | 0 | p->p_type_val_to_name[i], |
358 | 0 | p->p_type_val_to_name[j], |
359 | 0 | p->p_class_val_to_name |
360 | 0 | [curperm->tclass - |
361 | 0 | 1], |
362 | 0 | permstring ?: |
363 | 0 | "<format-failure>"); |
364 | |
|
365 | 0 | free(permstring); |
366 | 0 | errors++; |
367 | 0 | } |
368 | 0 | } |
369 | |
|
370 | 0 | if (found_true_xperm && found_false_xperm) |
371 | 0 | found_xperm = true; |
372 | 0 | else if (conditional && ((found_true_base && |
373 | 0 | !found_true_xperm) || |
374 | 0 | (found_false_base && |
375 | 0 | !found_false_xperm))) |
376 | 0 | found_cond_conflict = true; |
377 | 0 | } |
378 | 0 | } |
379 | 0 | } |
380 | |
|
381 | 0 | if ((!found_xperm && !conditional) || found_cond_conflict) { |
382 | | /* failure on the regular permissions */ |
383 | 0 | char *permstr = sepol_av_to_string(p, curperm->tclass, perms); |
384 | |
|
385 | 0 | ERR(handle, |
386 | 0 | "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
387 | 0 | " allow %s %s:%s {%s };", |
388 | 0 | narule->source_line, narule->source_filename, narule->line, |
389 | 0 | policy_name(p), p->p_type_val_to_name[stype], |
390 | 0 | p->p_type_val_to_name[ttype], |
391 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
392 | 0 | permstr ?: "<format-failure>"); |
393 | |
|
394 | 0 | free(permstr); |
395 | 0 | errors++; |
396 | 0 | } |
397 | |
|
398 | 0 | return errors; |
399 | 0 | } |
400 | | |
401 | | static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, |
402 | | void *args) |
403 | 0 | { |
404 | 0 | int rc = 0; |
405 | 0 | struct avtab_match_args *a = (struct avtab_match_args *)args; |
406 | 0 | sepol_handle_t *handle = a->handle; |
407 | 0 | policydb_t *p = a->p; |
408 | 0 | const avrule_t *narule = a->narule; |
409 | 0 | const class_perm_node_t *cp; |
410 | 0 | uint32_t perms; |
411 | 0 | ebitmap_t src_matches, tgt_matches, self_matches; |
412 | 0 | ebitmap_node_t *snode, *tnode; |
413 | 0 | unsigned int i, j; |
414 | 0 | const bool is_narule_self = (narule->flags & RULE_SELF) != 0; |
415 | 0 | const bool is_narule_notself = (narule->flags & RULE_NOTSELF) != 0; |
416 | |
|
417 | 0 | if ((k->specified & AVTAB_ALLOWED) == 0) |
418 | 0 | return 0; |
419 | | |
420 | 0 | if (!match_any_class_permissions(narule->perms, k->target_class, |
421 | 0 | d->data)) |
422 | 0 | return 0; |
423 | | |
424 | 0 | ebitmap_init(&src_matches); |
425 | 0 | ebitmap_init(&tgt_matches); |
426 | 0 | ebitmap_init(&self_matches); |
427 | |
|
428 | 0 | rc = ebitmap_and(&src_matches, &narule->stypes.types, |
429 | 0 | &p->attr_type_map[k->source_type - 1]); |
430 | 0 | if (rc < 0) |
431 | 0 | goto oom; |
432 | | |
433 | 0 | if (ebitmap_is_empty(&src_matches)) |
434 | 0 | goto exit; |
435 | | |
436 | 0 | if (is_narule_notself) { |
437 | 0 | if (ebitmap_is_empty(&narule->ttypes.types)) { |
438 | | /* avrule tgt is of the form ~self */ |
439 | 0 | rc = ebitmap_cpy(&tgt_matches, |
440 | 0 | &p->attr_type_map[k->target_type - 1]); |
441 | 0 | } else { |
442 | | /* avrule tgt is of the form {ATTR -self} */ |
443 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, |
444 | 0 | &p->attr_type_map[k->target_type - 1]); |
445 | 0 | } |
446 | 0 | if (rc) |
447 | 0 | goto oom; |
448 | 0 | } else { |
449 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, |
450 | 0 | &p->attr_type_map[k->target_type - 1]); |
451 | 0 | if (rc < 0) |
452 | 0 | goto oom; |
453 | | |
454 | 0 | if (is_narule_self) { |
455 | 0 | rc = ebitmap_and(&self_matches, &src_matches, |
456 | 0 | &p->attr_type_map[k->target_type - 1]); |
457 | 0 | if (rc < 0) |
458 | 0 | goto oom; |
459 | | |
460 | 0 | if (!ebitmap_is_empty(&self_matches)) { |
461 | 0 | rc = ebitmap_union(&tgt_matches, &self_matches); |
462 | 0 | if (rc < 0) |
463 | 0 | goto oom; |
464 | 0 | } |
465 | 0 | } |
466 | 0 | } |
467 | | |
468 | 0 | if (ebitmap_is_empty(&tgt_matches)) |
469 | 0 | goto exit; |
470 | | |
471 | 0 | for (cp = narule->perms; cp; cp = cp->next) { |
472 | 0 | perms = cp->data & d->data; |
473 | 0 | if ((cp->tclass != k->target_class) || !perms) { |
474 | 0 | continue; |
475 | 0 | } |
476 | | |
477 | 0 | ebitmap_for_each_positive_bit(&src_matches, snode, i) { |
478 | 0 | ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) { |
479 | 0 | if (is_narule_self && i != j) |
480 | 0 | continue; |
481 | 0 | if (is_narule_notself && i == j) |
482 | 0 | continue; |
483 | 0 | if (narule->specified == |
484 | 0 | AVRULE_XPERMS_NEVERALLOW) { |
485 | 0 | a->errors += |
486 | 0 | report_assertion_extended_permissions( |
487 | 0 | handle, p, narule, i, j, |
488 | 0 | cp, perms, k, |
489 | 0 | a->conditional); |
490 | 0 | } else { |
491 | 0 | a->errors++; |
492 | 0 | report_failure(handle, p, narule, i, j, |
493 | 0 | cp, perms); |
494 | 0 | } |
495 | 0 | } |
496 | 0 | } |
497 | 0 | } |
498 | |
|
499 | 0 | oom: |
500 | 0 | exit: |
501 | 0 | ebitmap_destroy(&src_matches); |
502 | 0 | ebitmap_destroy(&tgt_matches); |
503 | 0 | ebitmap_destroy(&self_matches); |
504 | 0 | return rc; |
505 | 0 | } |
506 | | |
507 | | static int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, |
508 | | const avrule_t *narule) |
509 | 0 | { |
510 | 0 | int rc; |
511 | 0 | struct avtab_match_args args = { |
512 | 0 | .handle = handle, |
513 | 0 | .p = p, |
514 | 0 | .narule = narule, |
515 | 0 | .errors = 0, |
516 | 0 | }; |
517 | |
|
518 | 0 | args.conditional = false; |
519 | 0 | rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args); |
520 | 0 | if (rc < 0) |
521 | 0 | goto oom; |
522 | | |
523 | 0 | args.conditional = true; |
524 | 0 | rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, |
525 | 0 | &args); |
526 | 0 | if (rc < 0) |
527 | 0 | goto oom; |
528 | | |
529 | 0 | return args.errors; |
530 | | |
531 | 0 | oom: |
532 | 0 | return rc; |
533 | 0 | } |
534 | | |
535 | | /* |
536 | | * Look up the extended permissions in avtab and verify that neverallowed |
537 | | * permissions are not granted. |
538 | | */ |
539 | | static bool check_assertion_extended_permissions_avtab( |
540 | | const avrule_t *narule, unsigned int stype, unsigned int ttype, |
541 | | const avtab_key_t *k, policydb_t *p, bool conditional) |
542 | 0 | { |
543 | 0 | avtab_ptr_t node; |
544 | 0 | avtab_key_t tmp_key; |
545 | 0 | const avtab_extended_perms_t *xperms; |
546 | 0 | const av_extended_perms_t *neverallow_xperms = narule->xperms; |
547 | 0 | const ebitmap_t *sattr = &p->type_attr_map[stype]; |
548 | 0 | const ebitmap_t *tattr = &p->type_attr_map[ttype]; |
549 | 0 | ebitmap_node_t *snode, *tnode; |
550 | 0 | unsigned int i, j; |
551 | 0 | bool found_xperm = false, found_cond_conflict = false; |
552 | |
|
553 | 0 | memcpy(&tmp_key, k, sizeof(avtab_key_t)); |
554 | 0 | tmp_key.specified = AVTAB_XPERMS_ALLOWED; |
555 | |
|
556 | 0 | ebitmap_for_each_positive_bit(sattr, snode, i) { |
557 | 0 | tmp_key.source_type = i + 1; |
558 | 0 | ebitmap_for_each_positive_bit(tattr, tnode, j) { |
559 | 0 | tmp_key.target_type = j + 1; |
560 | 0 | for (node = avtab_search_node(&p->te_avtab, &tmp_key); |
561 | 0 | node; node = avtab_search_node_next( |
562 | 0 | node, tmp_key.specified)) { |
563 | 0 | xperms = node->datum.xperms; |
564 | |
|
565 | 0 | if ((xperms->specified != |
566 | 0 | AVTAB_XPERMS_IOCTLFUNCTION) && |
567 | 0 | (xperms->specified != |
568 | 0 | AVTAB_XPERMS_IOCTLDRIVER) && |
569 | 0 | (xperms->specified != AVTAB_XPERMS_NLMSG)) |
570 | 0 | continue; |
571 | 0 | found_xperm = true; |
572 | 0 | if (check_extended_permissions( |
573 | 0 | neverallow_xperms, xperms)) |
574 | 0 | return true; |
575 | 0 | } |
576 | | |
577 | 0 | for (const cond_list_t *cl = p->cond_list; cl; |
578 | 0 | cl = cl->next) { |
579 | 0 | bool found_true_base = false, |
580 | 0 | found_true_xperm = false; |
581 | 0 | bool found_false_base = false, |
582 | 0 | found_false_xperm = false; |
583 | |
|
584 | 0 | for (const cond_av_list_t *cal = cl->true_list; |
585 | 0 | cal; cal = cal->next) { |
586 | 0 | node = cal->node; /* node->next is not from the same condition */ |
587 | 0 | if (!node) |
588 | 0 | continue; |
589 | | |
590 | 0 | if (!match_node_key(node, &tmp_key)) |
591 | 0 | continue; |
592 | | |
593 | 0 | if ((node->key.specified & |
594 | 0 | AVTAB_ALLOWED) && |
595 | 0 | match_any_class_permissions( |
596 | 0 | narule->perms, |
597 | 0 | node->key.target_class, |
598 | 0 | node->datum.data)) { |
599 | 0 | found_true_base = true; |
600 | 0 | continue; |
601 | 0 | } |
602 | | |
603 | 0 | if (!(node->key.specified & |
604 | 0 | AVTAB_XPERMS_ALLOWED)) |
605 | 0 | continue; |
606 | | |
607 | 0 | xperms = node->datum.xperms; |
608 | |
|
609 | 0 | if ((xperms->specified != |
610 | 0 | AVTAB_XPERMS_IOCTLFUNCTION) && |
611 | 0 | (xperms->specified != |
612 | 0 | AVTAB_XPERMS_IOCTLDRIVER) && |
613 | 0 | (xperms->specified != |
614 | 0 | AVTAB_XPERMS_NLMSG)) |
615 | 0 | continue; |
616 | 0 | found_true_xperm = true; |
617 | 0 | if (check_extended_permissions( |
618 | 0 | neverallow_xperms, xperms)) |
619 | 0 | return true; |
620 | 0 | } |
621 | | |
622 | 0 | for (const cond_av_list_t *cal = cl->false_list; |
623 | 0 | cal; cal = cal->next) { |
624 | 0 | node = cal->node; /* node->next is not from the same condition */ |
625 | 0 | if (!node) |
626 | 0 | continue; |
627 | | |
628 | 0 | if (!match_node_key(node, &tmp_key)) |
629 | 0 | continue; |
630 | | |
631 | 0 | if ((node->key.specified & |
632 | 0 | AVTAB_ALLOWED) && |
633 | 0 | match_any_class_permissions( |
634 | 0 | narule->perms, |
635 | 0 | node->key.target_class, |
636 | 0 | node->datum.data)) { |
637 | 0 | found_false_base = true; |
638 | 0 | continue; |
639 | 0 | } |
640 | | |
641 | 0 | if (!(node->key.specified & |
642 | 0 | AVTAB_XPERMS_ALLOWED)) |
643 | 0 | continue; |
644 | | |
645 | 0 | xperms = node->datum.xperms; |
646 | |
|
647 | 0 | if ((xperms->specified != |
648 | 0 | AVTAB_XPERMS_IOCTLFUNCTION) && |
649 | 0 | (xperms->specified != |
650 | 0 | AVTAB_XPERMS_IOCTLDRIVER) && |
651 | 0 | (xperms->specified != |
652 | 0 | AVTAB_XPERMS_NLMSG)) |
653 | 0 | continue; |
654 | 0 | found_false_xperm = true; |
655 | 0 | if (check_extended_permissions( |
656 | 0 | neverallow_xperms, xperms)) |
657 | 0 | return true; |
658 | 0 | } |
659 | | |
660 | 0 | if (found_true_xperm && found_false_xperm) |
661 | 0 | found_xperm = true; |
662 | 0 | else if (conditional && ((found_true_base && |
663 | 0 | !found_true_xperm) || |
664 | 0 | (found_false_base && |
665 | 0 | !found_false_xperm))) |
666 | 0 | found_cond_conflict = true; |
667 | 0 | } |
668 | 0 | } |
669 | 0 | } |
670 | | |
671 | 0 | return (!conditional && !found_xperm) || found_cond_conflict; |
672 | 0 | } |
673 | | |
674 | | /* |
675 | | * When the ioctl permission is granted on an avtab entry that matches an |
676 | | * avrule neverallowxperm entry, enumerate over the matching |
677 | | * source/target/class sets to determine if the extended permissions exist |
678 | | * and if the neverallowed ioctls are granted. |
679 | | * |
680 | | * Four scenarios of interest: |
681 | | * 1. PASS - the ioctl permission is not granted for this source/target/class |
682 | | * This case is handled in check_assertion_avtab_match |
683 | | * 2. PASS - The ioctl permission is granted AND the extended permission |
684 | | * is NOT granted |
685 | | * 3. FAIL - The ioctl permission is granted AND no extended permissions |
686 | | * exist |
687 | | * 4. FAIL - The ioctl permission is granted AND the extended permission is |
688 | | * granted |
689 | | */ |
690 | | static int check_assertion_extended_permissions(const avrule_t *narule, |
691 | | const avtab_key_t *k, |
692 | | policydb_t *p, bool conditional) |
693 | 0 | { |
694 | 0 | ebitmap_t src_matches, tgt_matches, self_matches; |
695 | 0 | unsigned int i, j; |
696 | 0 | ebitmap_node_t *snode, *tnode; |
697 | 0 | const bool is_narule_self = (narule->flags & RULE_SELF) != 0; |
698 | 0 | const bool is_narule_notself = (narule->flags & RULE_NOTSELF) != 0; |
699 | 0 | int rc; |
700 | |
|
701 | 0 | ebitmap_init(&src_matches); |
702 | 0 | ebitmap_init(&tgt_matches); |
703 | 0 | ebitmap_init(&self_matches); |
704 | |
|
705 | 0 | rc = ebitmap_and(&src_matches, &narule->stypes.types, |
706 | 0 | &p->attr_type_map[k->source_type - 1]); |
707 | 0 | if (rc < 0) |
708 | 0 | goto oom; |
709 | | |
710 | 0 | if (ebitmap_is_empty(&src_matches)) { |
711 | 0 | rc = 0; |
712 | 0 | goto exit; |
713 | 0 | } |
714 | | |
715 | 0 | if (is_narule_notself) { |
716 | 0 | if (ebitmap_is_empty(&narule->ttypes.types)) { |
717 | | /* avrule tgt is of the form ~self */ |
718 | 0 | rc = ebitmap_cpy(&tgt_matches, |
719 | 0 | &p->attr_type_map[k->target_type - 1]); |
720 | 0 | } else { |
721 | | /* avrule tgt is of the form {ATTR -self} */ |
722 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, |
723 | 0 | &p->attr_type_map[k->target_type - 1]); |
724 | 0 | } |
725 | 0 | if (rc < 0) |
726 | 0 | goto oom; |
727 | 0 | } else { |
728 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, |
729 | 0 | &p->attr_type_map[k->target_type - 1]); |
730 | 0 | if (rc < 0) |
731 | 0 | goto oom; |
732 | | |
733 | 0 | if (is_narule_self) { |
734 | 0 | rc = ebitmap_and(&self_matches, &src_matches, |
735 | 0 | &p->attr_type_map[k->target_type - 1]); |
736 | 0 | if (rc < 0) |
737 | 0 | goto oom; |
738 | | |
739 | 0 | if (!ebitmap_is_empty(&self_matches)) { |
740 | 0 | rc = ebitmap_union(&tgt_matches, &self_matches); |
741 | 0 | if (rc < 0) |
742 | 0 | goto oom; |
743 | 0 | } |
744 | 0 | } |
745 | 0 | } |
746 | | |
747 | 0 | if (ebitmap_is_empty(&tgt_matches)) { |
748 | 0 | rc = 0; |
749 | 0 | goto exit; |
750 | 0 | } |
751 | | |
752 | 0 | ebitmap_for_each_positive_bit(&src_matches, snode, i) { |
753 | 0 | ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) { |
754 | 0 | if (is_narule_self && i != j) |
755 | 0 | continue; |
756 | 0 | if (is_narule_notself && i == j) |
757 | 0 | continue; |
758 | 0 | if (check_assertion_extended_permissions_avtab( |
759 | 0 | narule, i, j, k, p, conditional)) { |
760 | 0 | rc = 1; |
761 | 0 | goto exit; |
762 | 0 | } |
763 | 0 | } |
764 | 0 | } |
765 | | |
766 | 0 | rc = 0; |
767 | |
|
768 | 0 | oom: |
769 | 0 | exit: |
770 | 0 | ebitmap_destroy(&src_matches); |
771 | 0 | ebitmap_destroy(&tgt_matches); |
772 | 0 | ebitmap_destroy(&self_matches); |
773 | 0 | return rc; |
774 | 0 | } |
775 | | |
776 | | static int check_assertion_notself_match(const avtab_key_t *k, |
777 | | const avrule_t *narule, policydb_t *p) |
778 | 0 | { |
779 | 0 | ebitmap_t src_matches, tgt_matches; |
780 | 0 | unsigned int num_src_matches, num_tgt_matches; |
781 | 0 | int rc; |
782 | |
|
783 | 0 | ebitmap_init(&src_matches); |
784 | 0 | ebitmap_init(&tgt_matches); |
785 | |
|
786 | 0 | rc = ebitmap_and(&src_matches, &narule->stypes.types, |
787 | 0 | &p->attr_type_map[k->source_type - 1]); |
788 | 0 | if (rc < 0) |
789 | 0 | goto oom; |
790 | | |
791 | 0 | if (ebitmap_is_empty(&narule->ttypes.types)) { |
792 | | /* avrule tgt is of the form ~self */ |
793 | 0 | rc = ebitmap_cpy(&tgt_matches, |
794 | 0 | &p->attr_type_map[k->target_type - 1]); |
795 | 0 | } else { |
796 | | /* avrule tgt is of the form {ATTR -self} */ |
797 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, |
798 | 0 | &p->attr_type_map[k->target_type - 1]); |
799 | 0 | } |
800 | 0 | if (rc < 0) |
801 | 0 | goto oom; |
802 | | |
803 | 0 | num_src_matches = ebitmap_cardinality(&src_matches); |
804 | 0 | num_tgt_matches = ebitmap_cardinality(&tgt_matches); |
805 | 0 | if (num_src_matches == 0 || num_tgt_matches == 0) { |
806 | 0 | rc = 0; |
807 | 0 | goto nomatch; |
808 | 0 | } |
809 | 0 | if (num_src_matches == 1 && num_tgt_matches == 1) { |
810 | 0 | ebitmap_t matches; |
811 | 0 | unsigned int num_matches; |
812 | 0 | rc = ebitmap_and(&matches, &src_matches, &tgt_matches); |
813 | 0 | if (rc < 0) { |
814 | 0 | ebitmap_destroy(&matches); |
815 | 0 | goto oom; |
816 | 0 | } |
817 | 0 | num_matches = ebitmap_cardinality(&matches); |
818 | 0 | ebitmap_destroy(&matches); |
819 | 0 | if (num_matches == 1) { |
820 | | /* The only non-match is of the form TYPE TYPE */ |
821 | 0 | rc = 0; |
822 | 0 | goto nomatch; |
823 | 0 | } |
824 | 0 | } |
825 | | |
826 | 0 | rc = 1; |
827 | |
|
828 | 0 | oom: |
829 | 0 | nomatch: |
830 | 0 | ebitmap_destroy(&src_matches); |
831 | 0 | ebitmap_destroy(&tgt_matches); |
832 | 0 | return rc; |
833 | 0 | } |
834 | | |
835 | | static int check_assertion_self_match(const avtab_key_t *k, |
836 | | const avrule_t *narule, policydb_t *p) |
837 | 0 | { |
838 | 0 | ebitmap_t src_matches; |
839 | 0 | int rc; |
840 | | |
841 | | /* The key's target must match something in the matches of the avrule's source |
842 | | * and the key's source. |
843 | | */ |
844 | |
|
845 | 0 | rc = ebitmap_and(&src_matches, &narule->stypes.types, |
846 | 0 | &p->attr_type_map[k->source_type - 1]); |
847 | 0 | if (rc < 0) |
848 | 0 | goto oom; |
849 | | |
850 | 0 | if (!ebitmap_match_any(&src_matches, |
851 | 0 | &p->attr_type_map[k->target_type - 1])) { |
852 | 0 | rc = 0; |
853 | 0 | goto nomatch; |
854 | 0 | } |
855 | | |
856 | 0 | rc = 1; |
857 | |
|
858 | 0 | oom: |
859 | 0 | nomatch: |
860 | 0 | ebitmap_destroy(&src_matches); |
861 | 0 | return rc; |
862 | 0 | } |
863 | | |
864 | | static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, |
865 | | void *args) |
866 | 0 | { |
867 | 0 | int rc; |
868 | 0 | struct avtab_match_args *a = (struct avtab_match_args *)args; |
869 | 0 | policydb_t *p = a->p; |
870 | 0 | const avrule_t *narule = a->narule; |
871 | |
|
872 | 0 | if ((k->specified & AVTAB_ALLOWED) == 0) |
873 | 0 | goto nomatch; |
874 | | |
875 | 0 | if (!match_any_class_permissions(narule->perms, k->target_class, |
876 | 0 | d->data)) |
877 | 0 | goto nomatch; |
878 | | |
879 | 0 | if (!ebitmap_match_any(&narule->stypes.types, |
880 | 0 | &p->attr_type_map[k->source_type - 1])) |
881 | 0 | goto nomatch; |
882 | | |
883 | 0 | if (narule->flags & RULE_NOTSELF) { |
884 | 0 | rc = check_assertion_notself_match(k, narule, p); |
885 | 0 | if (rc < 0) |
886 | 0 | goto oom; |
887 | 0 | if (rc == 0) |
888 | 0 | goto nomatch; |
889 | 0 | } else { |
890 | | /* neverallow may have tgts even if it uses SELF */ |
891 | 0 | if (!ebitmap_match_any(&narule->ttypes.types, |
892 | 0 | &p->attr_type_map[k->target_type - 1])) { |
893 | 0 | if (narule->flags == RULE_SELF) { |
894 | 0 | rc = check_assertion_self_match(k, narule, p); |
895 | 0 | if (rc < 0) |
896 | 0 | goto oom; |
897 | 0 | if (rc == 0) |
898 | 0 | goto nomatch; |
899 | 0 | } else { |
900 | 0 | goto nomatch; |
901 | 0 | } |
902 | 0 | } |
903 | 0 | } |
904 | | |
905 | 0 | if (narule->specified == AVRULE_XPERMS_NEVERALLOW) { |
906 | 0 | rc = check_assertion_extended_permissions(narule, k, p, |
907 | 0 | a->conditional); |
908 | 0 | if (rc < 0) |
909 | 0 | goto oom; |
910 | 0 | if (rc == 0) |
911 | 0 | goto nomatch; |
912 | 0 | } |
913 | 0 | return 1; |
914 | | |
915 | 0 | nomatch: |
916 | 0 | return 0; |
917 | | |
918 | 0 | oom: |
919 | 0 | return rc; |
920 | 0 | } |
921 | | |
922 | | int check_assertion(policydb_t *p, const avrule_t *narule) |
923 | 0 | { |
924 | 0 | int rc; |
925 | 0 | struct avtab_match_args args = { |
926 | 0 | .handle = NULL, |
927 | 0 | .p = p, |
928 | 0 | .narule = narule, |
929 | 0 | .errors = 0, |
930 | 0 | }; |
931 | |
|
932 | 0 | args.conditional = false; |
933 | 0 | rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args); |
934 | |
|
935 | 0 | if (rc == 0) { |
936 | 0 | args.conditional = true; |
937 | 0 | rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, |
938 | 0 | &args); |
939 | 0 | } |
940 | |
|
941 | 0 | return rc; |
942 | 0 | } |
943 | | |
944 | | int check_assertions(sepol_handle_t *handle, policydb_t *p, |
945 | | const avrule_t *narules) |
946 | 0 | { |
947 | 0 | int rc; |
948 | 0 | const avrule_t *a; |
949 | 0 | unsigned long errors = 0; |
950 | |
|
951 | 0 | for (a = narules; a != NULL; a = a->next) { |
952 | 0 | if (!(a->specified & |
953 | 0 | (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW))) |
954 | 0 | continue; |
955 | 0 | rc = check_assertion(p, a); |
956 | 0 | if (rc < 0) { |
957 | 0 | ERR(handle, |
958 | 0 | "Error occurred while checking neverallows"); |
959 | 0 | return -1; |
960 | 0 | } |
961 | 0 | if (rc) { |
962 | 0 | rc = report_assertion_failures(handle, p, a); |
963 | 0 | if (rc < 0) { |
964 | 0 | ERR(handle, |
965 | 0 | "Error occurred while checking neverallows"); |
966 | 0 | return -1; |
967 | 0 | } |
968 | 0 | errors += rc; |
969 | 0 | } |
970 | 0 | } |
971 | | |
972 | 0 | if (errors) |
973 | 0 | ERR(handle, "%lu neverallow failures occurred", errors); |
974 | |
|
975 | 0 | return errors ? -1 : 0; |
976 | 0 | } |