diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2019-02-25 10:49:02 -0500 |
---|---|---|
committer | Petr Lautrbach <plautrba@redhat.com> | 2019-03-01 12:51:31 +0100 |
commit | c19395d72295f5e69275d98df5db22dfdf214b6c (patch) | |
tree | ea2410795ff7827e9b20f1005876d03b0226a01f /libselinux/src/mapping.c | |
parent | 478c745d82d7c8bb4b15209408335a97891dc4ae (diff) | |
download | android_external_selinux-c19395d72295f5e69275d98df5db22dfdf214b6c.tar.gz android_external_selinux-c19395d72295f5e69275d98df5db22dfdf214b6c.tar.bz2 android_external_selinux-c19395d72295f5e69275d98df5db22dfdf214b6c.zip |
libselinux: selinux_set_mapping: fix handling of unknown classes/perms
The libselinux selinux_set_mapping() implementation was never updated
to handle unknown classes/permissions based on the policy handle_unknown
flag. Update it and the internal mapping functions to gracefully
handle unknown classes/permissions. Add a security_reject_unknown()
interface to expose the corresponding selinuxfs node and use it when
creating a mapping to decide whether to fail immediately or proceed.
This enables dbus-daemon and XSELinux, which use selinux_set_mapping(),
to continue working with the dummy policy or other policies that lack
their userspace class/permission definitions as long as the policy
was built with -U allow.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Diffstat (limited to 'libselinux/src/mapping.c')
-rw-r--r-- | libselinux/src/mapping.c | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/libselinux/src/mapping.c b/libselinux/src/mapping.c index f205804b..33cea5ae 100644 --- a/libselinux/src/mapping.c +++ b/libselinux/src/mapping.c @@ -6,9 +6,12 @@ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> +#include <stdbool.h> #include <selinux/selinux.h> #include <selinux/avc.h> +#include "callbacks.h" #include "mapping.h" +#include "selinux_internal.h" /* * Class and permission mappings @@ -33,6 +36,9 @@ selinux_set_mapping(struct security_class_mapping *map) size_t size = sizeof(struct selinux_mapping); security_class_t i, j; unsigned k; + bool print_unknown_handle = false; + bool reject = (security_reject_unknown() == 1); + bool deny = (security_deny_unknown() == 1); free(current_mapping); current_mapping = NULL; @@ -62,8 +68,16 @@ selinux_set_mapping(struct security_class_mapping *map) struct selinux_mapping *p_out = current_mapping + j; p_out->value = string_to_security_class(p_in->name); - if (!p_out->value) - goto err2; + if (!p_out->value) { + selinux_log(SELINUX_INFO, + "SELinux: Class %s not defined in policy.\n", + p_in->name); + if (reject) + goto err2; + p_out->num_perms = 0; + print_unknown_handle = true; + continue; + } k = 0; while (p_in->perms[k]) { @@ -74,13 +88,24 @@ selinux_set_mapping(struct security_class_mapping *map) } p_out->perms[k] = string_to_av_perm(p_out->value, p_in->perms[k]); - if (!p_out->perms[k]) - goto err2; + if (!p_out->perms[k]) { + selinux_log(SELINUX_INFO, + "SELinux: Permission %s in class %s not defined in policy.\n", + p_in->perms[k], p_in->name); + if (reject) + goto err2; + print_unknown_handle = true; + } k++; } p_out->num_perms = k; } + if (print_unknown_handle) + selinux_log(SELINUX_INFO, + "SELinux: the above unknown classes and permissions will be %s\n", + deny ? "denied" : "allowed"); + /* Set the mapping size here so the above lookups are "raw" */ current_mapping_size = i; return 0; @@ -184,27 +209,46 @@ void map_decision(security_class_t tclass, struct av_decision *avd) { if (tclass < current_mapping_size) { - unsigned i; + bool allow_unknown = (security_deny_unknown() == 0); + struct selinux_mapping *mapping = ¤t_mapping[tclass]; + unsigned int i, n = mapping->num_perms; access_vector_t result; - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->allowed & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) { + if (avd->allowed & mapping->perms[i]) + result |= 1<<i; + else if (allow_unknown && !mapping->perms[i]) result |= 1<<i; + } avd->allowed = result; - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->decided & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) { + if (avd->decided & mapping->perms[i]) + result |= 1<<i; + else if (allow_unknown && !mapping->perms[i]) result |= 1<<i; + } avd->decided = result; - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->auditallow & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) + if (avd->auditallow & mapping->perms[i]) result |= 1<<i; avd->auditallow = result; - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->auditdeny & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) { + if (avd->auditdeny & mapping->perms[i]) result |= 1<<i; + else if (!allow_unknown && !mapping->perms[i]) + result |= 1<<i; + } + + /* + * Make sure we audit denials for any permission check + * beyond the mapping->num_perms since this indicates + * a bug in the object manager. + */ + for (; i < (sizeof(result)*8); i++) + result |= 1<<i; avd->auditdeny = result; } } |