16cd6a6acSopenharmony_ci#ifndef _SELABEL_FILE_H_ 26cd6a6acSopenharmony_ci#define _SELABEL_FILE_H_ 36cd6a6acSopenharmony_ci 46cd6a6acSopenharmony_ci#include <errno.h> 56cd6a6acSopenharmony_ci#include <pthread.h> 66cd6a6acSopenharmony_ci#include <string.h> 76cd6a6acSopenharmony_ci 86cd6a6acSopenharmony_ci#include <sys/stat.h> 96cd6a6acSopenharmony_ci#include <sys/xattr.h> 106cd6a6acSopenharmony_ci 116cd6a6acSopenharmony_ci/* 126cd6a6acSopenharmony_ci * regex.h/c were introduced to hold all dependencies on the regular 136cd6a6acSopenharmony_ci * expression back-end when we started supporting PCRE2. regex.h defines a 146cd6a6acSopenharmony_ci * minimal interface required by libselinux, so that the remaining code 156cd6a6acSopenharmony_ci * can be agnostic about the underlying implementation. 166cd6a6acSopenharmony_ci */ 176cd6a6acSopenharmony_ci#include "regex.h" 186cd6a6acSopenharmony_ci 196cd6a6acSopenharmony_ci#include "callbacks.h" 206cd6a6acSopenharmony_ci#include "label_internal.h" 216cd6a6acSopenharmony_ci#include "selinux_internal.h" 226cd6a6acSopenharmony_ci 236cd6a6acSopenharmony_ci#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci/* Version specific changes */ 266cd6a6acSopenharmony_ci#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 276cd6a6acSopenharmony_ci#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 286cd6a6acSopenharmony_ci#define SELINUX_COMPILED_FCONTEXT_MODE 3 296cd6a6acSopenharmony_ci#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4 306cd6a6acSopenharmony_ci#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH 5 316cd6a6acSopenharmony_ci 326cd6a6acSopenharmony_ci#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \ 336cd6a6acSopenharmony_ci SELINUX_COMPILED_FCONTEXT_REGEX_ARCH 346cd6a6acSopenharmony_ci 356cd6a6acSopenharmony_ci/* Required selinux_restorecon and selabel_get_digests_all_partial_matches() */ 366cd6a6acSopenharmony_ci#define RESTORECON_PARTIAL_MATCH_DIGEST "security.sehash" 376cd6a6acSopenharmony_ci 386cd6a6acSopenharmony_cistruct selabel_sub { 396cd6a6acSopenharmony_ci char *src; 406cd6a6acSopenharmony_ci int slen; 416cd6a6acSopenharmony_ci char *dst; 426cd6a6acSopenharmony_ci struct selabel_sub *next; 436cd6a6acSopenharmony_ci}; 446cd6a6acSopenharmony_ci 456cd6a6acSopenharmony_ci/* A file security context specification. */ 466cd6a6acSopenharmony_cistruct spec { 476cd6a6acSopenharmony_ci struct selabel_lookup_rec lr; /* holds contexts for lookup result */ 486cd6a6acSopenharmony_ci char *regex_str; /* regular expression string for diagnostics */ 496cd6a6acSopenharmony_ci char *type_str; /* type string for diagnostic messages */ 506cd6a6acSopenharmony_ci struct regex_data * regex; /* backend dependent regular expression data */ 516cd6a6acSopenharmony_ci bool regex_compiled; /* bool to indicate if the regex is compiled */ 526cd6a6acSopenharmony_ci pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */ 536cd6a6acSopenharmony_ci mode_t mode; /* mode format value */ 546cd6a6acSopenharmony_ci bool any_matches; /* did any pathname match? */ 556cd6a6acSopenharmony_ci int stem_id; /* indicates which stem-compression item */ 566cd6a6acSopenharmony_ci char hasMetaChars; /* regular expression has meta-chars */ 576cd6a6acSopenharmony_ci char from_mmap; /* this spec is from an mmap of the data */ 586cd6a6acSopenharmony_ci size_t prefix_len; /* length of fixed path prefix */ 596cd6a6acSopenharmony_ci}; 606cd6a6acSopenharmony_ci 616cd6a6acSopenharmony_ci/* A regular expression stem */ 626cd6a6acSopenharmony_cistruct stem { 636cd6a6acSopenharmony_ci char *buf; 646cd6a6acSopenharmony_ci int len; 656cd6a6acSopenharmony_ci char from_mmap; 666cd6a6acSopenharmony_ci}; 676cd6a6acSopenharmony_ci 686cd6a6acSopenharmony_ci/* Where we map the file in during selabel_open() */ 696cd6a6acSopenharmony_cistruct mmap_area { 706cd6a6acSopenharmony_ci void *addr; /* Start addr + len used to release memory at close */ 716cd6a6acSopenharmony_ci size_t len; 726cd6a6acSopenharmony_ci void *next_addr; /* Incremented by next_entry() */ 736cd6a6acSopenharmony_ci size_t next_len; /* Decremented by next_entry() */ 746cd6a6acSopenharmony_ci struct mmap_area *next; 756cd6a6acSopenharmony_ci}; 766cd6a6acSopenharmony_ci 776cd6a6acSopenharmony_ci/* Our stored configuration */ 786cd6a6acSopenharmony_cistruct saved_data { 796cd6a6acSopenharmony_ci /* 806cd6a6acSopenharmony_ci * The array of specifications, initially in the same order as in 816cd6a6acSopenharmony_ci * the specification file. Sorting occurs based on hasMetaChars. 826cd6a6acSopenharmony_ci */ 836cd6a6acSopenharmony_ci struct spec *spec_arr; 846cd6a6acSopenharmony_ci unsigned int nspec; 856cd6a6acSopenharmony_ci unsigned int alloc_specs; 866cd6a6acSopenharmony_ci 876cd6a6acSopenharmony_ci /* 886cd6a6acSopenharmony_ci * The array of regular expression stems. 896cd6a6acSopenharmony_ci */ 906cd6a6acSopenharmony_ci struct stem *stem_arr; 916cd6a6acSopenharmony_ci int num_stems; 926cd6a6acSopenharmony_ci int alloc_stems; 936cd6a6acSopenharmony_ci struct mmap_area *mmap_areas; 946cd6a6acSopenharmony_ci 956cd6a6acSopenharmony_ci /* substitution support */ 966cd6a6acSopenharmony_ci struct selabel_sub *dist_subs; 976cd6a6acSopenharmony_ci struct selabel_sub *subs; 986cd6a6acSopenharmony_ci}; 996cd6a6acSopenharmony_ci 1006cd6a6acSopenharmony_cistatic inline mode_t string_to_mode(char *mode) 1016cd6a6acSopenharmony_ci{ 1026cd6a6acSopenharmony_ci size_t len; 1036cd6a6acSopenharmony_ci 1046cd6a6acSopenharmony_ci if (!mode) 1056cd6a6acSopenharmony_ci return 0; 1066cd6a6acSopenharmony_ci len = strlen(mode); 1076cd6a6acSopenharmony_ci if (mode[0] != '-' || len != 2) 1086cd6a6acSopenharmony_ci return -1; 1096cd6a6acSopenharmony_ci switch (mode[1]) { 1106cd6a6acSopenharmony_ci case 'b': 1116cd6a6acSopenharmony_ci return S_IFBLK; 1126cd6a6acSopenharmony_ci case 'c': 1136cd6a6acSopenharmony_ci return S_IFCHR; 1146cd6a6acSopenharmony_ci case 'd': 1156cd6a6acSopenharmony_ci return S_IFDIR; 1166cd6a6acSopenharmony_ci case 'p': 1176cd6a6acSopenharmony_ci return S_IFIFO; 1186cd6a6acSopenharmony_ci case 'l': 1196cd6a6acSopenharmony_ci return S_IFLNK; 1206cd6a6acSopenharmony_ci case 's': 1216cd6a6acSopenharmony_ci return S_IFSOCK; 1226cd6a6acSopenharmony_ci case '-': 1236cd6a6acSopenharmony_ci return S_IFREG; 1246cd6a6acSopenharmony_ci default: 1256cd6a6acSopenharmony_ci return -1; 1266cd6a6acSopenharmony_ci } 1276cd6a6acSopenharmony_ci /* impossible to get here */ 1286cd6a6acSopenharmony_ci return 0; 1296cd6a6acSopenharmony_ci} 1306cd6a6acSopenharmony_ci 1316cd6a6acSopenharmony_cistatic inline int grow_specs(struct saved_data *data) 1326cd6a6acSopenharmony_ci{ 1336cd6a6acSopenharmony_ci struct spec *specs; 1346cd6a6acSopenharmony_ci size_t new_specs, total_specs; 1356cd6a6acSopenharmony_ci 1366cd6a6acSopenharmony_ci if (data->nspec < data->alloc_specs) 1376cd6a6acSopenharmony_ci return 0; 1386cd6a6acSopenharmony_ci 1396cd6a6acSopenharmony_ci new_specs = data->nspec + 16; 1406cd6a6acSopenharmony_ci total_specs = data->nspec + new_specs; 1416cd6a6acSopenharmony_ci 1426cd6a6acSopenharmony_ci specs = realloc(data->spec_arr, total_specs * sizeof(*specs)); 1436cd6a6acSopenharmony_ci if (!specs) { 1446cd6a6acSopenharmony_ci perror("realloc"); 1456cd6a6acSopenharmony_ci return -1; 1466cd6a6acSopenharmony_ci } 1476cd6a6acSopenharmony_ci 1486cd6a6acSopenharmony_ci /* blank the new entries */ 1496cd6a6acSopenharmony_ci memset(&specs[data->nspec], 0, new_specs * sizeof(*specs)); 1506cd6a6acSopenharmony_ci 1516cd6a6acSopenharmony_ci data->spec_arr = specs; 1526cd6a6acSopenharmony_ci data->alloc_specs = total_specs; 1536cd6a6acSopenharmony_ci return 0; 1546cd6a6acSopenharmony_ci} 1556cd6a6acSopenharmony_ci 1566cd6a6acSopenharmony_ci/* Determine if the regular expression specification has any meta characters. */ 1576cd6a6acSopenharmony_cistatic inline void spec_hasMetaChars(struct spec *spec) 1586cd6a6acSopenharmony_ci{ 1596cd6a6acSopenharmony_ci char *c; 1606cd6a6acSopenharmony_ci int len; 1616cd6a6acSopenharmony_ci char *end; 1626cd6a6acSopenharmony_ci 1636cd6a6acSopenharmony_ci c = spec->regex_str; 1646cd6a6acSopenharmony_ci len = strlen(spec->regex_str); 1656cd6a6acSopenharmony_ci end = c + len; 1666cd6a6acSopenharmony_ci 1676cd6a6acSopenharmony_ci spec->hasMetaChars = 0; 1686cd6a6acSopenharmony_ci spec->prefix_len = len; 1696cd6a6acSopenharmony_ci 1706cd6a6acSopenharmony_ci /* Look at each character in the RE specification string for a 1716cd6a6acSopenharmony_ci * meta character. Return when any meta character reached. */ 1726cd6a6acSopenharmony_ci while (c < end) { 1736cd6a6acSopenharmony_ci switch (*c) { 1746cd6a6acSopenharmony_ci case '.': 1756cd6a6acSopenharmony_ci case '^': 1766cd6a6acSopenharmony_ci case '$': 1776cd6a6acSopenharmony_ci case '?': 1786cd6a6acSopenharmony_ci case '*': 1796cd6a6acSopenharmony_ci case '+': 1806cd6a6acSopenharmony_ci case '|': 1816cd6a6acSopenharmony_ci case '[': 1826cd6a6acSopenharmony_ci case '(': 1836cd6a6acSopenharmony_ci case '{': 1846cd6a6acSopenharmony_ci spec->hasMetaChars = 1; 1856cd6a6acSopenharmony_ci spec->prefix_len = c - spec->regex_str; 1866cd6a6acSopenharmony_ci return; 1876cd6a6acSopenharmony_ci case '\\': /* skip the next character */ 1886cd6a6acSopenharmony_ci c++; 1896cd6a6acSopenharmony_ci break; 1906cd6a6acSopenharmony_ci default: 1916cd6a6acSopenharmony_ci break; 1926cd6a6acSopenharmony_ci 1936cd6a6acSopenharmony_ci } 1946cd6a6acSopenharmony_ci c++; 1956cd6a6acSopenharmony_ci } 1966cd6a6acSopenharmony_ci} 1976cd6a6acSopenharmony_ci 1986cd6a6acSopenharmony_ci/* Move exact pathname specifications to the end. */ 1996cd6a6acSopenharmony_cistatic inline int sort_specs(struct saved_data *data) 2006cd6a6acSopenharmony_ci{ 2016cd6a6acSopenharmony_ci struct spec *spec_copy; 2026cd6a6acSopenharmony_ci struct spec spec; 2036cd6a6acSopenharmony_ci unsigned int i; 2046cd6a6acSopenharmony_ci int front, back; 2056cd6a6acSopenharmony_ci size_t len = sizeof(*spec_copy); 2066cd6a6acSopenharmony_ci 2076cd6a6acSopenharmony_ci spec_copy = malloc(len * data->nspec); 2086cd6a6acSopenharmony_ci if (!spec_copy) 2096cd6a6acSopenharmony_ci return -1; 2106cd6a6acSopenharmony_ci 2116cd6a6acSopenharmony_ci /* first move the exact pathnames to the back */ 2126cd6a6acSopenharmony_ci front = 0; 2136cd6a6acSopenharmony_ci back = data->nspec - 1; 2146cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) { 2156cd6a6acSopenharmony_ci if (data->spec_arr[i].hasMetaChars) 2166cd6a6acSopenharmony_ci memcpy(&spec_copy[front++], &data->spec_arr[i], len); 2176cd6a6acSopenharmony_ci else 2186cd6a6acSopenharmony_ci memcpy(&spec_copy[back--], &data->spec_arr[i], len); 2196cd6a6acSopenharmony_ci } 2206cd6a6acSopenharmony_ci 2216cd6a6acSopenharmony_ci /* 2226cd6a6acSopenharmony_ci * now the exact pathnames are at the end, but they are in the reverse 2236cd6a6acSopenharmony_ci * order. Since 'front' is now the first of the 'exact' we can run 2246cd6a6acSopenharmony_ci * that part of the array switching the front and back element. 2256cd6a6acSopenharmony_ci */ 2266cd6a6acSopenharmony_ci back = data->nspec - 1; 2276cd6a6acSopenharmony_ci while (front < back) { 2286cd6a6acSopenharmony_ci /* save the front */ 2296cd6a6acSopenharmony_ci memcpy(&spec, &spec_copy[front], len); 2306cd6a6acSopenharmony_ci /* move the back to the front */ 2316cd6a6acSopenharmony_ci memcpy(&spec_copy[front], &spec_copy[back], len); 2326cd6a6acSopenharmony_ci /* put the old front in the back */ 2336cd6a6acSopenharmony_ci memcpy(&spec_copy[back], &spec, len); 2346cd6a6acSopenharmony_ci front++; 2356cd6a6acSopenharmony_ci back--; 2366cd6a6acSopenharmony_ci } 2376cd6a6acSopenharmony_ci 2386cd6a6acSopenharmony_ci free(data->spec_arr); 2396cd6a6acSopenharmony_ci data->spec_arr = spec_copy; 2406cd6a6acSopenharmony_ci 2416cd6a6acSopenharmony_ci return 0; 2426cd6a6acSopenharmony_ci} 2436cd6a6acSopenharmony_ci 2446cd6a6acSopenharmony_ci/* Return the length of the text that can be considered the stem, returns 0 2456cd6a6acSopenharmony_ci * if there is no identifiable stem */ 2466cd6a6acSopenharmony_cistatic inline int get_stem_from_spec(const char *const buf) 2476cd6a6acSopenharmony_ci{ 2486cd6a6acSopenharmony_ci const char *tmp = strchr(buf + 1, '/'); 2496cd6a6acSopenharmony_ci const char *ind; 2506cd6a6acSopenharmony_ci 2516cd6a6acSopenharmony_ci if (!tmp) 2526cd6a6acSopenharmony_ci return 0; 2536cd6a6acSopenharmony_ci 2546cd6a6acSopenharmony_ci for (ind = buf; ind < tmp; ind++) { 2556cd6a6acSopenharmony_ci if (strchr(".^$?*+|[({", (int)*ind)) 2566cd6a6acSopenharmony_ci return 0; 2576cd6a6acSopenharmony_ci } 2586cd6a6acSopenharmony_ci return tmp - buf; 2596cd6a6acSopenharmony_ci} 2606cd6a6acSopenharmony_ci 2616cd6a6acSopenharmony_ci/* 2626cd6a6acSopenharmony_ci * return the stemid given a string and a length 2636cd6a6acSopenharmony_ci */ 2646cd6a6acSopenharmony_cistatic inline int find_stem(struct saved_data *data, const char *buf, 2656cd6a6acSopenharmony_ci int stem_len) 2666cd6a6acSopenharmony_ci{ 2676cd6a6acSopenharmony_ci int i; 2686cd6a6acSopenharmony_ci 2696cd6a6acSopenharmony_ci for (i = 0; i < data->num_stems; i++) { 2706cd6a6acSopenharmony_ci if (stem_len == data->stem_arr[i].len && 2716cd6a6acSopenharmony_ci !strncmp(buf, data->stem_arr[i].buf, stem_len)) 2726cd6a6acSopenharmony_ci return i; 2736cd6a6acSopenharmony_ci } 2746cd6a6acSopenharmony_ci 2756cd6a6acSopenharmony_ci return -1; 2766cd6a6acSopenharmony_ci} 2776cd6a6acSopenharmony_ci 2786cd6a6acSopenharmony_ci/* returns the index of the new stored object */ 2796cd6a6acSopenharmony_cistatic inline int store_stem(struct saved_data *data, char *buf, int stem_len) 2806cd6a6acSopenharmony_ci{ 2816cd6a6acSopenharmony_ci int num = data->num_stems; 2826cd6a6acSopenharmony_ci 2836cd6a6acSopenharmony_ci if (data->alloc_stems == num) { 2846cd6a6acSopenharmony_ci struct stem *tmp_arr; 2856cd6a6acSopenharmony_ci int alloc_stems = data->alloc_stems * 2 + 16; 2866cd6a6acSopenharmony_ci tmp_arr = realloc(data->stem_arr, 2876cd6a6acSopenharmony_ci sizeof(*tmp_arr) * alloc_stems); 2886cd6a6acSopenharmony_ci if (!tmp_arr) { 2896cd6a6acSopenharmony_ci return -1; 2906cd6a6acSopenharmony_ci } 2916cd6a6acSopenharmony_ci data->alloc_stems = alloc_stems; 2926cd6a6acSopenharmony_ci data->stem_arr = tmp_arr; 2936cd6a6acSopenharmony_ci } 2946cd6a6acSopenharmony_ci data->stem_arr[num].len = stem_len; 2956cd6a6acSopenharmony_ci data->stem_arr[num].buf = buf; 2966cd6a6acSopenharmony_ci data->stem_arr[num].from_mmap = 0; 2976cd6a6acSopenharmony_ci data->num_stems++; 2986cd6a6acSopenharmony_ci 2996cd6a6acSopenharmony_ci return num; 3006cd6a6acSopenharmony_ci} 3016cd6a6acSopenharmony_ci 3026cd6a6acSopenharmony_ci/* find the stem of a file spec, returns the index into stem_arr for a new 3036cd6a6acSopenharmony_ci * or existing stem, (or -1 if there is no possible stem - IE for a file in 3046cd6a6acSopenharmony_ci * the root directory or a regex that is too complex for us). */ 3056cd6a6acSopenharmony_cistatic inline int find_stem_from_spec(struct saved_data *data, const char *buf) 3066cd6a6acSopenharmony_ci{ 3076cd6a6acSopenharmony_ci int stem_len = get_stem_from_spec(buf); 3086cd6a6acSopenharmony_ci int stemid; 3096cd6a6acSopenharmony_ci char *stem; 3106cd6a6acSopenharmony_ci int r; 3116cd6a6acSopenharmony_ci 3126cd6a6acSopenharmony_ci if (!stem_len) 3136cd6a6acSopenharmony_ci return -1; 3146cd6a6acSopenharmony_ci 3156cd6a6acSopenharmony_ci stemid = find_stem(data, buf, stem_len); 3166cd6a6acSopenharmony_ci if (stemid >= 0) 3176cd6a6acSopenharmony_ci return stemid; 3186cd6a6acSopenharmony_ci 3196cd6a6acSopenharmony_ci /* not found, allocate a new one */ 3206cd6a6acSopenharmony_ci stem = strndup(buf, stem_len); 3216cd6a6acSopenharmony_ci if (!stem) 3226cd6a6acSopenharmony_ci return -1; 3236cd6a6acSopenharmony_ci 3246cd6a6acSopenharmony_ci r = store_stem(data, stem, stem_len); 3256cd6a6acSopenharmony_ci if (r < 0) 3266cd6a6acSopenharmony_ci free(stem); 3276cd6a6acSopenharmony_ci 3286cd6a6acSopenharmony_ci return r; 3296cd6a6acSopenharmony_ci} 3306cd6a6acSopenharmony_ci 3316cd6a6acSopenharmony_ci/* This will always check for buffer over-runs and either read the next entry 3326cd6a6acSopenharmony_ci * if buf != NULL or skip over the entry (as these areas are mapped in the 3336cd6a6acSopenharmony_ci * current buffer). */ 3346cd6a6acSopenharmony_cistatic inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes) 3356cd6a6acSopenharmony_ci{ 3366cd6a6acSopenharmony_ci if (bytes > fp->next_len) 3376cd6a6acSopenharmony_ci return -1; 3386cd6a6acSopenharmony_ci 3396cd6a6acSopenharmony_ci if (buf) 3406cd6a6acSopenharmony_ci memcpy(buf, fp->next_addr, bytes); 3416cd6a6acSopenharmony_ci 3426cd6a6acSopenharmony_ci fp->next_addr = (char *)fp->next_addr + bytes; 3436cd6a6acSopenharmony_ci fp->next_len -= bytes; 3446cd6a6acSopenharmony_ci return 0; 3456cd6a6acSopenharmony_ci} 3466cd6a6acSopenharmony_ci 3476cd6a6acSopenharmony_cistatic inline int compile_regex(struct spec *spec, const char **errbuf) 3486cd6a6acSopenharmony_ci{ 3496cd6a6acSopenharmony_ci char *reg_buf, *anchored_regex, *cp; 3506cd6a6acSopenharmony_ci struct regex_error_data error_data; 3516cd6a6acSopenharmony_ci static char regex_error_format_buffer[256]; 3526cd6a6acSopenharmony_ci size_t len; 3536cd6a6acSopenharmony_ci int rc; 3546cd6a6acSopenharmony_ci bool regex_compiled; 3556cd6a6acSopenharmony_ci 3566cd6a6acSopenharmony_ci /* We really want pthread_once() here, but since its 3576cd6a6acSopenharmony_ci * init_routine does not take a parameter, it's not possible 3586cd6a6acSopenharmony_ci * to use, so we generate the same effect with atomics and a 3596cd6a6acSopenharmony_ci * mutex */ 3606cd6a6acSopenharmony_ci#ifdef __ATOMIC_RELAXED 3616cd6a6acSopenharmony_ci regex_compiled = 3626cd6a6acSopenharmony_ci __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE); 3636cd6a6acSopenharmony_ci#else 3646cd6a6acSopenharmony_ci /* GCC <4.7 */ 3656cd6a6acSopenharmony_ci __sync_synchronize(); 3666cd6a6acSopenharmony_ci regex_compiled = spec->regex_compiled; 3676cd6a6acSopenharmony_ci#endif 3686cd6a6acSopenharmony_ci if (regex_compiled) { 3696cd6a6acSopenharmony_ci return 0; /* already done */ 3706cd6a6acSopenharmony_ci } 3716cd6a6acSopenharmony_ci 3726cd6a6acSopenharmony_ci __pthread_mutex_lock(&spec->regex_lock); 3736cd6a6acSopenharmony_ci /* Check if another thread compiled the regex while we waited 3746cd6a6acSopenharmony_ci * on the mutex */ 3756cd6a6acSopenharmony_ci#ifdef __ATOMIC_RELAXED 3766cd6a6acSopenharmony_ci regex_compiled = 3776cd6a6acSopenharmony_ci __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE); 3786cd6a6acSopenharmony_ci#else 3796cd6a6acSopenharmony_ci /* GCC <4.7 */ 3806cd6a6acSopenharmony_ci __sync_synchronize(); 3816cd6a6acSopenharmony_ci regex_compiled = spec->regex_compiled; 3826cd6a6acSopenharmony_ci#endif 3836cd6a6acSopenharmony_ci if (regex_compiled) { 3846cd6a6acSopenharmony_ci __pthread_mutex_unlock(&spec->regex_lock); 3856cd6a6acSopenharmony_ci return 0; 3866cd6a6acSopenharmony_ci } 3876cd6a6acSopenharmony_ci 3886cd6a6acSopenharmony_ci reg_buf = spec->regex_str; 3896cd6a6acSopenharmony_ci /* Anchor the regular expression. */ 3906cd6a6acSopenharmony_ci len = strlen(reg_buf); 3916cd6a6acSopenharmony_ci cp = anchored_regex = malloc(len + 3); 3926cd6a6acSopenharmony_ci if (!anchored_regex) { 3936cd6a6acSopenharmony_ci if (errbuf) 3946cd6a6acSopenharmony_ci *errbuf = "out of memory"; 3956cd6a6acSopenharmony_ci __pthread_mutex_unlock(&spec->regex_lock); 3966cd6a6acSopenharmony_ci return -1; 3976cd6a6acSopenharmony_ci } 3986cd6a6acSopenharmony_ci 3996cd6a6acSopenharmony_ci /* Create ^...$ regexp. */ 4006cd6a6acSopenharmony_ci *cp++ = '^'; 4016cd6a6acSopenharmony_ci memcpy(cp, reg_buf, len); 4026cd6a6acSopenharmony_ci cp += len; 4036cd6a6acSopenharmony_ci *cp++ = '$'; 4046cd6a6acSopenharmony_ci *cp = '\0'; 4056cd6a6acSopenharmony_ci 4066cd6a6acSopenharmony_ci /* Compile the regular expression. */ 4076cd6a6acSopenharmony_ci rc = regex_prepare_data(&spec->regex, anchored_regex, &error_data); 4086cd6a6acSopenharmony_ci free(anchored_regex); 4096cd6a6acSopenharmony_ci if (rc < 0) { 4106cd6a6acSopenharmony_ci if (errbuf) { 4116cd6a6acSopenharmony_ci regex_format_error(&error_data, 4126cd6a6acSopenharmony_ci regex_error_format_buffer, 4136cd6a6acSopenharmony_ci sizeof(regex_error_format_buffer)); 4146cd6a6acSopenharmony_ci *errbuf = ®ex_error_format_buffer[0]; 4156cd6a6acSopenharmony_ci } 4166cd6a6acSopenharmony_ci __pthread_mutex_unlock(&spec->regex_lock); 4176cd6a6acSopenharmony_ci return -1; 4186cd6a6acSopenharmony_ci } 4196cd6a6acSopenharmony_ci 4206cd6a6acSopenharmony_ci /* Done. */ 4216cd6a6acSopenharmony_ci#ifdef __ATOMIC_RELAXED 4226cd6a6acSopenharmony_ci __atomic_store_n(&spec->regex_compiled, true, __ATOMIC_RELEASE); 4236cd6a6acSopenharmony_ci#else 4246cd6a6acSopenharmony_ci /* GCC <4.7 */ 4256cd6a6acSopenharmony_ci spec->regex_compiled = true; 4266cd6a6acSopenharmony_ci __sync_synchronize(); 4276cd6a6acSopenharmony_ci#endif 4286cd6a6acSopenharmony_ci __pthread_mutex_unlock(&spec->regex_lock); 4296cd6a6acSopenharmony_ci return 0; 4306cd6a6acSopenharmony_ci} 4316cd6a6acSopenharmony_ci 4326cd6a6acSopenharmony_ci/* This service is used by label_file.c process_file() and 4336cd6a6acSopenharmony_ci * utils/sefcontext_compile.c */ 4346cd6a6acSopenharmony_cistatic inline int process_line(struct selabel_handle *rec, 4356cd6a6acSopenharmony_ci const char *path, const char *prefix, 4366cd6a6acSopenharmony_ci char *line_buf, unsigned lineno) 4376cd6a6acSopenharmony_ci{ 4386cd6a6acSopenharmony_ci int items, len, rc; 4396cd6a6acSopenharmony_ci char *regex = NULL, *type = NULL, *context = NULL; 4406cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 4416cd6a6acSopenharmony_ci struct spec *spec_arr; 4426cd6a6acSopenharmony_ci unsigned int nspec = data->nspec; 4436cd6a6acSopenharmony_ci const char *errbuf = NULL; 4446cd6a6acSopenharmony_ci 4456cd6a6acSopenharmony_ci items = read_spec_entries(line_buf, &errbuf, 3, ®ex, &type, &context); 4466cd6a6acSopenharmony_ci if (items < 0) { 4476cd6a6acSopenharmony_ci if (errbuf) { 4486cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, 4496cd6a6acSopenharmony_ci "%s: line %u error due to: %s\n", path, 4506cd6a6acSopenharmony_ci lineno, errbuf); 4516cd6a6acSopenharmony_ci } else { 4526cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, 4536cd6a6acSopenharmony_ci "%s: line %u error due to: %m\n", path, 4546cd6a6acSopenharmony_ci lineno); 4556cd6a6acSopenharmony_ci } 4566cd6a6acSopenharmony_ci return -1; 4576cd6a6acSopenharmony_ci } 4586cd6a6acSopenharmony_ci 4596cd6a6acSopenharmony_ci if (items == 0) 4606cd6a6acSopenharmony_ci return items; 4616cd6a6acSopenharmony_ci 4626cd6a6acSopenharmony_ci if (items < 2) { 4636cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_ERROR, 4646cd6a6acSopenharmony_ci "%s: line %u is missing fields\n", path, 4656cd6a6acSopenharmony_ci lineno); 4666cd6a6acSopenharmony_ci if (items == 1) 4676cd6a6acSopenharmony_ci free(regex); 4686cd6a6acSopenharmony_ci errno = EINVAL; 4696cd6a6acSopenharmony_ci return -1; 4706cd6a6acSopenharmony_ci } else if (items == 2) { 4716cd6a6acSopenharmony_ci /* The type field is optional. */ 4726cd6a6acSopenharmony_ci context = type; 4736cd6a6acSopenharmony_ci type = 0; 4746cd6a6acSopenharmony_ci } 4756cd6a6acSopenharmony_ci 4766cd6a6acSopenharmony_ci len = get_stem_from_spec(regex); 4776cd6a6acSopenharmony_ci if (len && prefix && strncmp(prefix, regex, len)) { 4786cd6a6acSopenharmony_ci /* Stem of regex does not match requested prefix, discard. */ 4796cd6a6acSopenharmony_ci free(regex); 4806cd6a6acSopenharmony_ci free(type); 4816cd6a6acSopenharmony_ci free(context); 4826cd6a6acSopenharmony_ci return 0; 4836cd6a6acSopenharmony_ci } 4846cd6a6acSopenharmony_ci 4856cd6a6acSopenharmony_ci rc = grow_specs(data); 4866cd6a6acSopenharmony_ci if (rc) 4876cd6a6acSopenharmony_ci return rc; 4886cd6a6acSopenharmony_ci 4896cd6a6acSopenharmony_ci spec_arr = data->spec_arr; 4906cd6a6acSopenharmony_ci 4916cd6a6acSopenharmony_ci /* process and store the specification in spec. */ 4926cd6a6acSopenharmony_ci spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); 4936cd6a6acSopenharmony_ci spec_arr[nspec].regex_str = regex; 4946cd6a6acSopenharmony_ci __pthread_mutex_init(&spec_arr[nspec].regex_lock, NULL); 4956cd6a6acSopenharmony_ci spec_arr[nspec].regex_compiled = false; 4966cd6a6acSopenharmony_ci 4976cd6a6acSopenharmony_ci spec_arr[nspec].type_str = type; 4986cd6a6acSopenharmony_ci spec_arr[nspec].mode = 0; 4996cd6a6acSopenharmony_ci 5006cd6a6acSopenharmony_ci spec_arr[nspec].lr.ctx_raw = context; 5016cd6a6acSopenharmony_ci spec_arr[nspec].lr.lineno = lineno; 5026cd6a6acSopenharmony_ci 5036cd6a6acSopenharmony_ci /* 5046cd6a6acSopenharmony_ci * bump data->nspecs to cause closef() to cover it in its free 5056cd6a6acSopenharmony_ci * but do not bump nspec since it's used below. 5066cd6a6acSopenharmony_ci */ 5076cd6a6acSopenharmony_ci data->nspec++; 5086cd6a6acSopenharmony_ci 5096cd6a6acSopenharmony_ci if (rec->validating 5106cd6a6acSopenharmony_ci && compile_regex(&spec_arr[nspec], &errbuf)) { 5116cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_ERROR, 5126cd6a6acSopenharmony_ci "%s: line %u has invalid regex %s: %s\n", 5136cd6a6acSopenharmony_ci path, lineno, regex, errbuf); 5146cd6a6acSopenharmony_ci errno = EINVAL; 5156cd6a6acSopenharmony_ci return -1; 5166cd6a6acSopenharmony_ci } 5176cd6a6acSopenharmony_ci 5186cd6a6acSopenharmony_ci if (type) { 5196cd6a6acSopenharmony_ci mode_t mode = string_to_mode(type); 5206cd6a6acSopenharmony_ci 5216cd6a6acSopenharmony_ci if (mode == (mode_t)-1) { 5226cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_ERROR, 5236cd6a6acSopenharmony_ci "%s: line %u has invalid file type %s\n", 5246cd6a6acSopenharmony_ci path, lineno, type); 5256cd6a6acSopenharmony_ci errno = EINVAL; 5266cd6a6acSopenharmony_ci return -1; 5276cd6a6acSopenharmony_ci } 5286cd6a6acSopenharmony_ci spec_arr[nspec].mode = mode; 5296cd6a6acSopenharmony_ci } 5306cd6a6acSopenharmony_ci 5316cd6a6acSopenharmony_ci /* Determine if specification has 5326cd6a6acSopenharmony_ci * any meta characters in the RE */ 5336cd6a6acSopenharmony_ci spec_hasMetaChars(&spec_arr[nspec]); 5346cd6a6acSopenharmony_ci 5356cd6a6acSopenharmony_ci if (strcmp(context, "<<none>>") && rec->validating) 5366cd6a6acSopenharmony_ci return compat_validate(rec, &spec_arr[nspec].lr, path, lineno); 5376cd6a6acSopenharmony_ci 5386cd6a6acSopenharmony_ci return 0; 5396cd6a6acSopenharmony_ci} 5406cd6a6acSopenharmony_ci 5416cd6a6acSopenharmony_ci#endif /* _SELABEL_FILE_H_ */ 542