16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * Class and permission mappings. 36cd6a6acSopenharmony_ci */ 46cd6a6acSopenharmony_ci 56cd6a6acSopenharmony_ci#include <errno.h> 66cd6a6acSopenharmony_ci#include <stdio.h> 76cd6a6acSopenharmony_ci#include <stdlib.h> 86cd6a6acSopenharmony_ci#include <stdarg.h> 96cd6a6acSopenharmony_ci#include <stdbool.h> 106cd6a6acSopenharmony_ci#include <selinux/selinux.h> 116cd6a6acSopenharmony_ci#include <selinux/avc.h> 126cd6a6acSopenharmony_ci#include "callbacks.h" 136cd6a6acSopenharmony_ci#include "mapping.h" 146cd6a6acSopenharmony_ci#include "selinux_internal.h" 156cd6a6acSopenharmony_ci 166cd6a6acSopenharmony_ci/* 176cd6a6acSopenharmony_ci * Class and permission mappings 186cd6a6acSopenharmony_ci */ 196cd6a6acSopenharmony_ci 206cd6a6acSopenharmony_cistruct selinux_mapping { 216cd6a6acSopenharmony_ci security_class_t value; /* real, kernel value */ 226cd6a6acSopenharmony_ci unsigned num_perms; 236cd6a6acSopenharmony_ci access_vector_t perms[sizeof(access_vector_t) * 8]; 246cd6a6acSopenharmony_ci}; 256cd6a6acSopenharmony_ci 266cd6a6acSopenharmony_cistatic struct selinux_mapping *current_mapping = NULL; 276cd6a6acSopenharmony_cistatic security_class_t current_mapping_size = 0; 286cd6a6acSopenharmony_ci 296cd6a6acSopenharmony_ci/* 306cd6a6acSopenharmony_ci * Mapping setting function 316cd6a6acSopenharmony_ci */ 326cd6a6acSopenharmony_ci 336cd6a6acSopenharmony_ciint 346cd6a6acSopenharmony_ciselinux_set_mapping(struct security_class_mapping *map) 356cd6a6acSopenharmony_ci{ 366cd6a6acSopenharmony_ci size_t size = sizeof(struct selinux_mapping); 376cd6a6acSopenharmony_ci security_class_t i, j; 386cd6a6acSopenharmony_ci unsigned k; 396cd6a6acSopenharmony_ci bool print_unknown_handle = false; 406cd6a6acSopenharmony_ci bool reject = (security_reject_unknown() == 1); 416cd6a6acSopenharmony_ci bool deny = (security_deny_unknown() == 1); 426cd6a6acSopenharmony_ci 436cd6a6acSopenharmony_ci free(current_mapping); 446cd6a6acSopenharmony_ci current_mapping = NULL; 456cd6a6acSopenharmony_ci current_mapping_size = 0; 466cd6a6acSopenharmony_ci 476cd6a6acSopenharmony_ci if (avc_reset() < 0) 486cd6a6acSopenharmony_ci goto err; 496cd6a6acSopenharmony_ci 506cd6a6acSopenharmony_ci /* Find number of classes in the input mapping */ 516cd6a6acSopenharmony_ci if (!map) { 526cd6a6acSopenharmony_ci errno = EINVAL; 536cd6a6acSopenharmony_ci goto err; 546cd6a6acSopenharmony_ci } 556cd6a6acSopenharmony_ci i = 0; 566cd6a6acSopenharmony_ci while (map[i].name) 576cd6a6acSopenharmony_ci i++; 586cd6a6acSopenharmony_ci 596cd6a6acSopenharmony_ci /* Allocate space for the class records, plus one for class zero */ 606cd6a6acSopenharmony_ci current_mapping = (struct selinux_mapping *)calloc(++i, size); 616cd6a6acSopenharmony_ci if (!current_mapping) 626cd6a6acSopenharmony_ci goto err; 636cd6a6acSopenharmony_ci 646cd6a6acSopenharmony_ci /* Store the raw class and permission values */ 656cd6a6acSopenharmony_ci j = 0; 666cd6a6acSopenharmony_ci while (map[j].name) { 676cd6a6acSopenharmony_ci struct security_class_mapping *p_in = map + (j++); 686cd6a6acSopenharmony_ci struct selinux_mapping *p_out = current_mapping + j; 696cd6a6acSopenharmony_ci 706cd6a6acSopenharmony_ci p_out->value = string_to_security_class(p_in->name); 716cd6a6acSopenharmony_ci if (!p_out->value) { 726cd6a6acSopenharmony_ci selinux_log(SELINUX_INFO, 736cd6a6acSopenharmony_ci "SELinux: Class %s not defined in policy.\n", 746cd6a6acSopenharmony_ci p_in->name); 756cd6a6acSopenharmony_ci if (reject) 766cd6a6acSopenharmony_ci goto err2; 776cd6a6acSopenharmony_ci p_out->num_perms = 0; 786cd6a6acSopenharmony_ci print_unknown_handle = true; 796cd6a6acSopenharmony_ci continue; 806cd6a6acSopenharmony_ci } 816cd6a6acSopenharmony_ci 826cd6a6acSopenharmony_ci k = 0; 836cd6a6acSopenharmony_ci while (p_in->perms[k]) { 846cd6a6acSopenharmony_ci /* An empty permission string skips ahead */ 856cd6a6acSopenharmony_ci if (!*p_in->perms[k]) { 866cd6a6acSopenharmony_ci k++; 876cd6a6acSopenharmony_ci continue; 886cd6a6acSopenharmony_ci } 896cd6a6acSopenharmony_ci p_out->perms[k] = string_to_av_perm(p_out->value, 906cd6a6acSopenharmony_ci p_in->perms[k]); 916cd6a6acSopenharmony_ci if (!p_out->perms[k]) { 926cd6a6acSopenharmony_ci selinux_log(SELINUX_INFO, 936cd6a6acSopenharmony_ci "SELinux: Permission %s in class %s not defined in policy.\n", 946cd6a6acSopenharmony_ci p_in->perms[k], p_in->name); 956cd6a6acSopenharmony_ci if (reject) 966cd6a6acSopenharmony_ci goto err2; 976cd6a6acSopenharmony_ci print_unknown_handle = true; 986cd6a6acSopenharmony_ci } 996cd6a6acSopenharmony_ci k++; 1006cd6a6acSopenharmony_ci } 1016cd6a6acSopenharmony_ci p_out->num_perms = k; 1026cd6a6acSopenharmony_ci } 1036cd6a6acSopenharmony_ci 1046cd6a6acSopenharmony_ci if (print_unknown_handle) 1056cd6a6acSopenharmony_ci selinux_log(SELINUX_INFO, 1066cd6a6acSopenharmony_ci "SELinux: the above unknown classes and permissions will be %s\n", 1076cd6a6acSopenharmony_ci deny ? "denied" : "allowed"); 1086cd6a6acSopenharmony_ci 1096cd6a6acSopenharmony_ci /* Set the mapping size here so the above lookups are "raw" */ 1106cd6a6acSopenharmony_ci current_mapping_size = i; 1116cd6a6acSopenharmony_ci return 0; 1126cd6a6acSopenharmony_cierr2: 1136cd6a6acSopenharmony_ci free(current_mapping); 1146cd6a6acSopenharmony_ci current_mapping = NULL; 1156cd6a6acSopenharmony_ci current_mapping_size = 0; 1166cd6a6acSopenharmony_cierr: 1176cd6a6acSopenharmony_ci return -1; 1186cd6a6acSopenharmony_ci} 1196cd6a6acSopenharmony_ci 1206cd6a6acSopenharmony_ci/* 1216cd6a6acSopenharmony_ci * Get real, kernel values from mapped values 1226cd6a6acSopenharmony_ci */ 1236cd6a6acSopenharmony_ci 1246cd6a6acSopenharmony_cisecurity_class_t 1256cd6a6acSopenharmony_ciunmap_class(security_class_t tclass) 1266cd6a6acSopenharmony_ci{ 1276cd6a6acSopenharmony_ci if (tclass < current_mapping_size) 1286cd6a6acSopenharmony_ci return current_mapping[tclass].value; 1296cd6a6acSopenharmony_ci 1306cd6a6acSopenharmony_ci /* If here no mapping set or the class requested is not valid. */ 1316cd6a6acSopenharmony_ci if (current_mapping_size != 0) { 1326cd6a6acSopenharmony_ci errno = EINVAL; 1336cd6a6acSopenharmony_ci return 0; 1346cd6a6acSopenharmony_ci } 1356cd6a6acSopenharmony_ci else 1366cd6a6acSopenharmony_ci return tclass; 1376cd6a6acSopenharmony_ci} 1386cd6a6acSopenharmony_ci 1396cd6a6acSopenharmony_ciaccess_vector_t 1406cd6a6acSopenharmony_ciunmap_perm(security_class_t tclass, access_vector_t tperm) 1416cd6a6acSopenharmony_ci{ 1426cd6a6acSopenharmony_ci if (tclass < current_mapping_size) { 1436cd6a6acSopenharmony_ci unsigned i; 1446cd6a6acSopenharmony_ci access_vector_t kperm = 0; 1456cd6a6acSopenharmony_ci 1466cd6a6acSopenharmony_ci for (i = 0; i < current_mapping[tclass].num_perms; i++) 1476cd6a6acSopenharmony_ci if (tperm & (UINT32_C(1)<<i)) { 1486cd6a6acSopenharmony_ci kperm |= current_mapping[tclass].perms[i]; 1496cd6a6acSopenharmony_ci tperm &= ~(UINT32_C(1)<<i); 1506cd6a6acSopenharmony_ci } 1516cd6a6acSopenharmony_ci return kperm; 1526cd6a6acSopenharmony_ci } 1536cd6a6acSopenharmony_ci 1546cd6a6acSopenharmony_ci /* If here no mapping set or the perm requested is not valid. */ 1556cd6a6acSopenharmony_ci if (current_mapping_size != 0) { 1566cd6a6acSopenharmony_ci errno = EINVAL; 1576cd6a6acSopenharmony_ci return 0; 1586cd6a6acSopenharmony_ci } 1596cd6a6acSopenharmony_ci else 1606cd6a6acSopenharmony_ci return tperm; 1616cd6a6acSopenharmony_ci} 1626cd6a6acSopenharmony_ci 1636cd6a6acSopenharmony_ci/* 1646cd6a6acSopenharmony_ci * Get mapped values from real, kernel values 1656cd6a6acSopenharmony_ci */ 1666cd6a6acSopenharmony_ci 1676cd6a6acSopenharmony_cisecurity_class_t 1686cd6a6acSopenharmony_cimap_class(security_class_t kclass) 1696cd6a6acSopenharmony_ci{ 1706cd6a6acSopenharmony_ci security_class_t i; 1716cd6a6acSopenharmony_ci 1726cd6a6acSopenharmony_ci for (i = 0; i < current_mapping_size; i++) 1736cd6a6acSopenharmony_ci if (current_mapping[i].value == kclass) 1746cd6a6acSopenharmony_ci return i; 1756cd6a6acSopenharmony_ci 1766cd6a6acSopenharmony_ci/* If here no mapping set or the class requested is not valid. */ 1776cd6a6acSopenharmony_ci if (current_mapping_size != 0) { 1786cd6a6acSopenharmony_ci errno = EINVAL; 1796cd6a6acSopenharmony_ci return 0; 1806cd6a6acSopenharmony_ci } 1816cd6a6acSopenharmony_ci else 1826cd6a6acSopenharmony_ci return kclass; 1836cd6a6acSopenharmony_ci} 1846cd6a6acSopenharmony_ci 1856cd6a6acSopenharmony_ciaccess_vector_t 1866cd6a6acSopenharmony_cimap_perm(security_class_t tclass, access_vector_t kperm) 1876cd6a6acSopenharmony_ci{ 1886cd6a6acSopenharmony_ci if (tclass < current_mapping_size) { 1896cd6a6acSopenharmony_ci unsigned i; 1906cd6a6acSopenharmony_ci access_vector_t tperm = 0; 1916cd6a6acSopenharmony_ci 1926cd6a6acSopenharmony_ci for (i = 0; i < current_mapping[tclass].num_perms; i++) 1936cd6a6acSopenharmony_ci if (kperm & current_mapping[tclass].perms[i]) { 1946cd6a6acSopenharmony_ci tperm |= UINT32_C(1)<<i; 1956cd6a6acSopenharmony_ci kperm &= ~current_mapping[tclass].perms[i]; 1966cd6a6acSopenharmony_ci } 1976cd6a6acSopenharmony_ci 1986cd6a6acSopenharmony_ci if (tperm == 0) { 1996cd6a6acSopenharmony_ci errno = EINVAL; 2006cd6a6acSopenharmony_ci return 0; 2016cd6a6acSopenharmony_ci } 2026cd6a6acSopenharmony_ci else 2036cd6a6acSopenharmony_ci return tperm; 2046cd6a6acSopenharmony_ci } 2056cd6a6acSopenharmony_ci return kperm; 2066cd6a6acSopenharmony_ci} 2076cd6a6acSopenharmony_ci 2086cd6a6acSopenharmony_civoid 2096cd6a6acSopenharmony_cimap_decision(security_class_t tclass, struct av_decision *avd) 2106cd6a6acSopenharmony_ci{ 2116cd6a6acSopenharmony_ci if (tclass < current_mapping_size) { 2126cd6a6acSopenharmony_ci bool allow_unknown = (security_deny_unknown() == 0); 2136cd6a6acSopenharmony_ci struct selinux_mapping *mapping = ¤t_mapping[tclass]; 2146cd6a6acSopenharmony_ci unsigned int i, n = mapping->num_perms; 2156cd6a6acSopenharmony_ci access_vector_t result; 2166cd6a6acSopenharmony_ci 2176cd6a6acSopenharmony_ci for (i = 0, result = 0; i < n; i++) { 2186cd6a6acSopenharmony_ci if (avd->allowed & mapping->perms[i]) 2196cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2206cd6a6acSopenharmony_ci else if (allow_unknown && !mapping->perms[i]) 2216cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2226cd6a6acSopenharmony_ci } 2236cd6a6acSopenharmony_ci avd->allowed = result; 2246cd6a6acSopenharmony_ci 2256cd6a6acSopenharmony_ci for (i = 0, result = 0; i < n; i++) { 2266cd6a6acSopenharmony_ci if (avd->decided & mapping->perms[i]) 2276cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2286cd6a6acSopenharmony_ci else if (allow_unknown && !mapping->perms[i]) 2296cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2306cd6a6acSopenharmony_ci } 2316cd6a6acSopenharmony_ci avd->decided = result; 2326cd6a6acSopenharmony_ci 2336cd6a6acSopenharmony_ci for (i = 0, result = 0; i < n; i++) 2346cd6a6acSopenharmony_ci if (avd->auditallow & mapping->perms[i]) 2356cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2366cd6a6acSopenharmony_ci avd->auditallow = result; 2376cd6a6acSopenharmony_ci 2386cd6a6acSopenharmony_ci for (i = 0, result = 0; i < n; i++) { 2396cd6a6acSopenharmony_ci if (avd->auditdeny & mapping->perms[i]) 2406cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2416cd6a6acSopenharmony_ci else if (!allow_unknown && !mapping->perms[i]) 2426cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2436cd6a6acSopenharmony_ci } 2446cd6a6acSopenharmony_ci 2456cd6a6acSopenharmony_ci /* 2466cd6a6acSopenharmony_ci * Make sure we audit denials for any permission check 2476cd6a6acSopenharmony_ci * beyond the mapping->num_perms since this indicates 2486cd6a6acSopenharmony_ci * a bug in the object manager. 2496cd6a6acSopenharmony_ci */ 2506cd6a6acSopenharmony_ci for (; i < (sizeof(result)*8); i++) 2516cd6a6acSopenharmony_ci result |= UINT32_C(1)<<i; 2526cd6a6acSopenharmony_ci avd->auditdeny = result; 2536cd6a6acSopenharmony_ci } 2546cd6a6acSopenharmony_ci} 255