16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * File contexts backend for labeling system 36cd6a6acSopenharmony_ci * 46cd6a6acSopenharmony_ci * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> 56cd6a6acSopenharmony_ci * Author : Stephen Smalley <sds@tycho.nsa.gov> 66cd6a6acSopenharmony_ci */ 76cd6a6acSopenharmony_ci 86cd6a6acSopenharmony_ci#include <assert.h> 96cd6a6acSopenharmony_ci#include <fcntl.h> 106cd6a6acSopenharmony_ci#include <stdarg.h> 116cd6a6acSopenharmony_ci#include <string.h> 126cd6a6acSopenharmony_ci#include <stdio.h> 136cd6a6acSopenharmony_ci#include <ctype.h> 146cd6a6acSopenharmony_ci#include <errno.h> 156cd6a6acSopenharmony_ci#include <limits.h> 166cd6a6acSopenharmony_ci#include <stdint.h> 176cd6a6acSopenharmony_ci#include <unistd.h> 186cd6a6acSopenharmony_ci#include <sys/mman.h> 196cd6a6acSopenharmony_ci#include <sys/types.h> 206cd6a6acSopenharmony_ci#include <sys/stat.h> 216cd6a6acSopenharmony_ci 226cd6a6acSopenharmony_ci#include "callbacks.h" 236cd6a6acSopenharmony_ci#include "label_internal.h" 246cd6a6acSopenharmony_ci#include "label_file.h" 256cd6a6acSopenharmony_ci 266cd6a6acSopenharmony_ci/* 276cd6a6acSopenharmony_ci * Internals, mostly moved over from matchpathcon.c 286cd6a6acSopenharmony_ci */ 296cd6a6acSopenharmony_ci 306cd6a6acSopenharmony_ci/* return the length of the text that is the stem of a file name */ 316cd6a6acSopenharmony_cistatic int get_stem_from_file_name(const char *const buf) 326cd6a6acSopenharmony_ci{ 336cd6a6acSopenharmony_ci const char *tmp = strchr(buf + 1, '/'); 346cd6a6acSopenharmony_ci 356cd6a6acSopenharmony_ci if (!tmp) 366cd6a6acSopenharmony_ci return 0; 376cd6a6acSopenharmony_ci return tmp - buf; 386cd6a6acSopenharmony_ci} 396cd6a6acSopenharmony_ci 406cd6a6acSopenharmony_ci/* find the stem of a file name, returns the index into stem_arr (or -1 if 416cd6a6acSopenharmony_ci * there is no match - IE for a file in the root directory or a regex that is 426cd6a6acSopenharmony_ci * too complex for us). */ 436cd6a6acSopenharmony_cistatic int find_stem_from_file(struct saved_data *data, const char *key) 446cd6a6acSopenharmony_ci{ 456cd6a6acSopenharmony_ci int i; 466cd6a6acSopenharmony_ci int stem_len = get_stem_from_file_name(key); 476cd6a6acSopenharmony_ci 486cd6a6acSopenharmony_ci if (!stem_len) 496cd6a6acSopenharmony_ci return -1; 506cd6a6acSopenharmony_ci for (i = 0; i < data->num_stems; i++) { 516cd6a6acSopenharmony_ci if (stem_len == data->stem_arr[i].len 526cd6a6acSopenharmony_ci && !strncmp(key, data->stem_arr[i].buf, stem_len)) { 536cd6a6acSopenharmony_ci return i; 546cd6a6acSopenharmony_ci } 556cd6a6acSopenharmony_ci } 566cd6a6acSopenharmony_ci return -1; 576cd6a6acSopenharmony_ci} 586cd6a6acSopenharmony_ci 596cd6a6acSopenharmony_ci/* 606cd6a6acSopenharmony_ci * Warn about duplicate specifications. 616cd6a6acSopenharmony_ci */ 626cd6a6acSopenharmony_cistatic int nodups_specs(struct saved_data *data, const char *path) 636cd6a6acSopenharmony_ci{ 646cd6a6acSopenharmony_ci int rc = 0; 656cd6a6acSopenharmony_ci unsigned int ii, jj; 666cd6a6acSopenharmony_ci struct spec *curr_spec, *spec_arr = data->spec_arr; 676cd6a6acSopenharmony_ci 686cd6a6acSopenharmony_ci for (ii = 0; ii < data->nspec; ii++) { 696cd6a6acSopenharmony_ci curr_spec = &spec_arr[ii]; 706cd6a6acSopenharmony_ci for (jj = ii + 1; jj < data->nspec; jj++) { 716cd6a6acSopenharmony_ci if ((!strcmp(spec_arr[jj].regex_str, 726cd6a6acSopenharmony_ci curr_spec->regex_str)) 736cd6a6acSopenharmony_ci && (!spec_arr[jj].mode || !curr_spec->mode 746cd6a6acSopenharmony_ci || spec_arr[jj].mode == curr_spec->mode)) { 756cd6a6acSopenharmony_ci rc = -1; 766cd6a6acSopenharmony_ci errno = EINVAL; 776cd6a6acSopenharmony_ci if (strcmp(spec_arr[jj].lr.ctx_raw, 786cd6a6acSopenharmony_ci curr_spec->lr.ctx_raw)) { 796cd6a6acSopenharmony_ci COMPAT_LOG 806cd6a6acSopenharmony_ci (SELINUX_ERROR, 816cd6a6acSopenharmony_ci "%s: Multiple different specifications for %s (%s and %s).\n", 826cd6a6acSopenharmony_ci path, curr_spec->regex_str, 836cd6a6acSopenharmony_ci spec_arr[jj].lr.ctx_raw, 846cd6a6acSopenharmony_ci curr_spec->lr.ctx_raw); 856cd6a6acSopenharmony_ci } else { 866cd6a6acSopenharmony_ci COMPAT_LOG 876cd6a6acSopenharmony_ci (SELINUX_ERROR, 886cd6a6acSopenharmony_ci "%s: Multiple same specifications for %s.\n", 896cd6a6acSopenharmony_ci path, curr_spec->regex_str); 906cd6a6acSopenharmony_ci } 916cd6a6acSopenharmony_ci } 926cd6a6acSopenharmony_ci } 936cd6a6acSopenharmony_ci } 946cd6a6acSopenharmony_ci return rc; 956cd6a6acSopenharmony_ci} 966cd6a6acSopenharmony_ci 976cd6a6acSopenharmony_cistatic int process_text_file(FILE *fp, const char *prefix, 986cd6a6acSopenharmony_ci struct selabel_handle *rec, const char *path) 996cd6a6acSopenharmony_ci{ 1006cd6a6acSopenharmony_ci int rc; 1016cd6a6acSopenharmony_ci size_t line_len; 1026cd6a6acSopenharmony_ci unsigned int lineno = 0; 1036cd6a6acSopenharmony_ci char *line_buf = NULL; 1046cd6a6acSopenharmony_ci 1056cd6a6acSopenharmony_ci while (getline(&line_buf, &line_len, fp) > 0) { 1066cd6a6acSopenharmony_ci rc = process_line(rec, path, prefix, line_buf, ++lineno); 1076cd6a6acSopenharmony_ci if (rc) 1086cd6a6acSopenharmony_ci goto out; 1096cd6a6acSopenharmony_ci } 1106cd6a6acSopenharmony_ci rc = 0; 1116cd6a6acSopenharmony_ciout: 1126cd6a6acSopenharmony_ci free(line_buf); 1136cd6a6acSopenharmony_ci return rc; 1146cd6a6acSopenharmony_ci} 1156cd6a6acSopenharmony_ci 1166cd6a6acSopenharmony_cistatic int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec, 1176cd6a6acSopenharmony_ci const char *path) 1186cd6a6acSopenharmony_ci{ 1196cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 1206cd6a6acSopenharmony_ci int rc; 1216cd6a6acSopenharmony_ci char *addr, *str_buf; 1226cd6a6acSopenharmony_ci int *stem_map; 1236cd6a6acSopenharmony_ci struct mmap_area *mmap_area; 1246cd6a6acSopenharmony_ci uint32_t i, magic, version; 1256cd6a6acSopenharmony_ci uint32_t entry_len, stem_map_len, regex_array_len; 1266cd6a6acSopenharmony_ci const char *reg_version; 1276cd6a6acSopenharmony_ci const char *reg_arch; 1286cd6a6acSopenharmony_ci char reg_arch_matches = 0; 1296cd6a6acSopenharmony_ci 1306cd6a6acSopenharmony_ci mmap_area = malloc(sizeof(*mmap_area)); 1316cd6a6acSopenharmony_ci if (!mmap_area) { 1326cd6a6acSopenharmony_ci return -1; 1336cd6a6acSopenharmony_ci } 1346cd6a6acSopenharmony_ci 1356cd6a6acSopenharmony_ci addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0); 1366cd6a6acSopenharmony_ci if (addr == MAP_FAILED) { 1376cd6a6acSopenharmony_ci free(mmap_area); 1386cd6a6acSopenharmony_ci perror("mmap"); 1396cd6a6acSopenharmony_ci return -1; 1406cd6a6acSopenharmony_ci } 1416cd6a6acSopenharmony_ci 1426cd6a6acSopenharmony_ci /* save where we mmap'd the file to cleanup on close() */ 1436cd6a6acSopenharmony_ci mmap_area->addr = mmap_area->next_addr = addr; 1446cd6a6acSopenharmony_ci mmap_area->len = mmap_area->next_len = len; 1456cd6a6acSopenharmony_ci mmap_area->next = data->mmap_areas; 1466cd6a6acSopenharmony_ci data->mmap_areas = mmap_area; 1476cd6a6acSopenharmony_ci 1486cd6a6acSopenharmony_ci /* check if this looks like an fcontext file */ 1496cd6a6acSopenharmony_ci rc = next_entry(&magic, mmap_area, sizeof(uint32_t)); 1506cd6a6acSopenharmony_ci if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) 1516cd6a6acSopenharmony_ci return -1; 1526cd6a6acSopenharmony_ci 1536cd6a6acSopenharmony_ci /* check if this version is higher than we understand */ 1546cd6a6acSopenharmony_ci rc = next_entry(&version, mmap_area, sizeof(uint32_t)); 1556cd6a6acSopenharmony_ci if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) 1566cd6a6acSopenharmony_ci return -1; 1576cd6a6acSopenharmony_ci 1586cd6a6acSopenharmony_ci reg_version = regex_version(); 1596cd6a6acSopenharmony_ci if (!reg_version) 1606cd6a6acSopenharmony_ci return -1; 1616cd6a6acSopenharmony_ci 1626cd6a6acSopenharmony_ci reg_arch = regex_arch_string(); 1636cd6a6acSopenharmony_ci if (!reg_arch) 1646cd6a6acSopenharmony_ci return -1; 1656cd6a6acSopenharmony_ci 1666cd6a6acSopenharmony_ci if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { 1676cd6a6acSopenharmony_ci 1686cd6a6acSopenharmony_ci len = strlen(reg_version); 1696cd6a6acSopenharmony_ci 1706cd6a6acSopenharmony_ci rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); 1716cd6a6acSopenharmony_ci if (rc < 0) 1726cd6a6acSopenharmony_ci return -1; 1736cd6a6acSopenharmony_ci 1746cd6a6acSopenharmony_ci /* Check version lengths */ 1756cd6a6acSopenharmony_ci if (len != entry_len) 1766cd6a6acSopenharmony_ci return -1; 1776cd6a6acSopenharmony_ci 1786cd6a6acSopenharmony_ci /* Check if regex version mismatch */ 1796cd6a6acSopenharmony_ci str_buf = malloc(entry_len + 1); 1806cd6a6acSopenharmony_ci if (!str_buf) 1816cd6a6acSopenharmony_ci return -1; 1826cd6a6acSopenharmony_ci 1836cd6a6acSopenharmony_ci rc = next_entry(str_buf, mmap_area, entry_len); 1846cd6a6acSopenharmony_ci if (rc < 0) { 1856cd6a6acSopenharmony_ci free(str_buf); 1866cd6a6acSopenharmony_ci return -1; 1876cd6a6acSopenharmony_ci } 1886cd6a6acSopenharmony_ci 1896cd6a6acSopenharmony_ci str_buf[entry_len] = '\0'; 1906cd6a6acSopenharmony_ci if ((strcmp(str_buf, reg_version) != 0)) { 1916cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_ERROR, 1926cd6a6acSopenharmony_ci "Regex version mismatch, expected: %s actual: %s\n", 1936cd6a6acSopenharmony_ci reg_version, str_buf); 1946cd6a6acSopenharmony_ci free(str_buf); 1956cd6a6acSopenharmony_ci return -1; 1966cd6a6acSopenharmony_ci } 1976cd6a6acSopenharmony_ci free(str_buf); 1986cd6a6acSopenharmony_ci 1996cd6a6acSopenharmony_ci if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) { 2006cd6a6acSopenharmony_ci len = strlen(reg_arch); 2016cd6a6acSopenharmony_ci 2026cd6a6acSopenharmony_ci rc = next_entry(&entry_len, mmap_area, 2036cd6a6acSopenharmony_ci sizeof(uint32_t)); 2046cd6a6acSopenharmony_ci if (rc < 0) 2056cd6a6acSopenharmony_ci return -1; 2066cd6a6acSopenharmony_ci 2076cd6a6acSopenharmony_ci /* Check arch string lengths */ 2086cd6a6acSopenharmony_ci if (len != entry_len) { 2096cd6a6acSopenharmony_ci /* 2106cd6a6acSopenharmony_ci * Skip the entry and conclude that we have 2116cd6a6acSopenharmony_ci * a mismatch, which is not fatal. 2126cd6a6acSopenharmony_ci */ 2136cd6a6acSopenharmony_ci next_entry(NULL, mmap_area, entry_len); 2146cd6a6acSopenharmony_ci goto end_arch_check; 2156cd6a6acSopenharmony_ci } 2166cd6a6acSopenharmony_ci 2176cd6a6acSopenharmony_ci /* Check if arch string mismatch */ 2186cd6a6acSopenharmony_ci str_buf = malloc(entry_len + 1); 2196cd6a6acSopenharmony_ci if (!str_buf) 2206cd6a6acSopenharmony_ci return -1; 2216cd6a6acSopenharmony_ci 2226cd6a6acSopenharmony_ci rc = next_entry(str_buf, mmap_area, entry_len); 2236cd6a6acSopenharmony_ci if (rc < 0) { 2246cd6a6acSopenharmony_ci free(str_buf); 2256cd6a6acSopenharmony_ci return -1; 2266cd6a6acSopenharmony_ci } 2276cd6a6acSopenharmony_ci 2286cd6a6acSopenharmony_ci str_buf[entry_len] = '\0'; 2296cd6a6acSopenharmony_ci reg_arch_matches = strcmp(str_buf, reg_arch) == 0; 2306cd6a6acSopenharmony_ci free(str_buf); 2316cd6a6acSopenharmony_ci } 2326cd6a6acSopenharmony_ci } 2336cd6a6acSopenharmony_ciend_arch_check: 2346cd6a6acSopenharmony_ci 2356cd6a6acSopenharmony_ci /* allocate the stems_data array */ 2366cd6a6acSopenharmony_ci rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t)); 2376cd6a6acSopenharmony_ci if (rc < 0) 2386cd6a6acSopenharmony_ci return -1; 2396cd6a6acSopenharmony_ci 2406cd6a6acSopenharmony_ci /* 2416cd6a6acSopenharmony_ci * map indexed by the stem # in the mmap file and contains the stem 2426cd6a6acSopenharmony_ci * number in the data stem_arr 2436cd6a6acSopenharmony_ci */ 2446cd6a6acSopenharmony_ci stem_map = calloc(stem_map_len, sizeof(*stem_map)); 2456cd6a6acSopenharmony_ci if (!stem_map) 2466cd6a6acSopenharmony_ci return -1; 2476cd6a6acSopenharmony_ci 2486cd6a6acSopenharmony_ci for (i = 0; i < stem_map_len; i++) { 2496cd6a6acSopenharmony_ci char *buf; 2506cd6a6acSopenharmony_ci uint32_t stem_len; 2516cd6a6acSopenharmony_ci int newid; 2526cd6a6acSopenharmony_ci 2536cd6a6acSopenharmony_ci /* the length does not include the nul */ 2546cd6a6acSopenharmony_ci rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); 2556cd6a6acSopenharmony_ci if (rc < 0 || !stem_len) { 2566cd6a6acSopenharmony_ci rc = -1; 2576cd6a6acSopenharmony_ci goto out; 2586cd6a6acSopenharmony_ci } 2596cd6a6acSopenharmony_ci 2606cd6a6acSopenharmony_ci /* Check for stem_len wrap around. */ 2616cd6a6acSopenharmony_ci if (stem_len < UINT32_MAX) { 2626cd6a6acSopenharmony_ci buf = (char *)mmap_area->next_addr; 2636cd6a6acSopenharmony_ci /* Check if over-run before null check. */ 2646cd6a6acSopenharmony_ci rc = next_entry(NULL, mmap_area, (stem_len + 1)); 2656cd6a6acSopenharmony_ci if (rc < 0) 2666cd6a6acSopenharmony_ci goto out; 2676cd6a6acSopenharmony_ci 2686cd6a6acSopenharmony_ci if (buf[stem_len] != '\0') { 2696cd6a6acSopenharmony_ci rc = -1; 2706cd6a6acSopenharmony_ci goto out; 2716cd6a6acSopenharmony_ci } 2726cd6a6acSopenharmony_ci } else { 2736cd6a6acSopenharmony_ci rc = -1; 2746cd6a6acSopenharmony_ci goto out; 2756cd6a6acSopenharmony_ci } 2766cd6a6acSopenharmony_ci 2776cd6a6acSopenharmony_ci /* store the mapping between old and new */ 2786cd6a6acSopenharmony_ci newid = find_stem(data, buf, stem_len); 2796cd6a6acSopenharmony_ci if (newid < 0) { 2806cd6a6acSopenharmony_ci newid = store_stem(data, buf, stem_len); 2816cd6a6acSopenharmony_ci if (newid < 0) { 2826cd6a6acSopenharmony_ci rc = newid; 2836cd6a6acSopenharmony_ci goto out; 2846cd6a6acSopenharmony_ci } 2856cd6a6acSopenharmony_ci data->stem_arr[newid].from_mmap = 1; 2866cd6a6acSopenharmony_ci } 2876cd6a6acSopenharmony_ci stem_map[i] = newid; 2886cd6a6acSopenharmony_ci } 2896cd6a6acSopenharmony_ci 2906cd6a6acSopenharmony_ci /* allocate the regex array */ 2916cd6a6acSopenharmony_ci rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); 2926cd6a6acSopenharmony_ci if (rc < 0 || !regex_array_len) { 2936cd6a6acSopenharmony_ci rc = -1; 2946cd6a6acSopenharmony_ci goto out; 2956cd6a6acSopenharmony_ci } 2966cd6a6acSopenharmony_ci 2976cd6a6acSopenharmony_ci for (i = 0; i < regex_array_len; i++) { 2986cd6a6acSopenharmony_ci struct spec *spec; 2996cd6a6acSopenharmony_ci int32_t stem_id, meta_chars; 3006cd6a6acSopenharmony_ci uint32_t mode = 0, prefix_len = 0; 3016cd6a6acSopenharmony_ci 3026cd6a6acSopenharmony_ci rc = grow_specs(data); 3036cd6a6acSopenharmony_ci if (rc < 0) 3046cd6a6acSopenharmony_ci goto out; 3056cd6a6acSopenharmony_ci 3066cd6a6acSopenharmony_ci spec = &data->spec_arr[data->nspec]; 3076cd6a6acSopenharmony_ci spec->from_mmap = 1; 3086cd6a6acSopenharmony_ci 3096cd6a6acSopenharmony_ci /* Process context */ 3106cd6a6acSopenharmony_ci rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); 3116cd6a6acSopenharmony_ci if (rc < 0 || !entry_len) { 3126cd6a6acSopenharmony_ci rc = -1; 3136cd6a6acSopenharmony_ci goto out; 3146cd6a6acSopenharmony_ci } 3156cd6a6acSopenharmony_ci 3166cd6a6acSopenharmony_ci str_buf = malloc(entry_len); 3176cd6a6acSopenharmony_ci if (!str_buf) { 3186cd6a6acSopenharmony_ci rc = -1; 3196cd6a6acSopenharmony_ci goto out; 3206cd6a6acSopenharmony_ci } 3216cd6a6acSopenharmony_ci rc = next_entry(str_buf, mmap_area, entry_len); 3226cd6a6acSopenharmony_ci if (rc < 0) { 3236cd6a6acSopenharmony_ci free(str_buf); 3246cd6a6acSopenharmony_ci goto out; 3256cd6a6acSopenharmony_ci } 3266cd6a6acSopenharmony_ci 3276cd6a6acSopenharmony_ci if (str_buf[entry_len - 1] != '\0') { 3286cd6a6acSopenharmony_ci free(str_buf); 3296cd6a6acSopenharmony_ci rc = -1; 3306cd6a6acSopenharmony_ci goto out; 3316cd6a6acSopenharmony_ci } 3326cd6a6acSopenharmony_ci spec->lr.ctx_raw = str_buf; 3336cd6a6acSopenharmony_ci 3346cd6a6acSopenharmony_ci if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) { 3356cd6a6acSopenharmony_ci if (selabel_validate(rec, &spec->lr) < 0) { 3366cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, 3376cd6a6acSopenharmony_ci "%s: context %s is invalid\n", 3386cd6a6acSopenharmony_ci path, spec->lr.ctx_raw); 3396cd6a6acSopenharmony_ci goto out; 3406cd6a6acSopenharmony_ci } 3416cd6a6acSopenharmony_ci } 3426cd6a6acSopenharmony_ci 3436cd6a6acSopenharmony_ci /* Process regex string */ 3446cd6a6acSopenharmony_ci rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); 3456cd6a6acSopenharmony_ci if (rc < 0 || !entry_len) { 3466cd6a6acSopenharmony_ci rc = -1; 3476cd6a6acSopenharmony_ci goto out; 3486cd6a6acSopenharmony_ci } 3496cd6a6acSopenharmony_ci 3506cd6a6acSopenharmony_ci spec->regex_str = (char *)mmap_area->next_addr; 3516cd6a6acSopenharmony_ci rc = next_entry(NULL, mmap_area, entry_len); 3526cd6a6acSopenharmony_ci if (rc < 0) 3536cd6a6acSopenharmony_ci goto out; 3546cd6a6acSopenharmony_ci 3556cd6a6acSopenharmony_ci if (spec->regex_str[entry_len - 1] != '\0') { 3566cd6a6acSopenharmony_ci rc = -1; 3576cd6a6acSopenharmony_ci goto out; 3586cd6a6acSopenharmony_ci } 3596cd6a6acSopenharmony_ci 3606cd6a6acSopenharmony_ci /* Process mode */ 3616cd6a6acSopenharmony_ci if (version >= SELINUX_COMPILED_FCONTEXT_MODE) 3626cd6a6acSopenharmony_ci rc = next_entry(&mode, mmap_area, sizeof(uint32_t)); 3636cd6a6acSopenharmony_ci else 3646cd6a6acSopenharmony_ci rc = next_entry(&mode, mmap_area, sizeof(mode_t)); 3656cd6a6acSopenharmony_ci if (rc < 0) 3666cd6a6acSopenharmony_ci goto out; 3676cd6a6acSopenharmony_ci 3686cd6a6acSopenharmony_ci spec->mode = mode; 3696cd6a6acSopenharmony_ci 3706cd6a6acSopenharmony_ci /* map the stem id from the mmap file to the data->stem_arr */ 3716cd6a6acSopenharmony_ci rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); 3726cd6a6acSopenharmony_ci if (rc < 0) 3736cd6a6acSopenharmony_ci goto out; 3746cd6a6acSopenharmony_ci 3756cd6a6acSopenharmony_ci if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) 3766cd6a6acSopenharmony_ci spec->stem_id = -1; 3776cd6a6acSopenharmony_ci else 3786cd6a6acSopenharmony_ci spec->stem_id = stem_map[stem_id]; 3796cd6a6acSopenharmony_ci 3806cd6a6acSopenharmony_ci /* retrieve the hasMetaChars bit */ 3816cd6a6acSopenharmony_ci rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); 3826cd6a6acSopenharmony_ci if (rc < 0) 3836cd6a6acSopenharmony_ci goto out; 3846cd6a6acSopenharmony_ci 3856cd6a6acSopenharmony_ci spec->hasMetaChars = meta_chars; 3866cd6a6acSopenharmony_ci /* and prefix length for use by selabel_lookup_best_match */ 3876cd6a6acSopenharmony_ci if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) { 3886cd6a6acSopenharmony_ci rc = next_entry(&prefix_len, mmap_area, 3896cd6a6acSopenharmony_ci sizeof(uint32_t)); 3906cd6a6acSopenharmony_ci if (rc < 0) 3916cd6a6acSopenharmony_ci goto out; 3926cd6a6acSopenharmony_ci 3936cd6a6acSopenharmony_ci spec->prefix_len = prefix_len; 3946cd6a6acSopenharmony_ci } 3956cd6a6acSopenharmony_ci 3966cd6a6acSopenharmony_ci rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches, 3976cd6a6acSopenharmony_ci &spec->regex_compiled); 3986cd6a6acSopenharmony_ci if (rc < 0) 3996cd6a6acSopenharmony_ci goto out; 4006cd6a6acSopenharmony_ci 4016cd6a6acSopenharmony_ci __pthread_mutex_init(&spec->regex_lock, NULL); 4026cd6a6acSopenharmony_ci data->nspec++; 4036cd6a6acSopenharmony_ci } 4046cd6a6acSopenharmony_ci 4056cd6a6acSopenharmony_ci rc = 0; 4066cd6a6acSopenharmony_ciout: 4076cd6a6acSopenharmony_ci free(stem_map); 4086cd6a6acSopenharmony_ci 4096cd6a6acSopenharmony_ci return rc; 4106cd6a6acSopenharmony_ci} 4116cd6a6acSopenharmony_ci 4126cd6a6acSopenharmony_cistruct file_details { 4136cd6a6acSopenharmony_ci const char *suffix; 4146cd6a6acSopenharmony_ci struct stat sb; 4156cd6a6acSopenharmony_ci}; 4166cd6a6acSopenharmony_ci 4176cd6a6acSopenharmony_cistatic char *rolling_append(char *current, const char *suffix, size_t max) 4186cd6a6acSopenharmony_ci{ 4196cd6a6acSopenharmony_ci size_t size; 4206cd6a6acSopenharmony_ci size_t suffix_size; 4216cd6a6acSopenharmony_ci size_t current_size; 4226cd6a6acSopenharmony_ci 4236cd6a6acSopenharmony_ci if (!suffix) 4246cd6a6acSopenharmony_ci return current; 4256cd6a6acSopenharmony_ci 4266cd6a6acSopenharmony_ci current_size = strlen(current); 4276cd6a6acSopenharmony_ci suffix_size = strlen(suffix); 4286cd6a6acSopenharmony_ci 4296cd6a6acSopenharmony_ci size = current_size + suffix_size; 4306cd6a6acSopenharmony_ci if (size < current_size || size < suffix_size) 4316cd6a6acSopenharmony_ci return NULL; 4326cd6a6acSopenharmony_ci 4336cd6a6acSopenharmony_ci /* ensure space for the '.' and the '\0' characters. */ 4346cd6a6acSopenharmony_ci if (size >= (SIZE_MAX - 2)) 4356cd6a6acSopenharmony_ci return NULL; 4366cd6a6acSopenharmony_ci 4376cd6a6acSopenharmony_ci size += 2; 4386cd6a6acSopenharmony_ci 4396cd6a6acSopenharmony_ci if (size > max) 4406cd6a6acSopenharmony_ci return NULL; 4416cd6a6acSopenharmony_ci 4426cd6a6acSopenharmony_ci /* Append any given suffix */ 4436cd6a6acSopenharmony_ci char *to = current + current_size; 4446cd6a6acSopenharmony_ci *to++ = '.'; 4456cd6a6acSopenharmony_ci strcpy(to, suffix); 4466cd6a6acSopenharmony_ci 4476cd6a6acSopenharmony_ci return current; 4486cd6a6acSopenharmony_ci} 4496cd6a6acSopenharmony_ci 4506cd6a6acSopenharmony_cistatic bool fcontext_is_binary(FILE *fp) 4516cd6a6acSopenharmony_ci{ 4526cd6a6acSopenharmony_ci uint32_t magic; 4536cd6a6acSopenharmony_ci 4546cd6a6acSopenharmony_ci size_t len = fread(&magic, sizeof(magic), 1, fp); 4556cd6a6acSopenharmony_ci rewind(fp); 4566cd6a6acSopenharmony_ci 4576cd6a6acSopenharmony_ci return (len && (magic == SELINUX_MAGIC_COMPILED_FCONTEXT)); 4586cd6a6acSopenharmony_ci} 4596cd6a6acSopenharmony_ci 4606cd6a6acSopenharmony_ci#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 4616cd6a6acSopenharmony_ci 4626cd6a6acSopenharmony_cistatic FILE *open_file(const char *path, const char *suffix, 4636cd6a6acSopenharmony_ci char *save_path, size_t len, struct stat *sb, bool open_oldest) 4646cd6a6acSopenharmony_ci{ 4656cd6a6acSopenharmony_ci unsigned int i; 4666cd6a6acSopenharmony_ci int rc; 4676cd6a6acSopenharmony_ci char stack_path[len]; 4686cd6a6acSopenharmony_ci struct file_details *found = NULL; 4696cd6a6acSopenharmony_ci 4706cd6a6acSopenharmony_ci /* 4716cd6a6acSopenharmony_ci * Rolling append of suffix. Try to open with path.suffix then the 4726cd6a6acSopenharmony_ci * next as path.suffix.suffix and so forth. 4736cd6a6acSopenharmony_ci */ 4746cd6a6acSopenharmony_ci struct file_details fdetails[2] = { 4756cd6a6acSopenharmony_ci { .suffix = suffix }, 4766cd6a6acSopenharmony_ci { .suffix = "bin" } 4776cd6a6acSopenharmony_ci }; 4786cd6a6acSopenharmony_ci 4796cd6a6acSopenharmony_ci rc = snprintf(stack_path, sizeof(stack_path), "%s", path); 4806cd6a6acSopenharmony_ci if (rc >= (int) sizeof(stack_path)) { 4816cd6a6acSopenharmony_ci errno = ENAMETOOLONG; 4826cd6a6acSopenharmony_ci return NULL; 4836cd6a6acSopenharmony_ci } 4846cd6a6acSopenharmony_ci 4856cd6a6acSopenharmony_ci for (i = 0; i < ARRAY_SIZE(fdetails); i++) { 4866cd6a6acSopenharmony_ci 4876cd6a6acSopenharmony_ci /* This handles the case if suffix is null */ 4886cd6a6acSopenharmony_ci path = rolling_append(stack_path, fdetails[i].suffix, 4896cd6a6acSopenharmony_ci sizeof(stack_path)); 4906cd6a6acSopenharmony_ci if (!path) 4916cd6a6acSopenharmony_ci return NULL; 4926cd6a6acSopenharmony_ci 4936cd6a6acSopenharmony_ci rc = stat(path, &fdetails[i].sb); 4946cd6a6acSopenharmony_ci if (rc) 4956cd6a6acSopenharmony_ci continue; 4966cd6a6acSopenharmony_ci 4976cd6a6acSopenharmony_ci /* first file thing found, just take it */ 4986cd6a6acSopenharmony_ci if (!found) { 4996cd6a6acSopenharmony_ci strcpy(save_path, path); 5006cd6a6acSopenharmony_ci found = &fdetails[i]; 5016cd6a6acSopenharmony_ci continue; 5026cd6a6acSopenharmony_ci } 5036cd6a6acSopenharmony_ci 5046cd6a6acSopenharmony_ci /* 5056cd6a6acSopenharmony_ci * Keep picking the newest file found. Where "newest" 5066cd6a6acSopenharmony_ci * includes equality. This provides a precedence on 5076cd6a6acSopenharmony_ci * secondary suffixes even when the timestamp is the 5086cd6a6acSopenharmony_ci * same. Ie choose file_contexts.bin over file_contexts 5096cd6a6acSopenharmony_ci * even if the time stamp is the same. Invert this logic 5106cd6a6acSopenharmony_ci * on open_oldest set to true. The idea is that if the 5116cd6a6acSopenharmony_ci * newest file failed to process, we can attempt to 5126cd6a6acSopenharmony_ci * process the oldest. The logic here is subtle and depends 5136cd6a6acSopenharmony_ci * on the array ordering in fdetails for the case when time 5146cd6a6acSopenharmony_ci * stamps are the same. 5156cd6a6acSopenharmony_ci */ 5166cd6a6acSopenharmony_ci if (open_oldest ^ 5176cd6a6acSopenharmony_ci (fdetails[i].sb.st_mtime >= found->sb.st_mtime)) { 5186cd6a6acSopenharmony_ci found = &fdetails[i]; 5196cd6a6acSopenharmony_ci strcpy(save_path, path); 5206cd6a6acSopenharmony_ci } 5216cd6a6acSopenharmony_ci } 5226cd6a6acSopenharmony_ci 5236cd6a6acSopenharmony_ci if (!found) { 5246cd6a6acSopenharmony_ci errno = ENOENT; 5256cd6a6acSopenharmony_ci return NULL; 5266cd6a6acSopenharmony_ci } 5276cd6a6acSopenharmony_ci 5286cd6a6acSopenharmony_ci memcpy(sb, &found->sb, sizeof(*sb)); 5296cd6a6acSopenharmony_ci return fopen(save_path, "re"); 5306cd6a6acSopenharmony_ci} 5316cd6a6acSopenharmony_ci 5326cd6a6acSopenharmony_cistatic int process_file(const char *path, const char *suffix, 5336cd6a6acSopenharmony_ci struct selabel_handle *rec, 5346cd6a6acSopenharmony_ci const char *prefix, struct selabel_digest *digest) 5356cd6a6acSopenharmony_ci{ 5366cd6a6acSopenharmony_ci int rc; 5376cd6a6acSopenharmony_ci unsigned int i; 5386cd6a6acSopenharmony_ci struct stat sb; 5396cd6a6acSopenharmony_ci FILE *fp = NULL; 5406cd6a6acSopenharmony_ci char found_path[PATH_MAX]; 5416cd6a6acSopenharmony_ci 5426cd6a6acSopenharmony_ci /* 5436cd6a6acSopenharmony_ci * On the first pass open the newest modified file. If it fails to 5446cd6a6acSopenharmony_ci * process, then the second pass shall open the oldest file. If both 5456cd6a6acSopenharmony_ci * passes fail, then it's a fatal error. 5466cd6a6acSopenharmony_ci */ 5476cd6a6acSopenharmony_ci for (i = 0; i < 2; i++) { 5486cd6a6acSopenharmony_ci fp = open_file(path, suffix, found_path, sizeof(found_path), 5496cd6a6acSopenharmony_ci &sb, i > 0); 5506cd6a6acSopenharmony_ci if (fp == NULL) 5516cd6a6acSopenharmony_ci return -1; 5526cd6a6acSopenharmony_ci 5536cd6a6acSopenharmony_ci rc = fcontext_is_binary(fp) ? 5546cd6a6acSopenharmony_ci load_mmap(fp, sb.st_size, rec, found_path) : 5556cd6a6acSopenharmony_ci process_text_file(fp, prefix, rec, found_path); 5566cd6a6acSopenharmony_ci if (!rc) 5576cd6a6acSopenharmony_ci rc = digest_add_specfile(digest, fp, NULL, sb.st_size, 5586cd6a6acSopenharmony_ci found_path); 5596cd6a6acSopenharmony_ci 5606cd6a6acSopenharmony_ci fclose(fp); 5616cd6a6acSopenharmony_ci 5626cd6a6acSopenharmony_ci if (!rc) 5636cd6a6acSopenharmony_ci return 0; 5646cd6a6acSopenharmony_ci } 5656cd6a6acSopenharmony_ci return -1; 5666cd6a6acSopenharmony_ci} 5676cd6a6acSopenharmony_ci 5686cd6a6acSopenharmony_cistatic void selabel_subs_fini(struct selabel_sub *ptr) 5696cd6a6acSopenharmony_ci{ 5706cd6a6acSopenharmony_ci struct selabel_sub *next; 5716cd6a6acSopenharmony_ci 5726cd6a6acSopenharmony_ci while (ptr) { 5736cd6a6acSopenharmony_ci next = ptr->next; 5746cd6a6acSopenharmony_ci free(ptr->src); 5756cd6a6acSopenharmony_ci free(ptr->dst); 5766cd6a6acSopenharmony_ci free(ptr); 5776cd6a6acSopenharmony_ci ptr = next; 5786cd6a6acSopenharmony_ci } 5796cd6a6acSopenharmony_ci} 5806cd6a6acSopenharmony_ci 5816cd6a6acSopenharmony_cistatic char *selabel_sub(struct selabel_sub *ptr, const char *src) 5826cd6a6acSopenharmony_ci{ 5836cd6a6acSopenharmony_ci char *dst = NULL; 5846cd6a6acSopenharmony_ci int len; 5856cd6a6acSopenharmony_ci 5866cd6a6acSopenharmony_ci while (ptr) { 5876cd6a6acSopenharmony_ci if (strncmp(src, ptr->src, ptr->slen) == 0 ) { 5886cd6a6acSopenharmony_ci if (src[ptr->slen] == '/' || 5896cd6a6acSopenharmony_ci src[ptr->slen] == 0) { 5906cd6a6acSopenharmony_ci if ((src[ptr->slen] == '/') && 5916cd6a6acSopenharmony_ci (strcmp(ptr->dst, "/") == 0)) 5926cd6a6acSopenharmony_ci len = ptr->slen + 1; 5936cd6a6acSopenharmony_ci else 5946cd6a6acSopenharmony_ci len = ptr->slen; 5956cd6a6acSopenharmony_ci if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0) 5966cd6a6acSopenharmony_ci return NULL; 5976cd6a6acSopenharmony_ci return dst; 5986cd6a6acSopenharmony_ci } 5996cd6a6acSopenharmony_ci } 6006cd6a6acSopenharmony_ci ptr = ptr->next; 6016cd6a6acSopenharmony_ci } 6026cd6a6acSopenharmony_ci return NULL; 6036cd6a6acSopenharmony_ci} 6046cd6a6acSopenharmony_ci 6056cd6a6acSopenharmony_cistatic int selabel_subs_init(const char *path, struct selabel_digest *digest, 6066cd6a6acSopenharmony_ci struct selabel_sub **out_subs) 6076cd6a6acSopenharmony_ci{ 6086cd6a6acSopenharmony_ci char buf[1024]; 6096cd6a6acSopenharmony_ci FILE *cfg = fopen(path, "re"); 6106cd6a6acSopenharmony_ci struct selabel_sub *list = NULL, *sub = NULL; 6116cd6a6acSopenharmony_ci struct stat sb; 6126cd6a6acSopenharmony_ci int status = -1; 6136cd6a6acSopenharmony_ci 6146cd6a6acSopenharmony_ci *out_subs = NULL; 6156cd6a6acSopenharmony_ci if (!cfg) { 6166cd6a6acSopenharmony_ci /* If the file does not exist, it is not fatal */ 6176cd6a6acSopenharmony_ci return (errno == ENOENT) ? 0 : -1; 6186cd6a6acSopenharmony_ci } 6196cd6a6acSopenharmony_ci 6206cd6a6acSopenharmony_ci if (fstat(fileno(cfg), &sb) < 0) 6216cd6a6acSopenharmony_ci goto out; 6226cd6a6acSopenharmony_ci 6236cd6a6acSopenharmony_ci while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) { 6246cd6a6acSopenharmony_ci char *ptr = NULL; 6256cd6a6acSopenharmony_ci char *src = buf; 6266cd6a6acSopenharmony_ci char *dst = NULL; 6276cd6a6acSopenharmony_ci 6286cd6a6acSopenharmony_ci while (*src && isspace(*src)) 6296cd6a6acSopenharmony_ci src++; 6306cd6a6acSopenharmony_ci if (src[0] == '#') continue; 6316cd6a6acSopenharmony_ci ptr = src; 6326cd6a6acSopenharmony_ci while (*ptr && ! isspace(*ptr)) 6336cd6a6acSopenharmony_ci ptr++; 6346cd6a6acSopenharmony_ci *ptr++ = '\0'; 6356cd6a6acSopenharmony_ci if (! *src) continue; 6366cd6a6acSopenharmony_ci 6376cd6a6acSopenharmony_ci dst = ptr; 6386cd6a6acSopenharmony_ci while (*dst && isspace(*dst)) 6396cd6a6acSopenharmony_ci dst++; 6406cd6a6acSopenharmony_ci ptr = dst; 6416cd6a6acSopenharmony_ci while (*ptr && ! isspace(*ptr)) 6426cd6a6acSopenharmony_ci ptr++; 6436cd6a6acSopenharmony_ci *ptr = '\0'; 6446cd6a6acSopenharmony_ci if (! *dst) 6456cd6a6acSopenharmony_ci continue; 6466cd6a6acSopenharmony_ci 6476cd6a6acSopenharmony_ci sub = malloc(sizeof(*sub)); 6486cd6a6acSopenharmony_ci if (! sub) 6496cd6a6acSopenharmony_ci goto err; 6506cd6a6acSopenharmony_ci memset(sub, 0, sizeof(*sub)); 6516cd6a6acSopenharmony_ci 6526cd6a6acSopenharmony_ci sub->src = strdup(src); 6536cd6a6acSopenharmony_ci if (! sub->src) 6546cd6a6acSopenharmony_ci goto err; 6556cd6a6acSopenharmony_ci 6566cd6a6acSopenharmony_ci sub->dst = strdup(dst); 6576cd6a6acSopenharmony_ci if (! sub->dst) 6586cd6a6acSopenharmony_ci goto err; 6596cd6a6acSopenharmony_ci 6606cd6a6acSopenharmony_ci sub->slen = strlen(src); 6616cd6a6acSopenharmony_ci sub->next = list; 6626cd6a6acSopenharmony_ci list = sub; 6636cd6a6acSopenharmony_ci sub = NULL; 6646cd6a6acSopenharmony_ci } 6656cd6a6acSopenharmony_ci 6666cd6a6acSopenharmony_ci if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0) 6676cd6a6acSopenharmony_ci goto err; 6686cd6a6acSopenharmony_ci 6696cd6a6acSopenharmony_ci *out_subs = list; 6706cd6a6acSopenharmony_ci status = 0; 6716cd6a6acSopenharmony_ci 6726cd6a6acSopenharmony_ciout: 6736cd6a6acSopenharmony_ci fclose(cfg); 6746cd6a6acSopenharmony_ci return status; 6756cd6a6acSopenharmony_cierr: 6766cd6a6acSopenharmony_ci if (sub) 6776cd6a6acSopenharmony_ci free(sub->src); 6786cd6a6acSopenharmony_ci free(sub); 6796cd6a6acSopenharmony_ci while (list) { 6806cd6a6acSopenharmony_ci sub = list->next; 6816cd6a6acSopenharmony_ci free(list->src); 6826cd6a6acSopenharmony_ci free(list->dst); 6836cd6a6acSopenharmony_ci free(list); 6846cd6a6acSopenharmony_ci list = sub; 6856cd6a6acSopenharmony_ci } 6866cd6a6acSopenharmony_ci goto out; 6876cd6a6acSopenharmony_ci} 6886cd6a6acSopenharmony_ci 6896cd6a6acSopenharmony_cistatic char *selabel_sub_key(struct saved_data *data, const char *key) 6906cd6a6acSopenharmony_ci{ 6916cd6a6acSopenharmony_ci char *ptr = NULL; 6926cd6a6acSopenharmony_ci char *dptr = NULL; 6936cd6a6acSopenharmony_ci 6946cd6a6acSopenharmony_ci ptr = selabel_sub(data->subs, key); 6956cd6a6acSopenharmony_ci if (ptr) { 6966cd6a6acSopenharmony_ci dptr = selabel_sub(data->dist_subs, ptr); 6976cd6a6acSopenharmony_ci if (dptr) { 6986cd6a6acSopenharmony_ci free(ptr); 6996cd6a6acSopenharmony_ci ptr = dptr; 7006cd6a6acSopenharmony_ci } 7016cd6a6acSopenharmony_ci } else { 7026cd6a6acSopenharmony_ci ptr = selabel_sub(data->dist_subs, key); 7036cd6a6acSopenharmony_ci } 7046cd6a6acSopenharmony_ci if (ptr) 7056cd6a6acSopenharmony_ci return ptr; 7066cd6a6acSopenharmony_ci 7076cd6a6acSopenharmony_ci return NULL; 7086cd6a6acSopenharmony_ci} 7096cd6a6acSopenharmony_ci 7106cd6a6acSopenharmony_cistatic void closef(struct selabel_handle *rec); 7116cd6a6acSopenharmony_ci 7126cd6a6acSopenharmony_ci#ifdef OHOS_FC_INIT 7136cd6a6acSopenharmony_cistatic int init(struct selabel_handle *rec, const struct selinux_opt *opts, unsigned n) 7146cd6a6acSopenharmony_ci{ 7156cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 7166cd6a6acSopenharmony_ci const char *prefix = NULL; 7176cd6a6acSopenharmony_ci int status = -1; 7186cd6a6acSopenharmony_ci size_t path_nums = 0; 7196cd6a6acSopenharmony_ci size_t opt_nums = n; 7206cd6a6acSopenharmony_ci 7216cd6a6acSopenharmony_ci while (n--) { 7226cd6a6acSopenharmony_ci switch (opts[n].type) { 7236cd6a6acSopenharmony_ci case SELABEL_OPT_PATH: 7246cd6a6acSopenharmony_ci path_nums++; 7256cd6a6acSopenharmony_ci break; 7266cd6a6acSopenharmony_ci default: 7276cd6a6acSopenharmony_ci break; 7286cd6a6acSopenharmony_ci } 7296cd6a6acSopenharmony_ci } 7306cd6a6acSopenharmony_ci 7316cd6a6acSopenharmony_ci if (path_nums == 0) { 7326cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, "No specific file_contexts provided\n"); 7336cd6a6acSopenharmony_ci goto finish; 7346cd6a6acSopenharmony_ci } 7356cd6a6acSopenharmony_ci 7366cd6a6acSopenharmony_ci rec->spec_file = (char **)calloc(path_nums, sizeof(char *)); 7376cd6a6acSopenharmony_ci if (rec->spec_file == NULL) { 7386cd6a6acSopenharmony_ci goto finish; 7396cd6a6acSopenharmony_ci } 7406cd6a6acSopenharmony_ci rec->spec_file_nums = path_nums; 7416cd6a6acSopenharmony_ci size_t i = 0; 7426cd6a6acSopenharmony_ci n = opt_nums; 7436cd6a6acSopenharmony_ci while (n--) { 7446cd6a6acSopenharmony_ci if (opts[n].type == SELABEL_OPT_PATH) { 7456cd6a6acSopenharmony_ci rec->spec_file[i] = strdup(opts[n].value); 7466cd6a6acSopenharmony_ci if (rec->spec_file[i] == NULL) { 7476cd6a6acSopenharmony_ci goto finish; 7486cd6a6acSopenharmony_ci } 7496cd6a6acSopenharmony_ci i++; 7506cd6a6acSopenharmony_ci } 7516cd6a6acSopenharmony_ci } 7526cd6a6acSopenharmony_ci 7536cd6a6acSopenharmony_ci for (int path_index = 0; path_index < rec->spec_file_nums; path_index++) { 7546cd6a6acSopenharmony_ci status = process_file(rec->spec_file[path_index], NULL, rec, prefix, rec->digest); 7556cd6a6acSopenharmony_ci if (status) { 7566cd6a6acSopenharmony_ci goto finish; 7576cd6a6acSopenharmony_ci } 7586cd6a6acSopenharmony_ci 7596cd6a6acSopenharmony_ci if (rec->validating) { 7606cd6a6acSopenharmony_ci status = nodups_specs(data, rec->spec_file[path_index]); 7616cd6a6acSopenharmony_ci if (status) { 7626cd6a6acSopenharmony_ci goto finish; 7636cd6a6acSopenharmony_ci } 7646cd6a6acSopenharmony_ci } 7656cd6a6acSopenharmony_ci } 7666cd6a6acSopenharmony_ci 7676cd6a6acSopenharmony_ci digest_gen_hash(rec->digest); 7686cd6a6acSopenharmony_ci 7696cd6a6acSopenharmony_ci status = sort_specs(data); 7706cd6a6acSopenharmony_ci 7716cd6a6acSopenharmony_cifinish: 7726cd6a6acSopenharmony_ci if (status) 7736cd6a6acSopenharmony_ci closef(rec); 7746cd6a6acSopenharmony_ci 7756cd6a6acSopenharmony_ci return status; 7766cd6a6acSopenharmony_ci} 7776cd6a6acSopenharmony_ci#else 7786cd6a6acSopenharmony_cistatic int init(struct selabel_handle *rec, const struct selinux_opt *opts, 7796cd6a6acSopenharmony_ci unsigned n) 7806cd6a6acSopenharmony_ci{ 7816cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 7826cd6a6acSopenharmony_ci const char *path = NULL; 7836cd6a6acSopenharmony_ci const char *prefix = NULL; 7846cd6a6acSopenharmony_ci int status = -1, baseonly = 0; 7856cd6a6acSopenharmony_ci 7866cd6a6acSopenharmony_ci /* Process arguments */ 7876cd6a6acSopenharmony_ci while (n--) 7886cd6a6acSopenharmony_ci switch(opts[n].type) { 7896cd6a6acSopenharmony_ci case SELABEL_OPT_PATH: 7906cd6a6acSopenharmony_ci path = opts[n].value; 7916cd6a6acSopenharmony_ci break; 7926cd6a6acSopenharmony_ci case SELABEL_OPT_SUBSET: 7936cd6a6acSopenharmony_ci prefix = opts[n].value; 7946cd6a6acSopenharmony_ci break; 7956cd6a6acSopenharmony_ci case SELABEL_OPT_BASEONLY: 7966cd6a6acSopenharmony_ci baseonly = !!opts[n].value; 7976cd6a6acSopenharmony_ci break; 7986cd6a6acSopenharmony_ci } 7996cd6a6acSopenharmony_ci 8006cd6a6acSopenharmony_ci#if !defined(BUILD_HOST) && !defined(ANDROID) 8016cd6a6acSopenharmony_ci char subs_file[PATH_MAX + 1]; 8026cd6a6acSopenharmony_ci /* Process local and distribution substitution files */ 8036cd6a6acSopenharmony_ci if (!path) { 8046cd6a6acSopenharmony_ci status = selabel_subs_init( 8056cd6a6acSopenharmony_ci selinux_file_context_subs_dist_path(), 8066cd6a6acSopenharmony_ci rec->digest, &data->dist_subs); 8076cd6a6acSopenharmony_ci if (status) 8086cd6a6acSopenharmony_ci goto finish; 8096cd6a6acSopenharmony_ci status = selabel_subs_init(selinux_file_context_subs_path(), 8106cd6a6acSopenharmony_ci rec->digest, &data->subs); 8116cd6a6acSopenharmony_ci if (status) 8126cd6a6acSopenharmony_ci goto finish; 8136cd6a6acSopenharmony_ci path = selinux_file_context_path(); 8146cd6a6acSopenharmony_ci } else { 8156cd6a6acSopenharmony_ci snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path); 8166cd6a6acSopenharmony_ci status = selabel_subs_init(subs_file, rec->digest, 8176cd6a6acSopenharmony_ci &data->dist_subs); 8186cd6a6acSopenharmony_ci if (status) 8196cd6a6acSopenharmony_ci goto finish; 8206cd6a6acSopenharmony_ci snprintf(subs_file, sizeof(subs_file), "%s.subs", path); 8216cd6a6acSopenharmony_ci status = selabel_subs_init(subs_file, rec->digest, 8226cd6a6acSopenharmony_ci &data->subs); 8236cd6a6acSopenharmony_ci if (status) 8246cd6a6acSopenharmony_ci goto finish; 8256cd6a6acSopenharmony_ci } 8266cd6a6acSopenharmony_ci 8276cd6a6acSopenharmony_ci#endif 8286cd6a6acSopenharmony_ci 8296cd6a6acSopenharmony_ci if (!path) 8306cd6a6acSopenharmony_ci goto finish; 8316cd6a6acSopenharmony_ci 8326cd6a6acSopenharmony_ci rec->spec_file = strdup(path); 8336cd6a6acSopenharmony_ci 8346cd6a6acSopenharmony_ci /* 8356cd6a6acSopenharmony_ci * The do detailed validation of the input and fill the spec array 8366cd6a6acSopenharmony_ci */ 8376cd6a6acSopenharmony_ci status = process_file(path, NULL, rec, prefix, rec->digest); 8386cd6a6acSopenharmony_ci if (status) 8396cd6a6acSopenharmony_ci goto finish; 8406cd6a6acSopenharmony_ci 8416cd6a6acSopenharmony_ci if (rec->validating) { 8426cd6a6acSopenharmony_ci status = nodups_specs(data, path); 8436cd6a6acSopenharmony_ci if (status) 8446cd6a6acSopenharmony_ci goto finish; 8456cd6a6acSopenharmony_ci } 8466cd6a6acSopenharmony_ci 8476cd6a6acSopenharmony_ci if (!baseonly) { 8486cd6a6acSopenharmony_ci status = process_file(path, "homedirs", rec, prefix, 8496cd6a6acSopenharmony_ci rec->digest); 8506cd6a6acSopenharmony_ci if (status && errno != ENOENT) 8516cd6a6acSopenharmony_ci goto finish; 8526cd6a6acSopenharmony_ci 8536cd6a6acSopenharmony_ci status = process_file(path, "local", rec, prefix, 8546cd6a6acSopenharmony_ci rec->digest); 8556cd6a6acSopenharmony_ci if (status && errno != ENOENT) 8566cd6a6acSopenharmony_ci goto finish; 8576cd6a6acSopenharmony_ci } 8586cd6a6acSopenharmony_ci 8596cd6a6acSopenharmony_ci digest_gen_hash(rec->digest); 8606cd6a6acSopenharmony_ci 8616cd6a6acSopenharmony_ci status = sort_specs(data); 8626cd6a6acSopenharmony_ci 8636cd6a6acSopenharmony_cifinish: 8646cd6a6acSopenharmony_ci if (status) 8656cd6a6acSopenharmony_ci closef(rec); 8666cd6a6acSopenharmony_ci 8676cd6a6acSopenharmony_ci return status; 8686cd6a6acSopenharmony_ci} 8696cd6a6acSopenharmony_ci#endif 8706cd6a6acSopenharmony_ci 8716cd6a6acSopenharmony_ci/* 8726cd6a6acSopenharmony_ci * Backend interface routines 8736cd6a6acSopenharmony_ci */ 8746cd6a6acSopenharmony_cistatic void closef(struct selabel_handle *rec) 8756cd6a6acSopenharmony_ci{ 8766cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 8776cd6a6acSopenharmony_ci struct mmap_area *area, *last_area; 8786cd6a6acSopenharmony_ci struct spec *spec; 8796cd6a6acSopenharmony_ci struct stem *stem; 8806cd6a6acSopenharmony_ci unsigned int i; 8816cd6a6acSopenharmony_ci 8826cd6a6acSopenharmony_ci selabel_subs_fini(data->subs); 8836cd6a6acSopenharmony_ci selabel_subs_fini(data->dist_subs); 8846cd6a6acSopenharmony_ci 8856cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) { 8866cd6a6acSopenharmony_ci spec = &data->spec_arr[i]; 8876cd6a6acSopenharmony_ci free(spec->lr.ctx_trans); 8886cd6a6acSopenharmony_ci free(spec->lr.ctx_raw); 8896cd6a6acSopenharmony_ci regex_data_free(spec->regex); 8906cd6a6acSopenharmony_ci __pthread_mutex_destroy(&spec->regex_lock); 8916cd6a6acSopenharmony_ci if (spec->from_mmap) 8926cd6a6acSopenharmony_ci continue; 8936cd6a6acSopenharmony_ci free(spec->regex_str); 8946cd6a6acSopenharmony_ci free(spec->type_str); 8956cd6a6acSopenharmony_ci } 8966cd6a6acSopenharmony_ci 8976cd6a6acSopenharmony_ci for (i = 0; i < (unsigned int)data->num_stems; i++) { 8986cd6a6acSopenharmony_ci stem = &data->stem_arr[i]; 8996cd6a6acSopenharmony_ci if (stem->from_mmap) 9006cd6a6acSopenharmony_ci continue; 9016cd6a6acSopenharmony_ci free(stem->buf); 9026cd6a6acSopenharmony_ci } 9036cd6a6acSopenharmony_ci 9046cd6a6acSopenharmony_ci if (data->spec_arr) 9056cd6a6acSopenharmony_ci free(data->spec_arr); 9066cd6a6acSopenharmony_ci if (data->stem_arr) 9076cd6a6acSopenharmony_ci free(data->stem_arr); 9086cd6a6acSopenharmony_ci 9096cd6a6acSopenharmony_ci area = data->mmap_areas; 9106cd6a6acSopenharmony_ci while (area) { 9116cd6a6acSopenharmony_ci munmap(area->addr, area->len); 9126cd6a6acSopenharmony_ci last_area = area; 9136cd6a6acSopenharmony_ci area = area->next; 9146cd6a6acSopenharmony_ci free(last_area); 9156cd6a6acSopenharmony_ci } 9166cd6a6acSopenharmony_ci free(data); 9176cd6a6acSopenharmony_ci} 9186cd6a6acSopenharmony_ci 9196cd6a6acSopenharmony_ci// Finds all the matches of |key| in the given context. Returns the result in 9206cd6a6acSopenharmony_ci// the allocated array and updates the match count. If match_count is NULL, 9216cd6a6acSopenharmony_ci// stops early once the 1st match is found. 9226cd6a6acSopenharmony_cistatic struct spec **lookup_all(struct selabel_handle *rec, 9236cd6a6acSopenharmony_ci const char *key, 9246cd6a6acSopenharmony_ci int type, 9256cd6a6acSopenharmony_ci bool partial, 9266cd6a6acSopenharmony_ci size_t *match_count) 9276cd6a6acSopenharmony_ci{ 9286cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 9296cd6a6acSopenharmony_ci struct spec *spec_arr = data->spec_arr; 9306cd6a6acSopenharmony_ci int i, rc, file_stem; 9316cd6a6acSopenharmony_ci size_t len; 9326cd6a6acSopenharmony_ci mode_t mode = (mode_t)type; 9336cd6a6acSopenharmony_ci char *clean_key = NULL; 9346cd6a6acSopenharmony_ci const char *prev_slash, *next_slash; 9356cd6a6acSopenharmony_ci unsigned int sofar = 0; 9366cd6a6acSopenharmony_ci char *sub = NULL; 9376cd6a6acSopenharmony_ci 9386cd6a6acSopenharmony_ci struct spec **result = NULL; 9396cd6a6acSopenharmony_ci if (match_count) { 9406cd6a6acSopenharmony_ci *match_count = 0; 9416cd6a6acSopenharmony_ci result = calloc(data->nspec, sizeof(struct spec*)); 9426cd6a6acSopenharmony_ci } else { 9436cd6a6acSopenharmony_ci result = calloc(1, sizeof(struct spec*)); 9446cd6a6acSopenharmony_ci } 9456cd6a6acSopenharmony_ci if (!result) { 9466cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, "Failed to allocate %zu bytes of data\n", 9476cd6a6acSopenharmony_ci data->nspec * sizeof(struct spec*)); 9486cd6a6acSopenharmony_ci goto finish; 9496cd6a6acSopenharmony_ci } 9506cd6a6acSopenharmony_ci 9516cd6a6acSopenharmony_ci if (!data->nspec) { 9526cd6a6acSopenharmony_ci errno = ENOENT; 9536cd6a6acSopenharmony_ci goto finish; 9546cd6a6acSopenharmony_ci } 9556cd6a6acSopenharmony_ci 9566cd6a6acSopenharmony_ci /* Remove duplicate slashes */ 9576cd6a6acSopenharmony_ci if ((next_slash = strstr(key, "//"))) { 9586cd6a6acSopenharmony_ci clean_key = (char *) malloc(strlen(key) + 1); 9596cd6a6acSopenharmony_ci if (!clean_key) 9606cd6a6acSopenharmony_ci goto finish; 9616cd6a6acSopenharmony_ci prev_slash = key; 9626cd6a6acSopenharmony_ci while (next_slash) { 9636cd6a6acSopenharmony_ci memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash); 9646cd6a6acSopenharmony_ci sofar += next_slash - prev_slash; 9656cd6a6acSopenharmony_ci prev_slash = next_slash + 1; 9666cd6a6acSopenharmony_ci next_slash = strstr(prev_slash, "//"); 9676cd6a6acSopenharmony_ci } 9686cd6a6acSopenharmony_ci strcpy(clean_key + sofar, prev_slash); 9696cd6a6acSopenharmony_ci key = clean_key; 9706cd6a6acSopenharmony_ci } 9716cd6a6acSopenharmony_ci 9726cd6a6acSopenharmony_ci /* remove trailing slash */ 9736cd6a6acSopenharmony_ci len = strlen(key); 9746cd6a6acSopenharmony_ci if (len == 0) { 9756cd6a6acSopenharmony_ci errno = EINVAL; 9766cd6a6acSopenharmony_ci goto finish; 9776cd6a6acSopenharmony_ci } 9786cd6a6acSopenharmony_ci 9796cd6a6acSopenharmony_ci if (len > 1 && key[len - 1] == '/') { 9806cd6a6acSopenharmony_ci /* reuse clean_key from above if available */ 9816cd6a6acSopenharmony_ci if (!clean_key) { 9826cd6a6acSopenharmony_ci clean_key = (char *) malloc(len); 9836cd6a6acSopenharmony_ci if (!clean_key) 9846cd6a6acSopenharmony_ci goto finish; 9856cd6a6acSopenharmony_ci 9866cd6a6acSopenharmony_ci memcpy(clean_key, key, len - 1); 9876cd6a6acSopenharmony_ci } 9886cd6a6acSopenharmony_ci 9896cd6a6acSopenharmony_ci clean_key[len - 1] = '\0'; 9906cd6a6acSopenharmony_ci key = clean_key; 9916cd6a6acSopenharmony_ci } 9926cd6a6acSopenharmony_ci 9936cd6a6acSopenharmony_ci sub = selabel_sub_key(data, key); 9946cd6a6acSopenharmony_ci if (sub) 9956cd6a6acSopenharmony_ci key = sub; 9966cd6a6acSopenharmony_ci 9976cd6a6acSopenharmony_ci file_stem = find_stem_from_file(data, key); 9986cd6a6acSopenharmony_ci mode &= S_IFMT; 9996cd6a6acSopenharmony_ci 10006cd6a6acSopenharmony_ci /* 10016cd6a6acSopenharmony_ci * Check for matching specifications in reverse order, so that 10026cd6a6acSopenharmony_ci * the last matching specification is used. 10036cd6a6acSopenharmony_ci */ 10046cd6a6acSopenharmony_ci for (i = data->nspec - 1; i >= 0; i--) { 10056cd6a6acSopenharmony_ci struct spec *spec = &spec_arr[i]; 10066cd6a6acSopenharmony_ci /* if the spec in question matches no stem or has the same 10076cd6a6acSopenharmony_ci * stem as the file AND if the spec in question has no mode 10086cd6a6acSopenharmony_ci * specified or if the mode matches the file mode then we do 10096cd6a6acSopenharmony_ci * a regex check */ 10106cd6a6acSopenharmony_ci bool stem_matches = spec->stem_id == -1 || spec->stem_id == file_stem; 10116cd6a6acSopenharmony_ci // Don't check the stem if we want to find partial matches. 10126cd6a6acSopenharmony_ci // Otherwise the case "/abc/efg/(/.*)?" will be considered 10136cd6a6acSopenharmony_ci //a miss for "/abc". 10146cd6a6acSopenharmony_ci if ((partial || stem_matches) && 10156cd6a6acSopenharmony_ci (!mode || !spec->mode || mode == spec->mode)) { 10166cd6a6acSopenharmony_ci if (compile_regex(spec, NULL) < 0) 10176cd6a6acSopenharmony_ci goto finish; 10186cd6a6acSopenharmony_ci rc = regex_match(spec->regex, key, partial); 10196cd6a6acSopenharmony_ci if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) { 10206cd6a6acSopenharmony_ci if (rc == REGEX_MATCH) { 10216cd6a6acSopenharmony_ci#ifdef __ATOMIC_RELAXED 10226cd6a6acSopenharmony_ci __atomic_store_n(&spec->any_matches, 10236cd6a6acSopenharmony_ci true, __ATOMIC_RELAXED); 10246cd6a6acSopenharmony_ci#else 10256cd6a6acSopenharmony_ci#error "Please use a compiler that supports __atomic builtins" 10266cd6a6acSopenharmony_ci#endif 10276cd6a6acSopenharmony_ci } 10286cd6a6acSopenharmony_ci 10296cd6a6acSopenharmony_ci if (strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) { 10306cd6a6acSopenharmony_ci errno = ENOENT; 10316cd6a6acSopenharmony_ci goto finish; 10326cd6a6acSopenharmony_ci } 10336cd6a6acSopenharmony_ci 10346cd6a6acSopenharmony_ci if (match_count) { 10356cd6a6acSopenharmony_ci result[*match_count] = spec; 10366cd6a6acSopenharmony_ci *match_count += 1; 10376cd6a6acSopenharmony_ci // Continue to find all the matches. 10386cd6a6acSopenharmony_ci continue; 10396cd6a6acSopenharmony_ci } 10406cd6a6acSopenharmony_ci result[0] = spec; 10416cd6a6acSopenharmony_ci break; 10426cd6a6acSopenharmony_ci } 10436cd6a6acSopenharmony_ci 10446cd6a6acSopenharmony_ci if (rc == REGEX_NO_MATCH) 10456cd6a6acSopenharmony_ci continue; 10466cd6a6acSopenharmony_ci 10476cd6a6acSopenharmony_ci errno = ENOENT; 10486cd6a6acSopenharmony_ci /* else it's an error */ 10496cd6a6acSopenharmony_ci goto finish; 10506cd6a6acSopenharmony_ci } 10516cd6a6acSopenharmony_ci } 10526cd6a6acSopenharmony_ci if (!result[0]) 10536cd6a6acSopenharmony_ci errno = ENOENT; 10546cd6a6acSopenharmony_ci 10556cd6a6acSopenharmony_cifinish: 10566cd6a6acSopenharmony_ci free(clean_key); 10576cd6a6acSopenharmony_ci free(sub); 10586cd6a6acSopenharmony_ci if (result && !result[0]) { 10596cd6a6acSopenharmony_ci free(result); 10606cd6a6acSopenharmony_ci result = NULL; 10616cd6a6acSopenharmony_ci } 10626cd6a6acSopenharmony_ci return result; 10636cd6a6acSopenharmony_ci} 10646cd6a6acSopenharmony_ci 10656cd6a6acSopenharmony_cistatic struct spec *lookup_common(struct selabel_handle *rec, 10666cd6a6acSopenharmony_ci const char *key, 10676cd6a6acSopenharmony_ci int type, 10686cd6a6acSopenharmony_ci bool partial) { 10696cd6a6acSopenharmony_ci struct spec **matches = lookup_all(rec, key, type, partial, NULL); 10706cd6a6acSopenharmony_ci if (!matches) { 10716cd6a6acSopenharmony_ci return NULL; 10726cd6a6acSopenharmony_ci } 10736cd6a6acSopenharmony_ci struct spec *result = matches[0]; 10746cd6a6acSopenharmony_ci free(matches); 10756cd6a6acSopenharmony_ci return result; 10766cd6a6acSopenharmony_ci} 10776cd6a6acSopenharmony_ci 10786cd6a6acSopenharmony_ci/* 10796cd6a6acSopenharmony_ci * Returns true if the digest of all partial matched contexts is the same as 10806cd6a6acSopenharmony_ci * the one saved by setxattr, otherwise returns false. The length of the SHA1 10816cd6a6acSopenharmony_ci * digest will always be returned. The caller must free any returned digests. 10826cd6a6acSopenharmony_ci */ 10836cd6a6acSopenharmony_cistatic bool get_digests_all_partial_matches(struct selabel_handle *rec, 10846cd6a6acSopenharmony_ci const char *pathname, 10856cd6a6acSopenharmony_ci uint8_t **calculated_digest, 10866cd6a6acSopenharmony_ci uint8_t **xattr_digest, 10876cd6a6acSopenharmony_ci size_t *digest_len) 10886cd6a6acSopenharmony_ci{ 10896cd6a6acSopenharmony_ci uint8_t read_digest[SHA1_HASH_SIZE]; 10906cd6a6acSopenharmony_ci ssize_t read_size = getxattr(pathname, RESTORECON_PARTIAL_MATCH_DIGEST, 10916cd6a6acSopenharmony_ci read_digest, SHA1_HASH_SIZE 10926cd6a6acSopenharmony_ci#ifdef __APPLE__ 10936cd6a6acSopenharmony_ci , 0, 0 10946cd6a6acSopenharmony_ci#endif /* __APPLE __ */ 10956cd6a6acSopenharmony_ci ); 10966cd6a6acSopenharmony_ci uint8_t hash_digest[SHA1_HASH_SIZE]; 10976cd6a6acSopenharmony_ci bool status = selabel_hash_all_partial_matches(rec, pathname, 10986cd6a6acSopenharmony_ci hash_digest); 10996cd6a6acSopenharmony_ci 11006cd6a6acSopenharmony_ci *xattr_digest = NULL; 11016cd6a6acSopenharmony_ci *calculated_digest = NULL; 11026cd6a6acSopenharmony_ci *digest_len = SHA1_HASH_SIZE; 11036cd6a6acSopenharmony_ci 11046cd6a6acSopenharmony_ci if (read_size == SHA1_HASH_SIZE) { 11056cd6a6acSopenharmony_ci *xattr_digest = calloc(1, SHA1_HASH_SIZE + 1); 11066cd6a6acSopenharmony_ci if (!*xattr_digest) 11076cd6a6acSopenharmony_ci goto oom; 11086cd6a6acSopenharmony_ci 11096cd6a6acSopenharmony_ci memcpy(*xattr_digest, read_digest, SHA1_HASH_SIZE); 11106cd6a6acSopenharmony_ci } 11116cd6a6acSopenharmony_ci 11126cd6a6acSopenharmony_ci if (status) { 11136cd6a6acSopenharmony_ci *calculated_digest = calloc(1, SHA1_HASH_SIZE + 1); 11146cd6a6acSopenharmony_ci if (!*calculated_digest) 11156cd6a6acSopenharmony_ci goto oom; 11166cd6a6acSopenharmony_ci 11176cd6a6acSopenharmony_ci memcpy(*calculated_digest, hash_digest, SHA1_HASH_SIZE); 11186cd6a6acSopenharmony_ci } 11196cd6a6acSopenharmony_ci 11206cd6a6acSopenharmony_ci if (status && read_size == SHA1_HASH_SIZE && 11216cd6a6acSopenharmony_ci memcmp(read_digest, hash_digest, SHA1_HASH_SIZE) == 0) 11226cd6a6acSopenharmony_ci return true; 11236cd6a6acSopenharmony_ci 11246cd6a6acSopenharmony_ci return false; 11256cd6a6acSopenharmony_ci 11266cd6a6acSopenharmony_cioom: 11276cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, "SELinux: %s: Out of memory\n", __func__); 11286cd6a6acSopenharmony_ci return false; 11296cd6a6acSopenharmony_ci} 11306cd6a6acSopenharmony_ci 11316cd6a6acSopenharmony_cistatic bool hash_all_partial_matches(struct selabel_handle *rec, const char *key, uint8_t *digest) 11326cd6a6acSopenharmony_ci{ 11336cd6a6acSopenharmony_ci assert(digest); 11346cd6a6acSopenharmony_ci 11356cd6a6acSopenharmony_ci size_t total_matches; 11366cd6a6acSopenharmony_ci struct spec **matches = lookup_all(rec, key, 0, true, &total_matches); 11376cd6a6acSopenharmony_ci if (!matches) { 11386cd6a6acSopenharmony_ci return false; 11396cd6a6acSopenharmony_ci } 11406cd6a6acSopenharmony_ci 11416cd6a6acSopenharmony_ci Sha1Context context; 11426cd6a6acSopenharmony_ci Sha1Initialise(&context); 11436cd6a6acSopenharmony_ci size_t i; 11446cd6a6acSopenharmony_ci for (i = 0; i < total_matches; i++) { 11456cd6a6acSopenharmony_ci char* regex_str = matches[i]->regex_str; 11466cd6a6acSopenharmony_ci mode_t mode = matches[i]->mode; 11476cd6a6acSopenharmony_ci char* ctx_raw = matches[i]->lr.ctx_raw; 11486cd6a6acSopenharmony_ci 11496cd6a6acSopenharmony_ci Sha1Update(&context, regex_str, strlen(regex_str) + 1); 11506cd6a6acSopenharmony_ci Sha1Update(&context, &mode, sizeof(mode_t)); 11516cd6a6acSopenharmony_ci Sha1Update(&context, ctx_raw, strlen(ctx_raw) + 1); 11526cd6a6acSopenharmony_ci } 11536cd6a6acSopenharmony_ci 11546cd6a6acSopenharmony_ci SHA1_HASH sha1_hash; 11556cd6a6acSopenharmony_ci Sha1Finalise(&context, &sha1_hash); 11566cd6a6acSopenharmony_ci memcpy(digest, sha1_hash.bytes, SHA1_HASH_SIZE); 11576cd6a6acSopenharmony_ci 11586cd6a6acSopenharmony_ci free(matches); 11596cd6a6acSopenharmony_ci return true; 11606cd6a6acSopenharmony_ci} 11616cd6a6acSopenharmony_ci 11626cd6a6acSopenharmony_cistatic struct selabel_lookup_rec *lookup(struct selabel_handle *rec, 11636cd6a6acSopenharmony_ci const char *key, int type) 11646cd6a6acSopenharmony_ci{ 11656cd6a6acSopenharmony_ci struct spec *spec; 11666cd6a6acSopenharmony_ci 11676cd6a6acSopenharmony_ci spec = lookup_common(rec, key, type, false); 11686cd6a6acSopenharmony_ci if (spec) 11696cd6a6acSopenharmony_ci return &spec->lr; 11706cd6a6acSopenharmony_ci return NULL; 11716cd6a6acSopenharmony_ci} 11726cd6a6acSopenharmony_ci 11736cd6a6acSopenharmony_cistatic bool partial_match(struct selabel_handle *rec, const char *key) 11746cd6a6acSopenharmony_ci{ 11756cd6a6acSopenharmony_ci return lookup_common(rec, key, 0, true) ? true : false; 11766cd6a6acSopenharmony_ci} 11776cd6a6acSopenharmony_ci 11786cd6a6acSopenharmony_cistatic struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec, 11796cd6a6acSopenharmony_ci const char *key, 11806cd6a6acSopenharmony_ci const char **aliases, 11816cd6a6acSopenharmony_ci int type) 11826cd6a6acSopenharmony_ci{ 11836cd6a6acSopenharmony_ci size_t n, i; 11846cd6a6acSopenharmony_ci int best = -1; 11856cd6a6acSopenharmony_ci struct spec **specs; 11866cd6a6acSopenharmony_ci size_t prefix_len = 0; 11876cd6a6acSopenharmony_ci struct selabel_lookup_rec *lr = NULL; 11886cd6a6acSopenharmony_ci 11896cd6a6acSopenharmony_ci if (!aliases || !aliases[0]) 11906cd6a6acSopenharmony_ci return lookup(rec, key, type); 11916cd6a6acSopenharmony_ci 11926cd6a6acSopenharmony_ci for (n = 0; aliases[n]; n++) 11936cd6a6acSopenharmony_ci ; 11946cd6a6acSopenharmony_ci 11956cd6a6acSopenharmony_ci specs = calloc(n+1, sizeof(struct spec *)); 11966cd6a6acSopenharmony_ci if (!specs) 11976cd6a6acSopenharmony_ci return NULL; 11986cd6a6acSopenharmony_ci specs[0] = lookup_common(rec, key, type, false); 11996cd6a6acSopenharmony_ci if (specs[0]) { 12006cd6a6acSopenharmony_ci if (!specs[0]->hasMetaChars) { 12016cd6a6acSopenharmony_ci /* exact match on key */ 12026cd6a6acSopenharmony_ci lr = &specs[0]->lr; 12036cd6a6acSopenharmony_ci goto out; 12046cd6a6acSopenharmony_ci } 12056cd6a6acSopenharmony_ci best = 0; 12066cd6a6acSopenharmony_ci prefix_len = specs[0]->prefix_len; 12076cd6a6acSopenharmony_ci } 12086cd6a6acSopenharmony_ci for (i = 1; i <= n; i++) { 12096cd6a6acSopenharmony_ci specs[i] = lookup_common(rec, aliases[i-1], type, false); 12106cd6a6acSopenharmony_ci if (specs[i]) { 12116cd6a6acSopenharmony_ci if (!specs[i]->hasMetaChars) { 12126cd6a6acSopenharmony_ci /* exact match on alias */ 12136cd6a6acSopenharmony_ci lr = &specs[i]->lr; 12146cd6a6acSopenharmony_ci goto out; 12156cd6a6acSopenharmony_ci } 12166cd6a6acSopenharmony_ci if (specs[i]->prefix_len > prefix_len) { 12176cd6a6acSopenharmony_ci best = i; 12186cd6a6acSopenharmony_ci prefix_len = specs[i]->prefix_len; 12196cd6a6acSopenharmony_ci } 12206cd6a6acSopenharmony_ci } 12216cd6a6acSopenharmony_ci } 12226cd6a6acSopenharmony_ci 12236cd6a6acSopenharmony_ci if (best >= 0) { 12246cd6a6acSopenharmony_ci /* longest fixed prefix match on key or alias */ 12256cd6a6acSopenharmony_ci lr = &specs[best]->lr; 12266cd6a6acSopenharmony_ci } else { 12276cd6a6acSopenharmony_ci errno = ENOENT; 12286cd6a6acSopenharmony_ci } 12296cd6a6acSopenharmony_ci 12306cd6a6acSopenharmony_ciout: 12316cd6a6acSopenharmony_ci free(specs); 12326cd6a6acSopenharmony_ci return lr; 12336cd6a6acSopenharmony_ci} 12346cd6a6acSopenharmony_ci 12356cd6a6acSopenharmony_cistatic enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, const char *reason, int i, int j) 12366cd6a6acSopenharmony_ci{ 12376cd6a6acSopenharmony_ci selinux_log(SELINUX_INFO, 12386cd6a6acSopenharmony_ci "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n", 12396cd6a6acSopenharmony_ci reason, 12406cd6a6acSopenharmony_ci i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw, 12416cd6a6acSopenharmony_ci j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw); 12426cd6a6acSopenharmony_ci return SELABEL_INCOMPARABLE; 12436cd6a6acSopenharmony_ci} 12446cd6a6acSopenharmony_ci 12456cd6a6acSopenharmony_cistatic enum selabel_cmp_result cmp(struct selabel_handle *h1, 12466cd6a6acSopenharmony_ci struct selabel_handle *h2) 12476cd6a6acSopenharmony_ci{ 12486cd6a6acSopenharmony_ci struct saved_data *data1 = (struct saved_data *)h1->data; 12496cd6a6acSopenharmony_ci struct saved_data *data2 = (struct saved_data *)h2->data; 12506cd6a6acSopenharmony_ci unsigned int i, nspec1 = data1->nspec, j, nspec2 = data2->nspec; 12516cd6a6acSopenharmony_ci struct spec *spec_arr1 = data1->spec_arr, *spec_arr2 = data2->spec_arr; 12526cd6a6acSopenharmony_ci struct stem *stem_arr1 = data1->stem_arr, *stem_arr2 = data2->stem_arr; 12536cd6a6acSopenharmony_ci bool skipped1 = false, skipped2 = false; 12546cd6a6acSopenharmony_ci 12556cd6a6acSopenharmony_ci i = 0; 12566cd6a6acSopenharmony_ci j = 0; 12576cd6a6acSopenharmony_ci while (i < nspec1 && j < nspec2) { 12586cd6a6acSopenharmony_ci struct spec *spec1 = &spec_arr1[i]; 12596cd6a6acSopenharmony_ci struct spec *spec2 = &spec_arr2[j]; 12606cd6a6acSopenharmony_ci 12616cd6a6acSopenharmony_ci /* 12626cd6a6acSopenharmony_ci * Because sort_specs() moves exact pathnames to the 12636cd6a6acSopenharmony_ci * end, we might need to skip over additional regex 12646cd6a6acSopenharmony_ci * entries that only exist in one of the configurations. 12656cd6a6acSopenharmony_ci */ 12666cd6a6acSopenharmony_ci if (!spec1->hasMetaChars && spec2->hasMetaChars) { 12676cd6a6acSopenharmony_ci j++; 12686cd6a6acSopenharmony_ci skipped2 = true; 12696cd6a6acSopenharmony_ci continue; 12706cd6a6acSopenharmony_ci } 12716cd6a6acSopenharmony_ci 12726cd6a6acSopenharmony_ci if (spec1->hasMetaChars && !spec2->hasMetaChars) { 12736cd6a6acSopenharmony_ci i++; 12746cd6a6acSopenharmony_ci skipped1 = true; 12756cd6a6acSopenharmony_ci continue; 12766cd6a6acSopenharmony_ci } 12776cd6a6acSopenharmony_ci 12786cd6a6acSopenharmony_ci if (spec1->regex && spec2->regex) { 12796cd6a6acSopenharmony_ci if (regex_cmp(spec1->regex, spec2->regex) == SELABEL_INCOMPARABLE){ 12806cd6a6acSopenharmony_ci return incomp(spec1, spec2, "regex", i, j); 12816cd6a6acSopenharmony_ci } 12826cd6a6acSopenharmony_ci } else { 12836cd6a6acSopenharmony_ci if (strcmp(spec1->regex_str, spec2->regex_str)) 12846cd6a6acSopenharmony_ci return incomp(spec1, spec2, "regex_str", i, j); 12856cd6a6acSopenharmony_ci } 12866cd6a6acSopenharmony_ci 12876cd6a6acSopenharmony_ci if (spec1->mode != spec2->mode) 12886cd6a6acSopenharmony_ci return incomp(spec1, spec2, "mode", i, j); 12896cd6a6acSopenharmony_ci 12906cd6a6acSopenharmony_ci if (spec1->stem_id == -1 && spec2->stem_id != -1) 12916cd6a6acSopenharmony_ci return incomp(spec1, spec2, "stem_id", i, j); 12926cd6a6acSopenharmony_ci if (spec2->stem_id == -1 && spec1->stem_id != -1) 12936cd6a6acSopenharmony_ci return incomp(spec1, spec2, "stem_id", i, j); 12946cd6a6acSopenharmony_ci if (spec1->stem_id != -1 && spec2->stem_id != -1) { 12956cd6a6acSopenharmony_ci struct stem *stem1 = &stem_arr1[spec1->stem_id]; 12966cd6a6acSopenharmony_ci struct stem *stem2 = &stem_arr2[spec2->stem_id]; 12976cd6a6acSopenharmony_ci if (stem1->len != stem2->len || 12986cd6a6acSopenharmony_ci strncmp(stem1->buf, stem2->buf, stem1->len)) 12996cd6a6acSopenharmony_ci return incomp(spec1, spec2, "stem", i, j); 13006cd6a6acSopenharmony_ci } 13016cd6a6acSopenharmony_ci 13026cd6a6acSopenharmony_ci if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw)) 13036cd6a6acSopenharmony_ci return incomp(spec1, spec2, "ctx_raw", i, j); 13046cd6a6acSopenharmony_ci 13056cd6a6acSopenharmony_ci i++; 13066cd6a6acSopenharmony_ci j++; 13076cd6a6acSopenharmony_ci } 13086cd6a6acSopenharmony_ci 13096cd6a6acSopenharmony_ci if ((skipped1 || i < nspec1) && !skipped2) 13106cd6a6acSopenharmony_ci return SELABEL_SUPERSET; 13116cd6a6acSopenharmony_ci if ((skipped2 || j < nspec2) && !skipped1) 13126cd6a6acSopenharmony_ci return SELABEL_SUBSET; 13136cd6a6acSopenharmony_ci if (skipped1 && skipped2) 13146cd6a6acSopenharmony_ci return SELABEL_INCOMPARABLE; 13156cd6a6acSopenharmony_ci return SELABEL_EQUAL; 13166cd6a6acSopenharmony_ci} 13176cd6a6acSopenharmony_ci 13186cd6a6acSopenharmony_ci 13196cd6a6acSopenharmony_cistatic void stats(struct selabel_handle *rec) 13206cd6a6acSopenharmony_ci{ 13216cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 13226cd6a6acSopenharmony_ci unsigned int i, nspec = data->nspec; 13236cd6a6acSopenharmony_ci struct spec *spec_arr = data->spec_arr; 13246cd6a6acSopenharmony_ci bool any_matches; 13256cd6a6acSopenharmony_ci 13266cd6a6acSopenharmony_ci for (i = 0; i < nspec; i++) { 13276cd6a6acSopenharmony_ci#ifdef __ATOMIC_RELAXED 13286cd6a6acSopenharmony_ci any_matches = __atomic_load_n(&spec_arr[i].any_matches, __ATOMIC_RELAXED); 13296cd6a6acSopenharmony_ci#else 13306cd6a6acSopenharmony_ci#error "Please use a compiler that supports __atomic builtins" 13316cd6a6acSopenharmony_ci#endif 13326cd6a6acSopenharmony_ci if (!any_matches) { 13336cd6a6acSopenharmony_ci if (spec_arr[i].type_str) { 13346cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_WARNING, 13356cd6a6acSopenharmony_ci "Warning! No matches for (%s, %s, %s)\n", 13366cd6a6acSopenharmony_ci spec_arr[i].regex_str, 13376cd6a6acSopenharmony_ci spec_arr[i].type_str, 13386cd6a6acSopenharmony_ci spec_arr[i].lr.ctx_raw); 13396cd6a6acSopenharmony_ci } else { 13406cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_WARNING, 13416cd6a6acSopenharmony_ci "Warning! No matches for (%s, %s)\n", 13426cd6a6acSopenharmony_ci spec_arr[i].regex_str, 13436cd6a6acSopenharmony_ci spec_arr[i].lr.ctx_raw); 13446cd6a6acSopenharmony_ci } 13456cd6a6acSopenharmony_ci } 13466cd6a6acSopenharmony_ci } 13476cd6a6acSopenharmony_ci} 13486cd6a6acSopenharmony_ci 13496cd6a6acSopenharmony_ciint selabel_file_init(struct selabel_handle *rec, 13506cd6a6acSopenharmony_ci const struct selinux_opt *opts, 13516cd6a6acSopenharmony_ci unsigned nopts) 13526cd6a6acSopenharmony_ci{ 13536cd6a6acSopenharmony_ci struct saved_data *data; 13546cd6a6acSopenharmony_ci 13556cd6a6acSopenharmony_ci data = (struct saved_data *)malloc(sizeof(*data)); 13566cd6a6acSopenharmony_ci if (!data) 13576cd6a6acSopenharmony_ci return -1; 13586cd6a6acSopenharmony_ci memset(data, 0, sizeof(*data)); 13596cd6a6acSopenharmony_ci 13606cd6a6acSopenharmony_ci rec->data = data; 13616cd6a6acSopenharmony_ci rec->func_close = &closef; 13626cd6a6acSopenharmony_ci rec->func_stats = &stats; 13636cd6a6acSopenharmony_ci rec->func_lookup = &lookup; 13646cd6a6acSopenharmony_ci rec->func_partial_match = &partial_match; 13656cd6a6acSopenharmony_ci rec->func_get_digests_all_partial_matches = 13666cd6a6acSopenharmony_ci &get_digests_all_partial_matches; 13676cd6a6acSopenharmony_ci rec->func_hash_all_partial_matches = &hash_all_partial_matches; 13686cd6a6acSopenharmony_ci rec->func_lookup_best_match = &lookup_best_match; 13696cd6a6acSopenharmony_ci rec->func_cmp = &cmp; 13706cd6a6acSopenharmony_ci 13716cd6a6acSopenharmony_ci return init(rec, opts, nopts); 13726cd6a6acSopenharmony_ci} 1373