/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 | 0 | static const char* policy_name(const policydb_t *p) { |
41 | 0 | return p->name ?: "policy.conf"; |
42 | 0 | } |
43 | | |
44 | | static void report_failure(sepol_handle_t *handle, const policydb_t *p, const avrule_t *narule, |
45 | | unsigned int stype, unsigned int ttype, |
46 | | const class_perm_node_t *curperm, uint32_t perms) |
47 | 0 | { |
48 | 0 | char *permstr = sepol_av_to_string(p, curperm->tclass, perms); |
49 | |
|
50 | 0 | if (narule->source_filename) { |
51 | 0 | ERR(handle, "neverallow on line %lu of %s (or line %lu of %s) violated by allow %s %s:%s {%s };", |
52 | 0 | narule->source_line, narule->source_filename, narule->line, policy_name(p), |
53 | 0 | p->p_type_val_to_name[stype], |
54 | 0 | p->p_type_val_to_name[ttype], |
55 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
56 | 0 | permstr ?: "<format-failure>"); |
57 | 0 | } else if (narule->line) { |
58 | 0 | ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };", |
59 | 0 | narule->line, p->p_type_val_to_name[stype], |
60 | 0 | p->p_type_val_to_name[ttype], |
61 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
62 | 0 | permstr ?: "<format-failure>"); |
63 | 0 | } else { |
64 | 0 | ERR(handle, "neverallow violated by allow %s %s:%s {%s };", |
65 | 0 | p->p_type_val_to_name[stype], |
66 | 0 | p->p_type_val_to_name[ttype], |
67 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
68 | 0 | permstr ?: "<format-failure>"); |
69 | 0 | } |
70 | |
|
71 | 0 | free(permstr); |
72 | 0 | } |
73 | | |
74 | | static bool match_any_class_permissions(const class_perm_node_t *cp, uint32_t class, uint32_t data) |
75 | 27.6M | { |
76 | 49.1M | for (; cp; cp = cp->next) { |
77 | 27.7M | if ((cp->tclass == class) && (cp->data & data)) |
78 | 6.28M | return true; |
79 | 27.7M | } |
80 | | |
81 | 21.3M | return false; |
82 | 27.6M | } |
83 | | |
84 | 0 | static bool extended_permissions_and(const uint32_t *perms1, const uint32_t *perms2) { |
85 | 0 | size_t i; |
86 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) { |
87 | 0 | if (perms1[i] & perms2[i]) |
88 | 0 | return true; |
89 | 0 | } |
90 | | |
91 | 0 | return false; |
92 | 0 | } |
93 | | |
94 | | static bool check_extended_permissions(const av_extended_perms_t *neverallow, const avtab_extended_perms_t *allow) |
95 | 0 | { |
96 | 0 | bool rc = false; |
97 | 0 | if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) |
98 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
99 | 0 | if (neverallow->driver == allow->driver) |
100 | 0 | rc = extended_permissions_and(neverallow->perms, allow->perms); |
101 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) |
102 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
103 | 0 | rc = xperm_test(neverallow->driver, allow->perms); |
104 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) |
105 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
106 | 0 | rc = xperm_test(allow->driver, neverallow->perms); |
107 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) |
108 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
109 | 0 | rc = extended_permissions_and(neverallow->perms, allow->perms); |
110 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_NLMSG) |
111 | 0 | && (allow->specified == AVTAB_XPERMS_NLMSG)) { |
112 | 0 | if (neverallow->driver == allow->driver) |
113 | 0 | rc = extended_permissions_and(neverallow->perms, allow->perms); |
114 | 0 | } |
115 | |
|
116 | 0 | return rc; |
117 | 0 | } |
118 | | |
119 | | /* Compute which allowed extended permissions violate the neverallow rule */ |
120 | | static void extended_permissions_violated(avtab_extended_perms_t *result, |
121 | | const av_extended_perms_t *neverallow, |
122 | | const avtab_extended_perms_t *allow) |
123 | 0 | { |
124 | 0 | size_t i; |
125 | 0 | if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) |
126 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
127 | 0 | result->specified = AVTAB_XPERMS_IOCTLFUNCTION; |
128 | 0 | result->driver = allow->driver; |
129 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) |
130 | 0 | result->perms[i] = neverallow->perms[i] & allow->perms[i]; |
131 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION) |
132 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
133 | 0 | result->specified = AVTAB_XPERMS_IOCTLFUNCTION; |
134 | 0 | result->driver = neverallow->driver; |
135 | 0 | memcpy(result->perms, neverallow->perms, sizeof(result->perms)); |
136 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) |
137 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) { |
138 | 0 | result->specified = AVTAB_XPERMS_IOCTLFUNCTION; |
139 | 0 | result->driver = allow->driver; |
140 | 0 | memcpy(result->perms, allow->perms, sizeof(result->perms)); |
141 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER) |
142 | 0 | && (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) { |
143 | 0 | result->specified = AVTAB_XPERMS_IOCTLDRIVER; |
144 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) |
145 | 0 | result->perms[i] = neverallow->perms[i] & allow->perms[i]; |
146 | 0 | } else if ((neverallow->specified == AVRULE_XPERMS_NLMSG) |
147 | 0 | && (allow->specified == AVTAB_XPERMS_NLMSG)) { |
148 | 0 | result->specified = AVTAB_XPERMS_NLMSG; |
149 | 0 | result->driver = allow->driver; |
150 | 0 | for (i = 0; i < EXTENDED_PERMS_LEN; i++) |
151 | 0 | result->perms[i] = neverallow->perms[i] & allow->perms[i]; |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | | static bool match_node_key(const struct avtab_node *node, const avtab_key_t *key) |
156 | 0 | { |
157 | 0 | return node->key.source_type == key->source_type |
158 | 0 | && node->key.target_type == key->target_type |
159 | 0 | && node->key.target_class == key->target_class; |
160 | 0 | } |
161 | | |
162 | | /* Same scenarios of interest as check_assertion_extended_permissions */ |
163 | | static int report_assertion_extended_permissions(sepol_handle_t *handle, |
164 | | policydb_t *p, const avrule_t *narule, |
165 | | unsigned int stype, unsigned int ttype, |
166 | | const class_perm_node_t *curperm, uint32_t perms, |
167 | | const avtab_key_t *k, bool conditional) |
168 | 0 | { |
169 | 0 | avtab_ptr_t node; |
170 | 0 | avtab_key_t tmp_key; |
171 | 0 | avtab_extended_perms_t *xperms; |
172 | 0 | avtab_extended_perms_t error; |
173 | 0 | const ebitmap_t *sattr = &p->type_attr_map[stype]; |
174 | 0 | const ebitmap_t *tattr = &p->type_attr_map[ttype]; |
175 | 0 | ebitmap_node_t *snode, *tnode; |
176 | 0 | unsigned int i, j; |
177 | 0 | bool found_xperm = false, found_cond_conflict = false; |
178 | 0 | int errors = 0; |
179 | |
|
180 | 0 | memcpy(&tmp_key, k, sizeof(avtab_key_t)); |
181 | 0 | tmp_key.specified = AVTAB_XPERMS_ALLOWED; |
182 | |
|
183 | 0 | ebitmap_for_each_positive_bit(sattr, snode, i) { |
184 | 0 | tmp_key.source_type = i + 1; |
185 | 0 | ebitmap_for_each_positive_bit(tattr, tnode, j) { |
186 | 0 | tmp_key.target_type = j + 1; |
187 | 0 | for (node = avtab_search_node(&p->te_avtab, &tmp_key); |
188 | 0 | node; |
189 | 0 | node = avtab_search_node_next(node, tmp_key.specified)) { |
190 | 0 | xperms = node->datum.xperms; |
191 | 0 | if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) |
192 | 0 | && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) |
193 | 0 | && (xperms->specified != AVTAB_XPERMS_NLMSG)) |
194 | 0 | continue; |
195 | 0 | found_xperm = true; |
196 | | /* failure on the extended permission check_extended_permissions */ |
197 | 0 | if (check_extended_permissions(narule->xperms, xperms)) { |
198 | 0 | char *permstring; |
199 | |
|
200 | 0 | extended_permissions_violated(&error, narule->xperms, xperms); |
201 | 0 | permstring = sepol_extended_perms_to_string(&error); |
202 | |
|
203 | 0 | ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
204 | 0 | " allowxperm %s %s:%s %s;", |
205 | 0 | narule->source_line, narule->source_filename, narule->line, policy_name(p), |
206 | 0 | p->p_type_val_to_name[i], |
207 | 0 | p->p_type_val_to_name[j], |
208 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
209 | 0 | permstring ?: "<format-failure>"); |
210 | |
|
211 | 0 | free(permstring); |
212 | 0 | errors++; |
213 | 0 | } |
214 | 0 | } |
215 | |
|
216 | 0 | for (const cond_list_t *cl = p->cond_list; cl; cl = cl->next) { |
217 | 0 | bool found_true_base = false, found_true_xperm = false; |
218 | 0 | bool found_false_base = false, found_false_xperm = false; |
219 | |
|
220 | 0 | for (const cond_av_list_t *cal = cl->true_list; cal; cal = cal->next) { |
221 | 0 | node = cal->node; /* node->next is not from the same condition */ |
222 | 0 | if (!node) |
223 | 0 | continue; |
224 | | |
225 | 0 | if (!match_node_key(node, &tmp_key)) |
226 | 0 | continue; |
227 | | |
228 | 0 | if (match_any_class_permissions(narule->perms, node->key.target_class, node->datum.data)) { |
229 | 0 | found_true_base = true; |
230 | 0 | continue; |
231 | 0 | } |
232 | | |
233 | 0 | if (!(node->key.specified & AVTAB_XPERMS_ALLOWED)) |
234 | 0 | continue; |
235 | | |
236 | 0 | xperms = node->datum.xperms; |
237 | 0 | if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) |
238 | 0 | && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) |
239 | 0 | && (xperms->specified != AVTAB_XPERMS_NLMSG)) |
240 | 0 | continue; |
241 | 0 | found_true_xperm = true; |
242 | | /* failure on the extended permission check_extended_permissions */ |
243 | 0 | if (check_extended_permissions(narule->xperms, xperms)) { |
244 | 0 | char *permstring; |
245 | |
|
246 | 0 | extended_permissions_violated(&error, narule->xperms, xperms); |
247 | 0 | permstring = sepol_extended_perms_to_string(&error); |
248 | |
|
249 | 0 | ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
250 | 0 | " allowxperm %s %s:%s %s;", |
251 | 0 | narule->source_line, narule->source_filename, narule->line, policy_name(p), |
252 | 0 | p->p_type_val_to_name[i], |
253 | 0 | p->p_type_val_to_name[j], |
254 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
255 | 0 | permstring ?: "<format-failure>"); |
256 | |
|
257 | 0 | free(permstring); |
258 | 0 | errors++; |
259 | 0 | } |
260 | 0 | } |
261 | |
|
262 | 0 | for (const cond_av_list_t *cal = cl->false_list; cal; cal = cal->next) { |
263 | 0 | node = cal->node; /* node->next is not from the same condition */ |
264 | 0 | if (!node) |
265 | 0 | continue; |
266 | | |
267 | 0 | if (!match_node_key(node, &tmp_key)) |
268 | 0 | continue; |
269 | | |
270 | 0 | if (match_any_class_permissions(narule->perms, node->key.target_class, node->datum.data)) { |
271 | 0 | found_false_base = true; |
272 | 0 | continue; |
273 | 0 | } |
274 | | |
275 | 0 | if (!(node->key.specified & AVTAB_XPERMS_ALLOWED)) |
276 | 0 | continue; |
277 | | |
278 | 0 | xperms = node->datum.xperms; |
279 | 0 | if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) |
280 | 0 | && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) |
281 | 0 | && (xperms->specified != AVTAB_XPERMS_NLMSG)) |
282 | 0 | continue; |
283 | 0 | found_false_xperm = true; |
284 | | /* failure on the extended permission check_extended_permissions */ |
285 | 0 | if (check_extended_permissions(narule->xperms, xperms)) { |
286 | 0 | char *permstring; |
287 | |
|
288 | 0 | extended_permissions_violated(&error, narule->xperms, xperms); |
289 | 0 | permstring = sepol_extended_perms_to_string(&error); |
290 | |
|
291 | 0 | ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
292 | 0 | " allowxperm %s %s:%s %s;", |
293 | 0 | narule->source_line, narule->source_filename, narule->line, policy_name(p), |
294 | 0 | p->p_type_val_to_name[i], |
295 | 0 | p->p_type_val_to_name[j], |
296 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
297 | 0 | permstring ?: "<format-failure>"); |
298 | |
|
299 | 0 | free(permstring); |
300 | 0 | errors++; |
301 | 0 | } |
302 | 0 | } |
303 | |
|
304 | 0 | if (found_true_xperm && found_false_xperm) |
305 | 0 | found_xperm = true; |
306 | 0 | else if (conditional && ((found_true_base && !found_true_xperm) || (found_false_base && !found_false_xperm))) |
307 | 0 | found_cond_conflict = true; |
308 | 0 | } |
309 | 0 | } |
310 | 0 | } |
311 | |
|
312 | 0 | if ((!found_xperm && !conditional) || found_cond_conflict) { |
313 | | /* failure on the regular permissions */ |
314 | 0 | char *permstr = sepol_av_to_string(p, curperm->tclass, perms); |
315 | |
|
316 | 0 | ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" |
317 | 0 | " allow %s %s:%s {%s };", |
318 | 0 | narule->source_line, narule->source_filename, narule->line, policy_name(p), |
319 | 0 | p->p_type_val_to_name[stype], |
320 | 0 | p->p_type_val_to_name[ttype], |
321 | 0 | p->p_class_val_to_name[curperm->tclass - 1], |
322 | 0 | permstr ?: "<format-failure>"); |
323 | |
|
324 | 0 | free(permstr); |
325 | 0 | errors++; |
326 | 0 | } |
327 | |
|
328 | 0 | return errors; |
329 | 0 | } |
330 | | |
331 | | static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args) |
332 | 0 | { |
333 | 0 | int rc = 0; |
334 | 0 | struct avtab_match_args *a = (struct avtab_match_args *)args; |
335 | 0 | sepol_handle_t *handle = a->handle; |
336 | 0 | policydb_t *p = a->p; |
337 | 0 | const avrule_t *narule = a->narule; |
338 | 0 | const class_perm_node_t *cp; |
339 | 0 | uint32_t perms; |
340 | 0 | ebitmap_t src_matches, tgt_matches, self_matches; |
341 | 0 | ebitmap_node_t *snode, *tnode; |
342 | 0 | unsigned int i, j; |
343 | 0 | const bool is_narule_self = (narule->flags & RULE_SELF) != 0; |
344 | 0 | const bool is_narule_notself = (narule->flags & RULE_NOTSELF) != 0; |
345 | |
|
346 | 0 | if ((k->specified & AVTAB_ALLOWED) == 0) |
347 | 0 | return 0; |
348 | | |
349 | 0 | if (!match_any_class_permissions(narule->perms, k->target_class, d->data)) |
350 | 0 | return 0; |
351 | | |
352 | 0 | ebitmap_init(&src_matches); |
353 | 0 | ebitmap_init(&tgt_matches); |
354 | 0 | ebitmap_init(&self_matches); |
355 | |
|
356 | 0 | rc = ebitmap_and(&src_matches, &narule->stypes.types, |
357 | 0 | &p->attr_type_map[k->source_type - 1]); |
358 | 0 | if (rc < 0) |
359 | 0 | goto oom; |
360 | | |
361 | 0 | if (ebitmap_is_empty(&src_matches)) |
362 | 0 | goto exit; |
363 | | |
364 | 0 | if (is_narule_notself) { |
365 | 0 | if (ebitmap_is_empty(&narule->ttypes.types)) { |
366 | | /* avrule tgt is of the form ~self */ |
367 | 0 | rc = ebitmap_cpy(&tgt_matches, &p->attr_type_map[k->target_type -1]); |
368 | 0 | } else { |
369 | | /* avrule tgt is of the form {ATTR -self} */ |
370 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, &p->attr_type_map[k->target_type - 1]); |
371 | 0 | } |
372 | 0 | if (rc) |
373 | 0 | goto oom; |
374 | 0 | } else { |
375 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, &p->attr_type_map[k->target_type -1]); |
376 | 0 | if (rc < 0) |
377 | 0 | goto oom; |
378 | | |
379 | 0 | if (is_narule_self) { |
380 | 0 | rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]); |
381 | 0 | if (rc < 0) |
382 | 0 | goto oom; |
383 | | |
384 | 0 | if (!ebitmap_is_empty(&self_matches)) { |
385 | 0 | rc = ebitmap_union(&tgt_matches, &self_matches); |
386 | 0 | if (rc < 0) |
387 | 0 | goto oom; |
388 | 0 | } |
389 | 0 | } |
390 | 0 | } |
391 | | |
392 | 0 | if (ebitmap_is_empty(&tgt_matches)) |
393 | 0 | goto exit; |
394 | | |
395 | 0 | for (cp = narule->perms; cp; cp = cp->next) { |
396 | |
|
397 | 0 | perms = cp->data & d->data; |
398 | 0 | if ((cp->tclass != k->target_class) || !perms) { |
399 | 0 | continue; |
400 | 0 | } |
401 | | |
402 | 0 | ebitmap_for_each_positive_bit(&src_matches, snode, i) { |
403 | 0 | ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) { |
404 | 0 | if (is_narule_self && i != j) |
405 | 0 | continue; |
406 | 0 | if (is_narule_notself && i == j) |
407 | 0 | continue; |
408 | 0 | if (narule->specified == AVRULE_XPERMS_NEVERALLOW) { |
409 | 0 | a->errors += report_assertion_extended_permissions(handle,p, narule, |
410 | 0 | i, j, cp, perms, k, |
411 | 0 | a->conditional); |
412 | 0 | } else { |
413 | 0 | a->errors++; |
414 | 0 | report_failure(handle, p, narule, i, j, cp, perms); |
415 | 0 | } |
416 | 0 | } |
417 | 0 | } |
418 | 0 | } |
419 | |
|
420 | 0 | oom: |
421 | 0 | exit: |
422 | 0 | ebitmap_destroy(&src_matches); |
423 | 0 | ebitmap_destroy(&tgt_matches); |
424 | 0 | ebitmap_destroy(&self_matches); |
425 | 0 | return rc; |
426 | 0 | } |
427 | | |
428 | | static int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, const avrule_t *narule) |
429 | 0 | { |
430 | 0 | int rc; |
431 | 0 | struct avtab_match_args args = { |
432 | 0 | .handle = handle, |
433 | 0 | .p = p, |
434 | 0 | .narule = narule, |
435 | 0 | .errors = 0, |
436 | 0 | }; |
437 | |
|
438 | 0 | args.conditional = false; |
439 | 0 | rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args); |
440 | 0 | if (rc < 0) |
441 | 0 | goto oom; |
442 | | |
443 | 0 | args.conditional = true; |
444 | 0 | rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args); |
445 | 0 | if (rc < 0) |
446 | 0 | goto oom; |
447 | | |
448 | 0 | return args.errors; |
449 | | |
450 | 0 | oom: |
451 | 0 | return rc; |
452 | 0 | } |
453 | | |
454 | | /* |
455 | | * Look up the extended permissions in avtab and verify that neverallowed |
456 | | * permissions are not granted. |
457 | | */ |
458 | | static bool check_assertion_extended_permissions_avtab(const avrule_t *narule, |
459 | | unsigned int stype, unsigned int ttype, |
460 | | const avtab_key_t *k, policydb_t *p, |
461 | | bool conditional) |
462 | 0 | { |
463 | 0 | avtab_ptr_t node; |
464 | 0 | avtab_key_t tmp_key; |
465 | 0 | const avtab_extended_perms_t *xperms; |
466 | 0 | const av_extended_perms_t *neverallow_xperms = narule->xperms; |
467 | 0 | const ebitmap_t *sattr = &p->type_attr_map[stype]; |
468 | 0 | const ebitmap_t *tattr = &p->type_attr_map[ttype]; |
469 | 0 | ebitmap_node_t *snode, *tnode; |
470 | 0 | unsigned int i, j; |
471 | 0 | bool found_xperm = false, found_cond_conflict = false; |
472 | |
|
473 | 0 | memcpy(&tmp_key, k, sizeof(avtab_key_t)); |
474 | 0 | tmp_key.specified = AVTAB_XPERMS_ALLOWED; |
475 | |
|
476 | 0 | ebitmap_for_each_positive_bit(sattr, snode, i) { |
477 | 0 | tmp_key.source_type = i + 1; |
478 | 0 | ebitmap_for_each_positive_bit(tattr, tnode, j) { |
479 | 0 | tmp_key.target_type = j + 1; |
480 | 0 | for (node = avtab_search_node(&p->te_avtab, &tmp_key); |
481 | 0 | node; |
482 | 0 | node = avtab_search_node_next(node, tmp_key.specified)) { |
483 | 0 | xperms = node->datum.xperms; |
484 | |
|
485 | 0 | if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) |
486 | 0 | && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) |
487 | 0 | && (xperms->specified != AVTAB_XPERMS_NLMSG)) |
488 | 0 | continue; |
489 | 0 | found_xperm = true; |
490 | 0 | if (check_extended_permissions(neverallow_xperms, xperms)) |
491 | 0 | return true; |
492 | 0 | } |
493 | | |
494 | 0 | for (const cond_list_t *cl = p->cond_list; cl; cl = cl->next) { |
495 | 0 | bool found_true_base = false, found_true_xperm = false; |
496 | 0 | bool found_false_base = false, found_false_xperm = false; |
497 | |
|
498 | 0 | for (const cond_av_list_t *cal = cl->true_list; cal; cal = cal->next) { |
499 | 0 | node = cal->node; /* node->next is not from the same condition */ |
500 | 0 | if (!node) |
501 | 0 | continue; |
502 | | |
503 | 0 | if (!match_node_key(node, &tmp_key)) |
504 | 0 | continue; |
505 | | |
506 | 0 | if ((node->key.specified & AVTAB_ALLOWED) && match_any_class_permissions(narule->perms, node->key.target_class, node->datum.data)) { |
507 | 0 | found_true_base = true; |
508 | 0 | continue; |
509 | 0 | } |
510 | | |
511 | 0 | if (!(node->key.specified & AVTAB_XPERMS_ALLOWED)) |
512 | 0 | continue; |
513 | | |
514 | 0 | xperms = node->datum.xperms; |
515 | |
|
516 | 0 | if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) |
517 | 0 | && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) |
518 | 0 | && (xperms->specified != AVTAB_XPERMS_NLMSG)) |
519 | 0 | continue; |
520 | 0 | found_true_xperm = true; |
521 | 0 | if (check_extended_permissions(neverallow_xperms, xperms)) |
522 | 0 | return true; |
523 | 0 | } |
524 | | |
525 | 0 | for (const cond_av_list_t *cal = cl->false_list; cal; cal = cal->next) { |
526 | 0 | node = cal->node; /* node->next is not from the same condition */ |
527 | 0 | if (!node) |
528 | 0 | continue; |
529 | | |
530 | 0 | if (!match_node_key(node, &tmp_key)) |
531 | 0 | continue; |
532 | | |
533 | 0 | if ((node->key.specified & AVTAB_ALLOWED) && match_any_class_permissions(narule->perms, node->key.target_class, node->datum.data)) { |
534 | 0 | found_false_base = true; |
535 | 0 | continue; |
536 | 0 | } |
537 | | |
538 | 0 | if (!(node->key.specified & AVTAB_XPERMS_ALLOWED)) |
539 | 0 | continue; |
540 | | |
541 | 0 | xperms = node->datum.xperms; |
542 | |
|
543 | 0 | if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) |
544 | 0 | && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER) |
545 | 0 | && (xperms->specified != AVTAB_XPERMS_NLMSG)) |
546 | 0 | continue; |
547 | 0 | found_false_xperm = true; |
548 | 0 | if (check_extended_permissions(neverallow_xperms, xperms)) |
549 | 0 | return true; |
550 | 0 | } |
551 | | |
552 | 0 | if (found_true_xperm && found_false_xperm) |
553 | 0 | found_xperm = true; |
554 | 0 | else if (conditional && ((found_true_base && !found_true_xperm) || (found_false_base && !found_false_xperm))) |
555 | 0 | found_cond_conflict = true; |
556 | 0 | } |
557 | 0 | } |
558 | 0 | } |
559 | | |
560 | 0 | return (!conditional && !found_xperm) || found_cond_conflict; |
561 | 0 | } |
562 | | |
563 | | /* |
564 | | * When the ioctl permission is granted on an avtab entry that matches an |
565 | | * avrule neverallowxperm entry, enumerate over the matching |
566 | | * source/target/class sets to determine if the extended permissions exist |
567 | | * and if the neverallowed ioctls are granted. |
568 | | * |
569 | | * Four scenarios of interest: |
570 | | * 1. PASS - the ioctl permission is not granted for this source/target/class |
571 | | * This case is handled in check_assertion_avtab_match |
572 | | * 2. PASS - The ioctl permission is granted AND the extended permission |
573 | | * is NOT granted |
574 | | * 3. FAIL - The ioctl permission is granted AND no extended permissions |
575 | | * exist |
576 | | * 4. FAIL - The ioctl permission is granted AND the extended permission is |
577 | | * granted |
578 | | */ |
579 | | static int check_assertion_extended_permissions(const avrule_t *narule, |
580 | | const avtab_key_t *k, policydb_t *p, |
581 | | bool conditional) |
582 | 0 | { |
583 | 0 | ebitmap_t src_matches, tgt_matches, self_matches; |
584 | 0 | unsigned int i, j; |
585 | 0 | ebitmap_node_t *snode, *tnode; |
586 | 0 | const bool is_narule_self = (narule->flags & RULE_SELF) != 0; |
587 | 0 | const bool is_narule_notself = (narule->flags & RULE_NOTSELF) != 0; |
588 | 0 | int rc; |
589 | |
|
590 | 0 | ebitmap_init(&src_matches); |
591 | 0 | ebitmap_init(&tgt_matches); |
592 | 0 | ebitmap_init(&self_matches); |
593 | |
|
594 | 0 | rc = ebitmap_and(&src_matches, &narule->stypes.types, |
595 | 0 | &p->attr_type_map[k->source_type - 1]); |
596 | 0 | if (rc < 0) |
597 | 0 | goto oom; |
598 | | |
599 | 0 | if (ebitmap_is_empty(&src_matches)) { |
600 | 0 | rc = 0; |
601 | 0 | goto exit; |
602 | 0 | } |
603 | | |
604 | 0 | if (is_narule_notself) { |
605 | 0 | if (ebitmap_is_empty(&narule->ttypes.types)) { |
606 | | /* avrule tgt is of the form ~self */ |
607 | 0 | rc = ebitmap_cpy(&tgt_matches, &p->attr_type_map[k->target_type -1]); |
608 | 0 | } else { |
609 | | /* avrule tgt is of the form {ATTR -self} */ |
610 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, &p->attr_type_map[k->target_type - 1]); |
611 | 0 | } |
612 | 0 | if (rc < 0) |
613 | 0 | goto oom; |
614 | 0 | } else { |
615 | 0 | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, &p->attr_type_map[k->target_type -1]); |
616 | 0 | if (rc < 0) |
617 | 0 | goto oom; |
618 | | |
619 | 0 | if (is_narule_self) { |
620 | 0 | rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]); |
621 | 0 | if (rc < 0) |
622 | 0 | goto oom; |
623 | | |
624 | 0 | if (!ebitmap_is_empty(&self_matches)) { |
625 | 0 | rc = ebitmap_union(&tgt_matches, &self_matches); |
626 | 0 | if (rc < 0) |
627 | 0 | goto oom; |
628 | 0 | } |
629 | 0 | } |
630 | 0 | } |
631 | | |
632 | 0 | if (ebitmap_is_empty(&tgt_matches)) { |
633 | 0 | rc = 0; |
634 | 0 | goto exit; |
635 | 0 | } |
636 | | |
637 | 0 | ebitmap_for_each_positive_bit(&src_matches, snode, i) { |
638 | 0 | ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) { |
639 | 0 | if (is_narule_self && i != j) |
640 | 0 | continue; |
641 | 0 | if (is_narule_notself && i == j) |
642 | 0 | continue; |
643 | 0 | if (check_assertion_extended_permissions_avtab(narule, i, j, k, p, conditional)) { |
644 | 0 | rc = 1; |
645 | 0 | goto exit; |
646 | 0 | } |
647 | 0 | } |
648 | 0 | } |
649 | | |
650 | 0 | rc = 0; |
651 | |
|
652 | 0 | oom: |
653 | 0 | exit: |
654 | 0 | ebitmap_destroy(&src_matches); |
655 | 0 | ebitmap_destroy(&tgt_matches); |
656 | 0 | ebitmap_destroy(&self_matches); |
657 | 0 | return rc; |
658 | 0 | } |
659 | | |
660 | | static int check_assertion_notself_match(const avtab_key_t *k, const avrule_t *narule, policydb_t *p) |
661 | 24.3k | { |
662 | 24.3k | ebitmap_t src_matches, tgt_matches; |
663 | 24.3k | unsigned int num_src_matches, num_tgt_matches; |
664 | 24.3k | int rc; |
665 | | |
666 | 24.3k | ebitmap_init(&src_matches); |
667 | 24.3k | ebitmap_init(&tgt_matches); |
668 | | |
669 | 24.3k | rc = ebitmap_and(&src_matches, &narule->stypes.types, &p->attr_type_map[k->source_type - 1]); |
670 | 24.3k | if (rc < 0) |
671 | 0 | goto oom; |
672 | | |
673 | 24.3k | if (ebitmap_is_empty(&narule->ttypes.types)) { |
674 | | /* avrule tgt is of the form ~self */ |
675 | 4.49k | rc = ebitmap_cpy(&tgt_matches, &p->attr_type_map[k->target_type - 1]); |
676 | 19.8k | } else { |
677 | | /* avrule tgt is of the form {ATTR -self} */ |
678 | 19.8k | rc = ebitmap_and(&tgt_matches, &narule->ttypes.types, &p->attr_type_map[k->target_type - 1]); |
679 | 19.8k | } |
680 | 24.3k | if (rc < 0) |
681 | 0 | goto oom; |
682 | | |
683 | 24.3k | num_src_matches = ebitmap_cardinality(&src_matches); |
684 | 24.3k | num_tgt_matches = ebitmap_cardinality(&tgt_matches); |
685 | 24.3k | if (num_src_matches == 0 || num_tgt_matches == 0) { |
686 | 17.3k | rc = 0; |
687 | 17.3k | goto nomatch; |
688 | 17.3k | } |
689 | 7.00k | if (num_src_matches == 1 && num_tgt_matches == 1) { |
690 | 4.73k | ebitmap_t matches; |
691 | 4.73k | unsigned int num_matches; |
692 | 4.73k | rc = ebitmap_and(&matches, &src_matches, &tgt_matches); |
693 | 4.73k | if (rc < 0) { |
694 | 0 | ebitmap_destroy(&matches); |
695 | 0 | goto oom; |
696 | 0 | } |
697 | 4.73k | num_matches = ebitmap_cardinality(&matches); |
698 | 4.73k | ebitmap_destroy(&matches); |
699 | 4.73k | if (num_matches == 1) { |
700 | | /* The only non-match is of the form TYPE TYPE */ |
701 | 1.11k | rc = 0; |
702 | 1.11k | goto nomatch; |
703 | 1.11k | } |
704 | 4.73k | } |
705 | | |
706 | 5.88k | rc = 1; |
707 | | |
708 | 5.88k | oom: |
709 | 24.3k | nomatch: |
710 | 24.3k | ebitmap_destroy(&src_matches); |
711 | 24.3k | ebitmap_destroy(&tgt_matches); |
712 | 24.3k | return rc; |
713 | 5.88k | } |
714 | | |
715 | | static int check_assertion_self_match(const avtab_key_t *k, const avrule_t *narule, policydb_t *p) |
716 | 3.66k | { |
717 | 3.66k | ebitmap_t src_matches; |
718 | 3.66k | int rc; |
719 | | |
720 | | /* The key's target must match something in the matches of the avrule's source |
721 | | * and the key's source. |
722 | | */ |
723 | | |
724 | 3.66k | rc = ebitmap_and(&src_matches, &narule->stypes.types, &p->attr_type_map[k->source_type - 1]); |
725 | 3.66k | if (rc < 0) |
726 | 0 | goto oom; |
727 | | |
728 | 3.66k | if (!ebitmap_match_any(&src_matches, &p->attr_type_map[k->target_type - 1])) { |
729 | 2.00k | rc = 0; |
730 | 2.00k | goto nomatch; |
731 | 2.00k | } |
732 | | |
733 | 1.66k | rc = 1; |
734 | | |
735 | 1.66k | oom: |
736 | 3.66k | nomatch: |
737 | 3.66k | ebitmap_destroy(&src_matches); |
738 | 3.66k | return rc; |
739 | 1.66k | } |
740 | | |
741 | | static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args) |
742 | 28.3M | { |
743 | 28.3M | int rc; |
744 | 28.3M | struct avtab_match_args *a = (struct avtab_match_args *)args; |
745 | 28.3M | policydb_t *p = a->p; |
746 | 28.3M | const avrule_t *narule = a->narule; |
747 | | |
748 | 28.3M | if ((k->specified & AVTAB_ALLOWED) == 0) |
749 | 643k | goto nomatch; |
750 | | |
751 | 27.6M | if (!match_any_class_permissions(narule->perms, k->target_class, d->data)) |
752 | 21.3M | goto nomatch; |
753 | | |
754 | 6.28M | if (!ebitmap_match_any(&narule->stypes.types, &p->attr_type_map[k->source_type - 1])) |
755 | 5.97M | goto nomatch; |
756 | | |
757 | 313k | if (narule->flags & RULE_NOTSELF) { |
758 | 24.3k | rc = check_assertion_notself_match(k, narule, p); |
759 | 24.3k | if (rc < 0) |
760 | 0 | goto oom; |
761 | 24.3k | if (rc == 0) |
762 | 18.4k | goto nomatch; |
763 | 288k | } else { |
764 | | /* neverallow may have tgts even if it uses SELF */ |
765 | 288k | if (!ebitmap_match_any(&narule->ttypes.types, &p->attr_type_map[k->target_type -1])) { |
766 | 283k | if (narule->flags == RULE_SELF) { |
767 | 3.66k | rc = check_assertion_self_match(k, narule, p); |
768 | 3.66k | if (rc < 0) |
769 | 0 | goto oom; |
770 | 3.66k | if (rc == 0) |
771 | 2.00k | goto nomatch; |
772 | 280k | } else { |
773 | 280k | goto nomatch; |
774 | 280k | } |
775 | 283k | } |
776 | 288k | } |
777 | | |
778 | 12.5k | if (narule->specified == AVRULE_XPERMS_NEVERALLOW) { |
779 | 0 | rc = check_assertion_extended_permissions(narule, k, p, a->conditional); |
780 | 0 | if (rc < 0) |
781 | 0 | goto oom; |
782 | 0 | if (rc == 0) |
783 | 0 | goto nomatch; |
784 | 0 | } |
785 | 12.5k | return 1; |
786 | | |
787 | 28.3M | nomatch: |
788 | 28.3M | return 0; |
789 | | |
790 | 0 | oom: |
791 | 0 | return rc; |
792 | 12.5k | } |
793 | | |
794 | | int check_assertion(policydb_t *p, const avrule_t *narule) |
795 | 33.2k | { |
796 | 33.2k | int rc; |
797 | 33.2k | struct avtab_match_args args = { |
798 | 33.2k | .handle = NULL, |
799 | 33.2k | .p = p, |
800 | 33.2k | .narule = narule, |
801 | 33.2k | .errors = 0, |
802 | 33.2k | }; |
803 | | |
804 | 33.2k | args.conditional = false; |
805 | 33.2k | rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args); |
806 | | |
807 | 33.2k | if (rc == 0) { |
808 | 20.6k | args.conditional = true; |
809 | 20.6k | rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, &args); |
810 | 20.6k | } |
811 | | |
812 | 33.2k | return rc; |
813 | 33.2k | } |
814 | | |
815 | | int check_assertions(sepol_handle_t * handle, policydb_t * p, |
816 | | const avrule_t * narules) |
817 | 2.26k | { |
818 | 2.26k | int rc; |
819 | 2.26k | const avrule_t *a; |
820 | 2.26k | unsigned long errors = 0; |
821 | | |
822 | 2.26k | for (a = narules; a != NULL; a = a->next) { |
823 | 6 | if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW))) |
824 | 5 | continue; |
825 | 1 | rc = check_assertion(p, a); |
826 | 1 | if (rc < 0) { |
827 | 0 | ERR(handle, "Error occurred while checking neverallows"); |
828 | 0 | return -1; |
829 | 0 | } |
830 | 1 | if (rc) { |
831 | 0 | rc = report_assertion_failures(handle, p, a); |
832 | 0 | if (rc < 0) { |
833 | 0 | ERR(handle, "Error occurred while checking neverallows"); |
834 | 0 | return -1; |
835 | 0 | } |
836 | 0 | errors += rc; |
837 | 0 | } |
838 | 1 | } |
839 | | |
840 | 2.26k | if (errors) |
841 | 2.26k | ERR(handle, "%lu neverallow failures occurred", errors); |
842 | | |
843 | 2.26k | return errors ? -1 : 0; |
844 | 2.26k | } |