1 /* 2 * String representation support for classes and permissions. 3 */ 4 #include <sys/stat.h> 5 #include <dirent.h> 6 #include <fcntl.h> 7 #include <limits.h> 8 #include <unistd.h> 9 #include <errno.h> 10 #include <stddef.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <stdint.h> 15 #include <ctype.h> 16 #include "selinux_internal.h" 17 #include "policy.h" 18 #include "mapping.h" 19 20 #define MAXVECTORS 8*sizeof(access_vector_t) 21 22 struct discover_class_node { 23 char *name; 24 security_class_t value; 25 char **perms; 26 27 struct discover_class_node *next; 28 }; 29 30 static struct discover_class_node *discover_class_cache = NULL; 31 get_class_cache_entry_name(const char * s)32 static struct discover_class_node * get_class_cache_entry_name(const char *s) 33 { 34 struct discover_class_node *node = discover_class_cache; 35 36 for (; node != NULL && strcmp(s,node->name) != 0; node = node->next); 37 38 return node; 39 } 40 get_class_cache_entry_value(security_class_t c)41 static struct discover_class_node * get_class_cache_entry_value(security_class_t c) 42 { 43 struct discover_class_node *node = discover_class_cache; 44 45 for (; node != NULL && c != node->value; node = node->next); 46 47 return node; 48 } 49 discover_class(const char * s)50 static struct discover_class_node * discover_class(const char *s) 51 { 52 int fd, ret; 53 char path[PATH_MAX]; 54 char buf[20]; 55 DIR *dir; 56 struct dirent *dentry; 57 size_t i; 58 59 struct discover_class_node *node; 60 61 if (!selinux_mnt) { 62 errno = ENOENT; 63 return NULL; 64 } 65 66 if (strchr(s, '/') != NULL) 67 return NULL; 68 69 /* allocate a node */ 70 node = malloc(sizeof(struct discover_class_node)); 71 if (node == NULL) 72 return NULL; 73 74 /* allocate array for perms */ 75 node->perms = calloc(MAXVECTORS,sizeof(char*)); 76 if (node->perms == NULL) 77 goto err1; 78 79 /* load up the name */ 80 node->name = strdup(s); 81 if (node->name == NULL) 82 goto err2; 83 84 /* load up class index */ 85 ret = snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); 86 if (ret < 0 || (size_t)ret >= sizeof path) 87 goto err3; 88 89 fd = open(path, O_RDONLY | O_CLOEXEC); 90 if (fd < 0) 91 goto err3; 92 93 memset(buf, 0, sizeof(buf)); 94 ret = read(fd, buf, sizeof(buf) - 1); 95 close(fd); 96 if (ret < 0) 97 goto err3; 98 99 if (sscanf(buf, "%hu", &node->value) != 1) 100 goto err3; 101 102 /* load up permission indices */ 103 ret = snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); 104 if (ret < 0 || (size_t)ret >= sizeof path) 105 goto err3; 106 107 dir = opendir(path); 108 if (dir == NULL) 109 goto err3; 110 111 dentry = readdir(dir); 112 while (dentry != NULL) { 113 unsigned int value; 114 struct stat m; 115 116 ret = snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); 117 if (ret < 0 || (size_t)ret >= sizeof path) 118 goto err4; 119 120 fd = open(path, O_RDONLY | O_CLOEXEC); 121 if (fd < 0) 122 goto err4; 123 124 if (fstat(fd, &m) < 0) { 125 close(fd); 126 goto err4; 127 } 128 129 if (m.st_mode & S_IFDIR) { 130 close(fd); 131 dentry = readdir(dir); 132 continue; 133 } 134 135 memset(buf, 0, sizeof(buf)); 136 ret = read(fd, buf, sizeof(buf) - 1); 137 close(fd); 138 if (ret < 0) 139 goto err4; 140 141 if (sscanf(buf, "%u", &value) != 1) 142 goto err4; 143 144 if (value == 0 || value > MAXVECTORS) 145 goto err4; 146 147 node->perms[value-1] = strdup(dentry->d_name); 148 if (node->perms[value-1] == NULL) 149 goto err4; 150 151 dentry = readdir(dir); 152 } 153 closedir(dir); 154 155 node->next = discover_class_cache; 156 discover_class_cache = node; 157 158 return node; 159 160 err4: 161 closedir(dir); 162 for (i = 0; i < MAXVECTORS; i++) 163 free(node->perms[i]); 164 err3: 165 free(node->name); 166 err2: 167 free(node->perms); 168 err1: 169 free(node); 170 return NULL; 171 } 172 selinux_flush_class_cache(void)173 void selinux_flush_class_cache(void) 174 { 175 struct discover_class_node *cur = discover_class_cache, *prev = NULL; 176 size_t i; 177 178 while (cur != NULL) { 179 free(cur->name); 180 181 for (i = 0; i < MAXVECTORS; i++) 182 free(cur->perms[i]); 183 184 free(cur->perms); 185 186 prev = cur; 187 cur = cur->next; 188 189 free(prev); 190 } 191 192 discover_class_cache = NULL; 193 } 194 195 string_to_security_class(const char * s)196 security_class_t string_to_security_class(const char *s) 197 { 198 struct discover_class_node *node; 199 200 node = get_class_cache_entry_name(s); 201 if (node == NULL) { 202 node = discover_class(s); 203 204 if (node == NULL) { 205 errno = EINVAL; 206 return 0; 207 } 208 } 209 210 return map_class(node->value); 211 } 212 mode_to_security_class(mode_t m)213 security_class_t mode_to_security_class(mode_t m) { 214 215 if (S_ISREG(m)) 216 return string_to_security_class("file"); 217 if (S_ISDIR(m)) 218 return string_to_security_class("dir"); 219 if (S_ISCHR(m)) 220 return string_to_security_class("chr_file"); 221 if (S_ISBLK(m)) 222 return string_to_security_class("blk_file"); 223 if (S_ISFIFO(m)) 224 return string_to_security_class("fifo_file"); 225 if (S_ISLNK(m)) 226 return string_to_security_class("lnk_file"); 227 if (S_ISSOCK(m)) 228 return string_to_security_class("sock_file"); 229 230 errno = EINVAL; 231 return 0; 232 } 233 string_to_av_perm(security_class_t tclass,const char * s)234 access_vector_t string_to_av_perm(security_class_t tclass, const char *s) 235 { 236 struct discover_class_node *node; 237 security_class_t kclass = unmap_class(tclass); 238 239 node = get_class_cache_entry_value(kclass); 240 if (node != NULL) { 241 size_t i; 242 for (i = 0; i < MAXVECTORS && node->perms[i] != NULL; i++) 243 if (strcmp(node->perms[i],s) == 0) 244 return map_perm(tclass, UINT32_C(1)<<i); 245 } 246 247 errno = EINVAL; 248 return 0; 249 } 250 security_class_to_string(security_class_t tclass)251 const char *security_class_to_string(security_class_t tclass) 252 { 253 struct discover_class_node *node; 254 255 tclass = unmap_class(tclass); 256 257 node = get_class_cache_entry_value(tclass); 258 if (node == NULL) 259 return NULL; 260 else 261 return node->name; 262 } 263 security_av_perm_to_string(security_class_t tclass,access_vector_t av)264 const char *security_av_perm_to_string(security_class_t tclass, 265 access_vector_t av) 266 { 267 struct discover_class_node *node; 268 size_t i; 269 270 av = unmap_perm(tclass, av); 271 tclass = unmap_class(tclass); 272 273 node = get_class_cache_entry_value(tclass); 274 if (av && node) 275 for (i = 0; i<MAXVECTORS; i++) 276 if ((UINT32_C(1)<<i) & av) 277 return node->perms[i]; 278 279 return NULL; 280 } 281 security_av_string(security_class_t tclass,access_vector_t av,char ** res)282 int security_av_string(security_class_t tclass, access_vector_t av, char **res) 283 { 284 unsigned int i; 285 size_t len = 5; 286 access_vector_t tmp = av; 287 int rc = 0; 288 const char *str; 289 char *ptr; 290 291 /* first pass computes the required length */ 292 for (i = 0; tmp; tmp >>= 1, i++) { 293 if (tmp & 1) { 294 str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i)); 295 if (str) 296 len += strlen(str) + 1; 297 } 298 } 299 300 *res = malloc(len); 301 if (!*res) { 302 rc = -1; 303 goto out; 304 } 305 306 /* second pass constructs the string */ 307 tmp = av; 308 ptr = *res; 309 310 if (!av) { 311 sprintf(ptr, "null"); 312 goto out; 313 } 314 315 ptr += sprintf(ptr, "{ "); 316 for (i = 0; tmp; tmp >>= 1, i++) { 317 if (tmp & 1) { 318 str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i)); 319 if (str) 320 ptr += sprintf(ptr, "%s ", str); 321 } 322 } 323 sprintf(ptr, "}"); 324 out: 325 return rc; 326 } 327 print_access_vector(security_class_t tclass,access_vector_t av)328 void print_access_vector(security_class_t tclass, access_vector_t av) 329 { 330 const char *permstr; 331 access_vector_t bit = 1; 332 333 if (av == 0) { 334 printf(" null"); 335 return; 336 } 337 338 printf(" {"); 339 340 for (;;) { 341 if (av & bit) { 342 permstr = security_av_perm_to_string(tclass, bit); 343 if (!permstr) 344 break; 345 printf(" %s", permstr); 346 av &= ~bit; 347 if (!av) 348 break; 349 } 350 bit <<= 1; 351 } 352 353 if (av) 354 printf(" 0x%x", av); 355 printf(" }"); 356 } 357