| /* |
| * Class and permission mappings. |
| */ |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <selinux/selinux.h> |
| #include <selinux/avc.h> |
| #include "mapping.h" |
| |
| /* |
| * Class and permission mappings |
| */ |
| |
| struct selinux_mapping { |
| security_class_t value; /* real, kernel value */ |
| unsigned num_perms; |
| access_vector_t perms[sizeof(access_vector_t) * 8]; |
| }; |
| |
| static struct selinux_mapping *current_mapping = NULL; |
| static security_class_t current_mapping_size = 0; |
| |
| /* |
| * Mapping setting function |
| */ |
| |
| int |
| selinux_set_mapping(struct security_class_mapping *map) |
| { |
| size_t size = sizeof(struct selinux_mapping); |
| security_class_t i, j; |
| unsigned k; |
| |
| free(current_mapping); |
| current_mapping = NULL; |
| current_mapping_size = 0; |
| |
| if (avc_reset() < 0) |
| goto err; |
| |
| /* Find number of classes in the input mapping */ |
| if (!map) { |
| errno = EINVAL; |
| goto err; |
| } |
| i = 0; |
| while (map[i].name) |
| i++; |
| |
| /* Allocate space for the class records, plus one for class zero */ |
| current_mapping = (struct selinux_mapping *)calloc(++i, size); |
| if (!current_mapping) |
| goto err; |
| |
| /* Store the raw class and permission values */ |
| j = 0; |
| while (map[j].name) { |
| struct security_class_mapping *p_in = map + (j++); |
| struct selinux_mapping *p_out = current_mapping + j; |
| |
| p_out->value = string_to_security_class(p_in->name); |
| if (!p_out->value) |
| goto err2; |
| |
| k = 0; |
| while (p_in->perms && p_in->perms[k]) { |
| /* An empty permission string skips ahead */ |
| if (!*p_in->perms[k]) { |
| k++; |
| continue; |
| } |
| p_out->perms[k] = string_to_av_perm(p_out->value, |
| p_in->perms[k]); |
| if (!p_out->perms[k]) |
| goto err2; |
| k++; |
| } |
| p_out->num_perms = k; |
| } |
| |
| /* Set the mapping size here so the above lookups are "raw" */ |
| current_mapping_size = i; |
| return 0; |
| err2: |
| free(current_mapping); |
| current_mapping = NULL; |
| current_mapping_size = 0; |
| err: |
| return -1; |
| } |
| |
| /* |
| * Get real, kernel values from mapped values |
| */ |
| |
| security_class_t |
| unmap_class(security_class_t tclass) |
| { |
| if (tclass < current_mapping_size) |
| return current_mapping[tclass].value; |
| |
| /* If here no mapping set or the class requested is not valid. */ |
| if (current_mapping_size != 0) { |
| errno = EINVAL; |
| return 0; |
| } |
| else |
| return tclass; |
| } |
| |
| access_vector_t |
| unmap_perm(security_class_t tclass, access_vector_t tperm) |
| { |
| if (tclass < current_mapping_size) { |
| unsigned i; |
| access_vector_t kperm = 0; |
| |
| for (i=0; i<current_mapping[tclass].num_perms; i++) |
| if (tperm & (1<<i)) { |
| kperm |= current_mapping[tclass].perms[i]; |
| tperm &= ~(1<<i); |
| } |
| return kperm; |
| } |
| |
| /* If here no mapping set or the perm requested is not valid. */ |
| if (current_mapping_size != 0) { |
| errno = EINVAL; |
| return 0; |
| } |
| else |
| return tperm; |
| } |
| |
| /* |
| * Get mapped values from real, kernel values |
| */ |
| |
| security_class_t |
| map_class(security_class_t kclass) |
| { |
| security_class_t i; |
| |
| for (i=0; i<current_mapping_size; i++) |
| if (current_mapping[i].value == kclass) |
| return i; |
| |
| /* If here no mapping set or the class requested is not valid. */ |
| if (current_mapping_size != 0) { |
| errno = EINVAL; |
| return 0; |
| } |
| else |
| return kclass; |
| } |
| |
| access_vector_t |
| map_perm(security_class_t tclass, access_vector_t kperm) |
| { |
| if (tclass < current_mapping_size) { |
| unsigned i; |
| access_vector_t tperm = 0; |
| |
| for (i=0; i<current_mapping[tclass].num_perms; i++) |
| if (kperm & current_mapping[tclass].perms[i]) { |
| tperm |= 1<<i; |
| kperm &= ~current_mapping[tclass].perms[i]; |
| } |
| |
| if (tperm == 0) { |
| errno = EINVAL; |
| return 0; |
| } |
| else |
| return tperm; |
| } |
| return kperm; |
| } |
| |
| void |
| map_decision(security_class_t tclass, struct av_decision *avd) |
| { |
| if (tclass < current_mapping_size) { |
| unsigned i; |
| access_vector_t result; |
| |
| for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) |
| if (avd->allowed & current_mapping[tclass].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]) |
| 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]) |
| 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]) |
| result |= 1<<i; |
| avd->auditdeny = result; |
| } |
| } |