16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * String representation support for classes and permissions. 36cd6a6acSopenharmony_ci */ 46cd6a6acSopenharmony_ci#include <sys/stat.h> 56cd6a6acSopenharmony_ci#include <dirent.h> 66cd6a6acSopenharmony_ci#include <fcntl.h> 76cd6a6acSopenharmony_ci#include <limits.h> 86cd6a6acSopenharmony_ci#include <unistd.h> 96cd6a6acSopenharmony_ci#include <errno.h> 106cd6a6acSopenharmony_ci#include <stddef.h> 116cd6a6acSopenharmony_ci#include <stdio.h> 126cd6a6acSopenharmony_ci#include <stdlib.h> 136cd6a6acSopenharmony_ci#include <string.h> 146cd6a6acSopenharmony_ci#include <stdint.h> 156cd6a6acSopenharmony_ci#include <ctype.h> 166cd6a6acSopenharmony_ci#include "selinux_internal.h" 176cd6a6acSopenharmony_ci#include "policy.h" 186cd6a6acSopenharmony_ci#include "mapping.h" 196cd6a6acSopenharmony_ci 206cd6a6acSopenharmony_ci#define MAXVECTORS 8*sizeof(access_vector_t) 216cd6a6acSopenharmony_ci 226cd6a6acSopenharmony_cistruct discover_class_node { 236cd6a6acSopenharmony_ci char *name; 246cd6a6acSopenharmony_ci security_class_t value; 256cd6a6acSopenharmony_ci char **perms; 266cd6a6acSopenharmony_ci 276cd6a6acSopenharmony_ci struct discover_class_node *next; 286cd6a6acSopenharmony_ci}; 296cd6a6acSopenharmony_ci 306cd6a6acSopenharmony_cistatic struct discover_class_node *discover_class_cache = NULL; 316cd6a6acSopenharmony_ci 326cd6a6acSopenharmony_cistatic struct discover_class_node * get_class_cache_entry_name(const char *s) 336cd6a6acSopenharmony_ci{ 346cd6a6acSopenharmony_ci struct discover_class_node *node = discover_class_cache; 356cd6a6acSopenharmony_ci 366cd6a6acSopenharmony_ci for (; node != NULL && strcmp(s,node->name) != 0; node = node->next); 376cd6a6acSopenharmony_ci 386cd6a6acSopenharmony_ci return node; 396cd6a6acSopenharmony_ci} 406cd6a6acSopenharmony_ci 416cd6a6acSopenharmony_cistatic struct discover_class_node * get_class_cache_entry_value(security_class_t c) 426cd6a6acSopenharmony_ci{ 436cd6a6acSopenharmony_ci struct discover_class_node *node = discover_class_cache; 446cd6a6acSopenharmony_ci 456cd6a6acSopenharmony_ci for (; node != NULL && c != node->value; node = node->next); 466cd6a6acSopenharmony_ci 476cd6a6acSopenharmony_ci return node; 486cd6a6acSopenharmony_ci} 496cd6a6acSopenharmony_ci 506cd6a6acSopenharmony_cistatic struct discover_class_node * discover_class(const char *s) 516cd6a6acSopenharmony_ci{ 526cd6a6acSopenharmony_ci int fd, ret; 536cd6a6acSopenharmony_ci char path[PATH_MAX]; 546cd6a6acSopenharmony_ci char buf[20]; 556cd6a6acSopenharmony_ci DIR *dir; 566cd6a6acSopenharmony_ci struct dirent *dentry; 576cd6a6acSopenharmony_ci size_t i; 586cd6a6acSopenharmony_ci 596cd6a6acSopenharmony_ci struct discover_class_node *node; 606cd6a6acSopenharmony_ci 616cd6a6acSopenharmony_ci if (!selinux_mnt) { 626cd6a6acSopenharmony_ci errno = ENOENT; 636cd6a6acSopenharmony_ci return NULL; 646cd6a6acSopenharmony_ci } 656cd6a6acSopenharmony_ci 666cd6a6acSopenharmony_ci if (strchr(s, '/') != NULL) 676cd6a6acSopenharmony_ci return NULL; 686cd6a6acSopenharmony_ci 696cd6a6acSopenharmony_ci /* allocate a node */ 706cd6a6acSopenharmony_ci node = malloc(sizeof(struct discover_class_node)); 716cd6a6acSopenharmony_ci if (node == NULL) 726cd6a6acSopenharmony_ci return NULL; 736cd6a6acSopenharmony_ci 746cd6a6acSopenharmony_ci /* allocate array for perms */ 756cd6a6acSopenharmony_ci node->perms = calloc(MAXVECTORS,sizeof(char*)); 766cd6a6acSopenharmony_ci if (node->perms == NULL) 776cd6a6acSopenharmony_ci goto err1; 786cd6a6acSopenharmony_ci 796cd6a6acSopenharmony_ci /* load up the name */ 806cd6a6acSopenharmony_ci node->name = strdup(s); 816cd6a6acSopenharmony_ci if (node->name == NULL) 826cd6a6acSopenharmony_ci goto err2; 836cd6a6acSopenharmony_ci 846cd6a6acSopenharmony_ci /* load up class index */ 856cd6a6acSopenharmony_ci ret = snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); 866cd6a6acSopenharmony_ci if (ret < 0 || (size_t)ret >= sizeof path) 876cd6a6acSopenharmony_ci goto err3; 886cd6a6acSopenharmony_ci 896cd6a6acSopenharmony_ci fd = open(path, O_RDONLY | O_CLOEXEC); 906cd6a6acSopenharmony_ci if (fd < 0) 916cd6a6acSopenharmony_ci goto err3; 926cd6a6acSopenharmony_ci 936cd6a6acSopenharmony_ci memset(buf, 0, sizeof(buf)); 946cd6a6acSopenharmony_ci ret = read(fd, buf, sizeof(buf) - 1); 956cd6a6acSopenharmony_ci close(fd); 966cd6a6acSopenharmony_ci if (ret < 0) 976cd6a6acSopenharmony_ci goto err3; 986cd6a6acSopenharmony_ci 996cd6a6acSopenharmony_ci if (sscanf(buf, "%hu", &node->value) != 1) 1006cd6a6acSopenharmony_ci goto err3; 1016cd6a6acSopenharmony_ci 1026cd6a6acSopenharmony_ci /* load up permission indices */ 1036cd6a6acSopenharmony_ci ret = snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); 1046cd6a6acSopenharmony_ci if (ret < 0 || (size_t)ret >= sizeof path) 1056cd6a6acSopenharmony_ci goto err3; 1066cd6a6acSopenharmony_ci 1076cd6a6acSopenharmony_ci dir = opendir(path); 1086cd6a6acSopenharmony_ci if (dir == NULL) 1096cd6a6acSopenharmony_ci goto err3; 1106cd6a6acSopenharmony_ci 1116cd6a6acSopenharmony_ci dentry = readdir(dir); 1126cd6a6acSopenharmony_ci while (dentry != NULL) { 1136cd6a6acSopenharmony_ci unsigned int value; 1146cd6a6acSopenharmony_ci struct stat m; 1156cd6a6acSopenharmony_ci 1166cd6a6acSopenharmony_ci ret = snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); 1176cd6a6acSopenharmony_ci if (ret < 0 || (size_t)ret >= sizeof path) 1186cd6a6acSopenharmony_ci goto err4; 1196cd6a6acSopenharmony_ci 1206cd6a6acSopenharmony_ci fd = open(path, O_RDONLY | O_CLOEXEC); 1216cd6a6acSopenharmony_ci if (fd < 0) 1226cd6a6acSopenharmony_ci goto err4; 1236cd6a6acSopenharmony_ci 1246cd6a6acSopenharmony_ci if (fstat(fd, &m) < 0) { 1256cd6a6acSopenharmony_ci close(fd); 1266cd6a6acSopenharmony_ci goto err4; 1276cd6a6acSopenharmony_ci } 1286cd6a6acSopenharmony_ci 1296cd6a6acSopenharmony_ci if (m.st_mode & S_IFDIR) { 1306cd6a6acSopenharmony_ci close(fd); 1316cd6a6acSopenharmony_ci dentry = readdir(dir); 1326cd6a6acSopenharmony_ci continue; 1336cd6a6acSopenharmony_ci } 1346cd6a6acSopenharmony_ci 1356cd6a6acSopenharmony_ci memset(buf, 0, sizeof(buf)); 1366cd6a6acSopenharmony_ci ret = read(fd, buf, sizeof(buf) - 1); 1376cd6a6acSopenharmony_ci close(fd); 1386cd6a6acSopenharmony_ci if (ret < 0) 1396cd6a6acSopenharmony_ci goto err4; 1406cd6a6acSopenharmony_ci 1416cd6a6acSopenharmony_ci if (sscanf(buf, "%u", &value) != 1) 1426cd6a6acSopenharmony_ci goto err4; 1436cd6a6acSopenharmony_ci 1446cd6a6acSopenharmony_ci if (value == 0 || value > MAXVECTORS) 1456cd6a6acSopenharmony_ci goto err4; 1466cd6a6acSopenharmony_ci 1476cd6a6acSopenharmony_ci node->perms[value-1] = strdup(dentry->d_name); 1486cd6a6acSopenharmony_ci if (node->perms[value-1] == NULL) 1496cd6a6acSopenharmony_ci goto err4; 1506cd6a6acSopenharmony_ci 1516cd6a6acSopenharmony_ci dentry = readdir(dir); 1526cd6a6acSopenharmony_ci } 1536cd6a6acSopenharmony_ci closedir(dir); 1546cd6a6acSopenharmony_ci 1556cd6a6acSopenharmony_ci node->next = discover_class_cache; 1566cd6a6acSopenharmony_ci discover_class_cache = node; 1576cd6a6acSopenharmony_ci 1586cd6a6acSopenharmony_ci return node; 1596cd6a6acSopenharmony_ci 1606cd6a6acSopenharmony_cierr4: 1616cd6a6acSopenharmony_ci closedir(dir); 1626cd6a6acSopenharmony_ci for (i = 0; i < MAXVECTORS; i++) 1636cd6a6acSopenharmony_ci free(node->perms[i]); 1646cd6a6acSopenharmony_cierr3: 1656cd6a6acSopenharmony_ci free(node->name); 1666cd6a6acSopenharmony_cierr2: 1676cd6a6acSopenharmony_ci free(node->perms); 1686cd6a6acSopenharmony_cierr1: 1696cd6a6acSopenharmony_ci free(node); 1706cd6a6acSopenharmony_ci return NULL; 1716cd6a6acSopenharmony_ci} 1726cd6a6acSopenharmony_ci 1736cd6a6acSopenharmony_civoid selinux_flush_class_cache(void) 1746cd6a6acSopenharmony_ci{ 1756cd6a6acSopenharmony_ci struct discover_class_node *cur = discover_class_cache, *prev = NULL; 1766cd6a6acSopenharmony_ci size_t i; 1776cd6a6acSopenharmony_ci 1786cd6a6acSopenharmony_ci while (cur != NULL) { 1796cd6a6acSopenharmony_ci free(cur->name); 1806cd6a6acSopenharmony_ci 1816cd6a6acSopenharmony_ci for (i = 0; i < MAXVECTORS; i++) 1826cd6a6acSopenharmony_ci free(cur->perms[i]); 1836cd6a6acSopenharmony_ci 1846cd6a6acSopenharmony_ci free(cur->perms); 1856cd6a6acSopenharmony_ci 1866cd6a6acSopenharmony_ci prev = cur; 1876cd6a6acSopenharmony_ci cur = cur->next; 1886cd6a6acSopenharmony_ci 1896cd6a6acSopenharmony_ci free(prev); 1906cd6a6acSopenharmony_ci } 1916cd6a6acSopenharmony_ci 1926cd6a6acSopenharmony_ci discover_class_cache = NULL; 1936cd6a6acSopenharmony_ci} 1946cd6a6acSopenharmony_ci 1956cd6a6acSopenharmony_ci 1966cd6a6acSopenharmony_cisecurity_class_t string_to_security_class(const char *s) 1976cd6a6acSopenharmony_ci{ 1986cd6a6acSopenharmony_ci struct discover_class_node *node; 1996cd6a6acSopenharmony_ci 2006cd6a6acSopenharmony_ci node = get_class_cache_entry_name(s); 2016cd6a6acSopenharmony_ci if (node == NULL) { 2026cd6a6acSopenharmony_ci node = discover_class(s); 2036cd6a6acSopenharmony_ci 2046cd6a6acSopenharmony_ci if (node == NULL) { 2056cd6a6acSopenharmony_ci errno = EINVAL; 2066cd6a6acSopenharmony_ci return 0; 2076cd6a6acSopenharmony_ci } 2086cd6a6acSopenharmony_ci } 2096cd6a6acSopenharmony_ci 2106cd6a6acSopenharmony_ci return map_class(node->value); 2116cd6a6acSopenharmony_ci} 2126cd6a6acSopenharmony_ci 2136cd6a6acSopenharmony_cisecurity_class_t mode_to_security_class(mode_t m) { 2146cd6a6acSopenharmony_ci 2156cd6a6acSopenharmony_ci if (S_ISREG(m)) 2166cd6a6acSopenharmony_ci return string_to_security_class("file"); 2176cd6a6acSopenharmony_ci if (S_ISDIR(m)) 2186cd6a6acSopenharmony_ci return string_to_security_class("dir"); 2196cd6a6acSopenharmony_ci if (S_ISCHR(m)) 2206cd6a6acSopenharmony_ci return string_to_security_class("chr_file"); 2216cd6a6acSopenharmony_ci if (S_ISBLK(m)) 2226cd6a6acSopenharmony_ci return string_to_security_class("blk_file"); 2236cd6a6acSopenharmony_ci if (S_ISFIFO(m)) 2246cd6a6acSopenharmony_ci return string_to_security_class("fifo_file"); 2256cd6a6acSopenharmony_ci if (S_ISLNK(m)) 2266cd6a6acSopenharmony_ci return string_to_security_class("lnk_file"); 2276cd6a6acSopenharmony_ci if (S_ISSOCK(m)) 2286cd6a6acSopenharmony_ci return string_to_security_class("sock_file"); 2296cd6a6acSopenharmony_ci 2306cd6a6acSopenharmony_ci errno = EINVAL; 2316cd6a6acSopenharmony_ci return 0; 2326cd6a6acSopenharmony_ci} 2336cd6a6acSopenharmony_ci 2346cd6a6acSopenharmony_ciaccess_vector_t string_to_av_perm(security_class_t tclass, const char *s) 2356cd6a6acSopenharmony_ci{ 2366cd6a6acSopenharmony_ci struct discover_class_node *node; 2376cd6a6acSopenharmony_ci security_class_t kclass = unmap_class(tclass); 2386cd6a6acSopenharmony_ci 2396cd6a6acSopenharmony_ci node = get_class_cache_entry_value(kclass); 2406cd6a6acSopenharmony_ci if (node != NULL) { 2416cd6a6acSopenharmony_ci size_t i; 2426cd6a6acSopenharmony_ci for (i = 0; i < MAXVECTORS && node->perms[i] != NULL; i++) 2436cd6a6acSopenharmony_ci if (strcmp(node->perms[i],s) == 0) 2446cd6a6acSopenharmony_ci return map_perm(tclass, UINT32_C(1)<<i); 2456cd6a6acSopenharmony_ci } 2466cd6a6acSopenharmony_ci 2476cd6a6acSopenharmony_ci errno = EINVAL; 2486cd6a6acSopenharmony_ci return 0; 2496cd6a6acSopenharmony_ci} 2506cd6a6acSopenharmony_ci 2516cd6a6acSopenharmony_ciconst char *security_class_to_string(security_class_t tclass) 2526cd6a6acSopenharmony_ci{ 2536cd6a6acSopenharmony_ci struct discover_class_node *node; 2546cd6a6acSopenharmony_ci 2556cd6a6acSopenharmony_ci tclass = unmap_class(tclass); 2566cd6a6acSopenharmony_ci 2576cd6a6acSopenharmony_ci node = get_class_cache_entry_value(tclass); 2586cd6a6acSopenharmony_ci if (node == NULL) 2596cd6a6acSopenharmony_ci return NULL; 2606cd6a6acSopenharmony_ci else 2616cd6a6acSopenharmony_ci return node->name; 2626cd6a6acSopenharmony_ci} 2636cd6a6acSopenharmony_ci 2646cd6a6acSopenharmony_ciconst char *security_av_perm_to_string(security_class_t tclass, 2656cd6a6acSopenharmony_ci access_vector_t av) 2666cd6a6acSopenharmony_ci{ 2676cd6a6acSopenharmony_ci struct discover_class_node *node; 2686cd6a6acSopenharmony_ci size_t i; 2696cd6a6acSopenharmony_ci 2706cd6a6acSopenharmony_ci av = unmap_perm(tclass, av); 2716cd6a6acSopenharmony_ci tclass = unmap_class(tclass); 2726cd6a6acSopenharmony_ci 2736cd6a6acSopenharmony_ci node = get_class_cache_entry_value(tclass); 2746cd6a6acSopenharmony_ci if (av && node) 2756cd6a6acSopenharmony_ci for (i = 0; i<MAXVECTORS; i++) 2766cd6a6acSopenharmony_ci if ((UINT32_C(1)<<i) & av) 2776cd6a6acSopenharmony_ci return node->perms[i]; 2786cd6a6acSopenharmony_ci 2796cd6a6acSopenharmony_ci return NULL; 2806cd6a6acSopenharmony_ci} 2816cd6a6acSopenharmony_ci 2826cd6a6acSopenharmony_ciint security_av_string(security_class_t tclass, access_vector_t av, char **res) 2836cd6a6acSopenharmony_ci{ 2846cd6a6acSopenharmony_ci unsigned int i; 2856cd6a6acSopenharmony_ci size_t len = 5; 2866cd6a6acSopenharmony_ci access_vector_t tmp = av; 2876cd6a6acSopenharmony_ci int rc = 0; 2886cd6a6acSopenharmony_ci const char *str; 2896cd6a6acSopenharmony_ci char *ptr; 2906cd6a6acSopenharmony_ci 2916cd6a6acSopenharmony_ci /* first pass computes the required length */ 2926cd6a6acSopenharmony_ci for (i = 0; tmp; tmp >>= 1, i++) { 2936cd6a6acSopenharmony_ci if (tmp & 1) { 2946cd6a6acSopenharmony_ci str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i)); 2956cd6a6acSopenharmony_ci if (str) 2966cd6a6acSopenharmony_ci len += strlen(str) + 1; 2976cd6a6acSopenharmony_ci } 2986cd6a6acSopenharmony_ci } 2996cd6a6acSopenharmony_ci 3006cd6a6acSopenharmony_ci *res = malloc(len); 3016cd6a6acSopenharmony_ci if (!*res) { 3026cd6a6acSopenharmony_ci rc = -1; 3036cd6a6acSopenharmony_ci goto out; 3046cd6a6acSopenharmony_ci } 3056cd6a6acSopenharmony_ci 3066cd6a6acSopenharmony_ci /* second pass constructs the string */ 3076cd6a6acSopenharmony_ci tmp = av; 3086cd6a6acSopenharmony_ci ptr = *res; 3096cd6a6acSopenharmony_ci 3106cd6a6acSopenharmony_ci if (!av) { 3116cd6a6acSopenharmony_ci sprintf(ptr, "null"); 3126cd6a6acSopenharmony_ci goto out; 3136cd6a6acSopenharmony_ci } 3146cd6a6acSopenharmony_ci 3156cd6a6acSopenharmony_ci ptr += sprintf(ptr, "{ "); 3166cd6a6acSopenharmony_ci for (i = 0; tmp; tmp >>= 1, i++) { 3176cd6a6acSopenharmony_ci if (tmp & 1) { 3186cd6a6acSopenharmony_ci str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i)); 3196cd6a6acSopenharmony_ci if (str) 3206cd6a6acSopenharmony_ci ptr += sprintf(ptr, "%s ", str); 3216cd6a6acSopenharmony_ci } 3226cd6a6acSopenharmony_ci } 3236cd6a6acSopenharmony_ci sprintf(ptr, "}"); 3246cd6a6acSopenharmony_ciout: 3256cd6a6acSopenharmony_ci return rc; 3266cd6a6acSopenharmony_ci} 3276cd6a6acSopenharmony_ci 3286cd6a6acSopenharmony_civoid print_access_vector(security_class_t tclass, access_vector_t av) 3296cd6a6acSopenharmony_ci{ 3306cd6a6acSopenharmony_ci const char *permstr; 3316cd6a6acSopenharmony_ci access_vector_t bit = 1; 3326cd6a6acSopenharmony_ci 3336cd6a6acSopenharmony_ci if (av == 0) { 3346cd6a6acSopenharmony_ci printf(" null"); 3356cd6a6acSopenharmony_ci return; 3366cd6a6acSopenharmony_ci } 3376cd6a6acSopenharmony_ci 3386cd6a6acSopenharmony_ci printf(" {"); 3396cd6a6acSopenharmony_ci 3406cd6a6acSopenharmony_ci while (av) { 3416cd6a6acSopenharmony_ci if (av & bit) { 3426cd6a6acSopenharmony_ci permstr = security_av_perm_to_string(tclass, bit); 3436cd6a6acSopenharmony_ci if (!permstr) 3446cd6a6acSopenharmony_ci break; 3456cd6a6acSopenharmony_ci printf(" %s", permstr); 3466cd6a6acSopenharmony_ci av &= ~bit; 3476cd6a6acSopenharmony_ci } 3486cd6a6acSopenharmony_ci bit <<= 1; 3496cd6a6acSopenharmony_ci } 3506cd6a6acSopenharmony_ci 3516cd6a6acSopenharmony_ci if (av) 3526cd6a6acSopenharmony_ci printf(" 0x%x", av); 3536cd6a6acSopenharmony_ci printf(" }"); 3546cd6a6acSopenharmony_ci} 355