diff options
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r-- | security/selinux/ss/services.c | 180 |
1 files changed, 175 insertions, 5 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 8551952ef329..ab0cc0c7b944 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -88,6 +88,11 @@ static u32 latest_granting; | |||
88 | static int context_struct_to_string(struct context *context, char **scontext, | 88 | static int context_struct_to_string(struct context *context, char **scontext, |
89 | u32 *scontext_len); | 89 | u32 *scontext_len); |
90 | 90 | ||
91 | static int context_struct_compute_av(struct context *scontext, | ||
92 | struct context *tcontext, | ||
93 | u16 tclass, | ||
94 | u32 requested, | ||
95 | struct av_decision *avd); | ||
91 | /* | 96 | /* |
92 | * Return the boolean value of a constraint expression | 97 | * Return the boolean value of a constraint expression |
93 | * when it is applied to the specified source and target | 98 | * when it is applied to the specified source and target |
@@ -274,6 +279,100 @@ mls_ops: | |||
274 | } | 279 | } |
275 | 280 | ||
276 | /* | 281 | /* |
282 | * security_boundary_permission - drops violated permissions | ||
283 | * on boundary constraint. | ||
284 | */ | ||
285 | static void type_attribute_bounds_av(struct context *scontext, | ||
286 | struct context *tcontext, | ||
287 | u16 tclass, | ||
288 | u32 requested, | ||
289 | struct av_decision *avd) | ||
290 | { | ||
291 | struct context lo_scontext; | ||
292 | struct context lo_tcontext; | ||
293 | struct av_decision lo_avd; | ||
294 | struct type_datum *source | ||
295 | = policydb.type_val_to_struct[scontext->type - 1]; | ||
296 | struct type_datum *target | ||
297 | = policydb.type_val_to_struct[tcontext->type - 1]; | ||
298 | u32 masked = 0; | ||
299 | |||
300 | if (source->bounds) { | ||
301 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
302 | |||
303 | memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); | ||
304 | lo_scontext.type = source->bounds; | ||
305 | |||
306 | context_struct_compute_av(&lo_scontext, | ||
307 | tcontext, | ||
308 | tclass, | ||
309 | requested, | ||
310 | &lo_avd); | ||
311 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
312 | return; /* no masked permission */ | ||
313 | masked = ~lo_avd.allowed & avd->allowed; | ||
314 | } | ||
315 | |||
316 | if (target->bounds) { | ||
317 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
318 | |||
319 | memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); | ||
320 | lo_tcontext.type = target->bounds; | ||
321 | |||
322 | context_struct_compute_av(scontext, | ||
323 | &lo_tcontext, | ||
324 | tclass, | ||
325 | requested, | ||
326 | &lo_avd); | ||
327 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
328 | return; /* no masked permission */ | ||
329 | masked = ~lo_avd.allowed & avd->allowed; | ||
330 | } | ||
331 | |||
332 | if (source->bounds && target->bounds) { | ||
333 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
334 | /* | ||
335 | * lo_scontext and lo_tcontext are already | ||
336 | * set up. | ||
337 | */ | ||
338 | |||
339 | context_struct_compute_av(&lo_scontext, | ||
340 | &lo_tcontext, | ||
341 | tclass, | ||
342 | requested, | ||
343 | &lo_avd); | ||
344 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
345 | return; /* no masked permission */ | ||
346 | masked = ~lo_avd.allowed & avd->allowed; | ||
347 | } | ||
348 | |||
349 | if (masked) { | ||
350 | struct audit_buffer *ab; | ||
351 | char *stype_name | ||
352 | = policydb.p_type_val_to_name[source->value - 1]; | ||
353 | char *ttype_name | ||
354 | = policydb.p_type_val_to_name[target->value - 1]; | ||
355 | char *tclass_name | ||
356 | = policydb.p_class_val_to_name[tclass - 1]; | ||
357 | |||
358 | /* mask violated permissions */ | ||
359 | avd->allowed &= ~masked; | ||
360 | |||
361 | /* notice to userspace via audit message */ | ||
362 | ab = audit_log_start(current->audit_context, | ||
363 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
364 | if (!ab) | ||
365 | return; | ||
366 | |||
367 | audit_log_format(ab, "av boundary violation: " | ||
368 | "source=%s target=%s tclass=%s", | ||
369 | stype_name, ttype_name, tclass_name); | ||
370 | avc_dump_av(ab, tclass, masked); | ||
371 | audit_log_end(ab); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | /* | ||
277 | * Compute access vectors based on a context structure pair for | 376 | * Compute access vectors based on a context structure pair for |
278 | * the permissions in a particular class. | 377 | * the permissions in a particular class. |
279 | */ | 378 | */ |
@@ -356,7 +455,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
356 | avkey.source_type = i + 1; | 455 | avkey.source_type = i + 1; |
357 | avkey.target_type = j + 1; | 456 | avkey.target_type = j + 1; |
358 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); | 457 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); |
359 | node != NULL; | 458 | node; |
360 | node = avtab_search_node_next(node, avkey.specified)) { | 459 | node = avtab_search_node_next(node, avkey.specified)) { |
361 | if (node->key.specified == AVTAB_ALLOWED) | 460 | if (node->key.specified == AVTAB_ALLOWED) |
362 | avd->allowed |= node->datum.data; | 461 | avd->allowed |= node->datum.data; |
@@ -404,6 +503,14 @@ static int context_struct_compute_av(struct context *scontext, | |||
404 | PROCESS__DYNTRANSITION); | 503 | PROCESS__DYNTRANSITION); |
405 | } | 504 | } |
406 | 505 | ||
506 | /* | ||
507 | * If the given source and target types have boundary | ||
508 | * constraint, lazy checks have to mask any violated | ||
509 | * permission and notice it to userspace via audit. | ||
510 | */ | ||
511 | type_attribute_bounds_av(scontext, tcontext, | ||
512 | tclass, requested, avd); | ||
513 | |||
407 | return 0; | 514 | return 0; |
408 | 515 | ||
409 | inval_class: | 516 | inval_class: |
@@ -549,6 +656,69 @@ out: | |||
549 | return rc; | 656 | return rc; |
550 | } | 657 | } |
551 | 658 | ||
659 | /* | ||
660 | * security_bounded_transition - check whether the given | ||
661 | * transition is directed to bounded, or not. | ||
662 | * It returns 0, if @newsid is bounded by @oldsid. | ||
663 | * Otherwise, it returns error code. | ||
664 | * | ||
665 | * @oldsid : current security identifier | ||
666 | * @newsid : destinated security identifier | ||
667 | */ | ||
668 | int security_bounded_transition(u32 old_sid, u32 new_sid) | ||
669 | { | ||
670 | struct context *old_context, *new_context; | ||
671 | struct type_datum *type; | ||
672 | int index; | ||
673 | int rc = -EINVAL; | ||
674 | |||
675 | read_lock(&policy_rwlock); | ||
676 | |||
677 | old_context = sidtab_search(&sidtab, old_sid); | ||
678 | if (!old_context) { | ||
679 | printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", | ||
680 | __func__, old_sid); | ||
681 | goto out; | ||
682 | } | ||
683 | |||
684 | new_context = sidtab_search(&sidtab, new_sid); | ||
685 | if (!new_context) { | ||
686 | printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", | ||
687 | __func__, new_sid); | ||
688 | goto out; | ||
689 | } | ||
690 | |||
691 | /* type/domain unchaned */ | ||
692 | if (old_context->type == new_context->type) { | ||
693 | rc = 0; | ||
694 | goto out; | ||
695 | } | ||
696 | |||
697 | index = new_context->type; | ||
698 | while (true) { | ||
699 | type = policydb.type_val_to_struct[index - 1]; | ||
700 | BUG_ON(!type); | ||
701 | |||
702 | /* not bounded anymore */ | ||
703 | if (!type->bounds) { | ||
704 | rc = -EPERM; | ||
705 | break; | ||
706 | } | ||
707 | |||
708 | /* @newsid is bounded by @oldsid */ | ||
709 | if (type->bounds == old_context->type) { | ||
710 | rc = 0; | ||
711 | break; | ||
712 | } | ||
713 | index = type->bounds; | ||
714 | } | ||
715 | out: | ||
716 | read_unlock(&policy_rwlock); | ||
717 | |||
718 | return rc; | ||
719 | } | ||
720 | |||
721 | |||
552 | /** | 722 | /** |
553 | * security_compute_av - Compute access vector decisions. | 723 | * security_compute_av - Compute access vector decisions. |
554 | * @ssid: source security identifier | 724 | * @ssid: source security identifier |
@@ -794,7 +964,7 @@ static int string_to_context_struct(struct policydb *pol, | |||
794 | *p++ = 0; | 964 | *p++ = 0; |
795 | 965 | ||
796 | typdatum = hashtab_search(pol->p_types.table, scontextp); | 966 | typdatum = hashtab_search(pol->p_types.table, scontextp); |
797 | if (!typdatum) | 967 | if (!typdatum || typdatum->attribute) |
798 | goto out; | 968 | goto out; |
799 | 969 | ||
800 | ctx->type = typdatum->value; | 970 | ctx->type = typdatum->value; |
@@ -1037,7 +1207,7 @@ static int security_compute_sid(u32 ssid, | |||
1037 | /* If no permanent rule, also check for enabled conditional rules */ | 1207 | /* If no permanent rule, also check for enabled conditional rules */ |
1038 | if (!avdatum) { | 1208 | if (!avdatum) { |
1039 | node = avtab_search_node(&policydb.te_cond_avtab, &avkey); | 1209 | node = avtab_search_node(&policydb.te_cond_avtab, &avkey); |
1040 | for (; node != NULL; node = avtab_search_node_next(node, specified)) { | 1210 | for (; node; node = avtab_search_node_next(node, specified)) { |
1041 | if (node->key.specified & AVTAB_ENABLED) { | 1211 | if (node->key.specified & AVTAB_ENABLED) { |
1042 | avdatum = &node->datum; | 1212 | avdatum = &node->datum; |
1043 | break; | 1213 | break; |
@@ -2050,7 +2220,7 @@ int security_set_bools(int len, int *values) | |||
2050 | policydb.bool_val_to_struct[i]->state = 0; | 2220 | policydb.bool_val_to_struct[i]->state = 0; |
2051 | } | 2221 | } |
2052 | 2222 | ||
2053 | for (cur = policydb.cond_list; cur != NULL; cur = cur->next) { | 2223 | for (cur = policydb.cond_list; cur; cur = cur->next) { |
2054 | rc = evaluate_cond_node(&policydb, cur); | 2224 | rc = evaluate_cond_node(&policydb, cur); |
2055 | if (rc) | 2225 | if (rc) |
2056 | goto out; | 2226 | goto out; |
@@ -2102,7 +2272,7 @@ static int security_preserve_bools(struct policydb *p) | |||
2102 | if (booldatum) | 2272 | if (booldatum) |
2103 | booldatum->state = bvalues[i]; | 2273 | booldatum->state = bvalues[i]; |
2104 | } | 2274 | } |
2105 | for (cur = p->cond_list; cur != NULL; cur = cur->next) { | 2275 | for (cur = p->cond_list; cur; cur = cur->next) { |
2106 | rc = evaluate_cond_node(p, cur); | 2276 | rc = evaluate_cond_node(p, cur); |
2107 | if (rc) | 2277 | if (rc) |
2108 | goto out; | 2278 | goto out; |