1 #ifndef _SELABEL_FILE_H_ 2 #define _SELABEL_FILE_H_ 3 4 #include <sys/stat.h> 5 6 #include "label_internal.h" 7 8 #define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a 9 #define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 10 #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 11 #define SELINUX_COMPILED_FCONTEXT_MAX_VERS 2 12 13 /* Prior to verison 8.20, libpcre did not have pcre_free_study() */ 14 #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20)) 15 #define pcre_free_study pcre_free 16 #endif 17 18 /* A file security context specification. */ 19 struct spec { 20 struct selabel_lookup_rec lr; /* holds contexts for lookup result */ 21 char *regex_str; /* regular expession string for diagnostics */ 22 char *type_str; /* type string for diagnostic messages */ 23 pcre *regex; /* compiled regular expression */ 24 union { 25 pcre_extra *sd; /* pointer to extra compiled stuff */ 26 pcre_extra lsd; /* used to hold the mmap'd version */ 27 }; 28 mode_t mode; /* mode format value */ 29 int matches; /* number of matching pathnames */ 30 int stem_id; /* indicates which stem-compression item */ 31 char hasMetaChars; /* regular expression has meta-chars */ 32 char regcomp; /* regex_str has been compiled to regex */ 33 char from_mmap; /* this spec is from an mmap of the data */ 34 }; 35 36 /* A regular expression stem */ 37 struct stem { 38 char *buf; 39 int len; 40 char from_mmap; 41 }; 42 43 /* Where we map the file in during selabel_open() */ 44 struct mmap_area { 45 void *addr; 46 size_t len; 47 struct mmap_area *next; 48 }; 49 50 /* Our stored configuration */ 51 struct saved_data { 52 /* 53 * The array of specifications, initially in the same order as in 54 * the specification file. Sorting occurs based on hasMetaChars. 55 */ 56 struct spec *spec_arr; 57 unsigned int nspec; 58 unsigned int alloc_specs; 59 60 /* 61 * The array of regular expression stems. 62 */ 63 struct stem *stem_arr; 64 int num_stems; 65 int alloc_stems; 66 struct mmap_area *mmap_areas; 67 }; 68 69 static inline pcre_extra *get_pcre_extra(struct spec *spec) 70 { 71 if (spec->from_mmap) 72 return &spec->lsd; 73 else 74 return spec->sd; 75 } 76 77 static inline mode_t string_to_mode(char *mode) 78 { 79 size_t len; 80 81 if (!mode) 82 return 0; 83 len = strlen(mode); 84 if (mode[0] != '-' || len != 2) 85 return -1; 86 switch (mode[1]) { 87 case 'b': 88 return S_IFBLK; 89 case 'c': 90 return S_IFCHR; 91 case 'd': 92 return S_IFDIR; 93 case 'p': 94 return S_IFIFO; 95 case 'l': 96 return S_IFLNK; 97 case 's': 98 return S_IFSOCK; 99 case '-': 100 return S_IFREG; 101 default: 102 return -1; 103 } 104 /* impossible to get here */ 105 return 0; 106 } 107 108 static inline int grow_specs(struct saved_data *data) 109 { 110 struct spec *specs; 111 size_t new_specs, total_specs; 112 113 if (data->nspec < data->alloc_specs) 114 return 0; 115 116 new_specs = data->nspec + 16; 117 total_specs = data->nspec + new_specs; 118 119 specs = realloc(data->spec_arr, total_specs * sizeof(*specs)); 120 if (!specs) { 121 perror("realloc"); 122 return -1; 123 } 124 125 /* blank the new entries */ 126 memset(&specs[data->nspec], 0, new_specs * sizeof(*specs)); 127 128 data->spec_arr = specs; 129 data->alloc_specs = total_specs; 130 return 0; 131 } 132 133 /* Determine if the regular expression specification has any meta characters. */ 134 static inline void spec_hasMetaChars(struct spec *spec) 135 { 136 char *c; 137 int len; 138 char *end; 139 140 c = spec->regex_str; 141 len = strlen(spec->regex_str); 142 end = c + len; 143 144 spec->hasMetaChars = 0; 145 146 /* Look at each character in the RE specification string for a 147 * meta character. Return when any meta character reached. */ 148 while (c < end) { 149 switch (*c) { 150 case '.': 151 case '^': 152 case '$': 153 case '?': 154 case '*': 155 case '+': 156 case '|': 157 case '[': 158 case '(': 159 case '{': 160 spec->hasMetaChars = 1; 161 return; 162 case '\\': /* skip the next character */ 163 c++; 164 break; 165 default: 166 break; 167 168 } 169 c++; 170 } 171 return; 172 } 173 174 /* Move exact pathname specifications to the end. */ 175 static inline int sort_specs(struct saved_data *data) 176 { 177 struct spec *spec_copy; 178 struct spec spec; 179 unsigned int i; 180 int front, back; 181 size_t len = sizeof(*spec_copy); 182 183 spec_copy = malloc(len * data->nspec); 184 if (!spec_copy) 185 return -1; 186 187 /* first move the exact pathnames to the back */ 188 front = 0; 189 back = data->nspec - 1; 190 for (i = 0; i < data->nspec; i++) { 191 if (data->spec_arr[i].hasMetaChars) 192 memcpy(&spec_copy[front++], &data->spec_arr[i], len); 193 else 194 memcpy(&spec_copy[back--], &data->spec_arr[i], len); 195 } 196 197 /* 198 * now the exact pathnames are at the end, but they are in the reverse order. 199 * since 'front' is now the first of the 'exact' we can run that part of the 200 * array switching the front and back element. 201 */ 202 back = data->nspec - 1; 203 while (front < back) { 204 /* save the front */ 205 memcpy(&spec, &spec_copy[front], len); 206 /* move the back to the front */ 207 memcpy(&spec_copy[front], &spec_copy[back], len); 208 /* put the old front in the back */ 209 memcpy(&spec_copy[back], &spec, len); 210 front++; 211 back--; 212 } 213 214 free(data->spec_arr); 215 data->spec_arr = spec_copy; 216 217 return 0; 218 } 219 220 /* Return the length of the text that can be considered the stem, returns 0 221 * if there is no identifiable stem */ 222 static inline int get_stem_from_spec(const char *const buf) 223 { 224 const char *tmp = strchr(buf + 1, '/'); 225 const char *ind; 226 227 if (!tmp) 228 return 0; 229 230 for (ind = buf; ind < tmp; ind++) { 231 if (strchr(".^$?*+|[({", (int)*ind)) 232 return 0; 233 } 234 return tmp - buf; 235 } 236 237 /* 238 * return the stemid given a string and a length 239 */ 240 static inline int find_stem(struct saved_data *data, const char *buf, int stem_len) 241 { 242 int i; 243 244 for (i = 0; i < data->num_stems; i++) { 245 if (stem_len == data->stem_arr[i].len && 246 !strncmp(buf, data->stem_arr[i].buf, stem_len)) 247 return i; 248 } 249 250 return -1; 251 } 252 253 /* returns the index of the new stored object */ 254 static inline int store_stem(struct saved_data *data, char *buf, int stem_len) 255 { 256 int num = data->num_stems; 257 258 if (data->alloc_stems == num) { 259 struct stem *tmp_arr; 260 261 data->alloc_stems = data->alloc_stems * 2 + 16; 262 tmp_arr = realloc(data->stem_arr, 263 sizeof(*tmp_arr) * data->alloc_stems); 264 if (!tmp_arr) 265 return -1; 266 data->stem_arr = tmp_arr; 267 } 268 data->stem_arr[num].len = stem_len; 269 data->stem_arr[num].buf = buf; 270 data->num_stems++; 271 272 return num; 273 } 274 275 /* find the stem of a file spec, returns the index into stem_arr for a new 276 * or existing stem, (or -1 if there is no possible stem - IE for a file in 277 * the root directory or a regex that is too complex for us). */ 278 static inline int find_stem_from_spec(struct saved_data *data, const char *buf) 279 { 280 int stem_len = get_stem_from_spec(buf); 281 int stemid; 282 char *stem; 283 284 if (!stem_len) 285 return -1; 286 287 stemid = find_stem(data, buf, stem_len); 288 if (stemid >= 0) 289 return stemid; 290 291 /* not found, allocate a new one */ 292 stem = strndup(buf, stem_len); 293 if (!stem) 294 return -1; 295 296 return store_stem(data, stem, stem_len); 297 } 298 299 #endif /* _SELABEL_FILE_H_ */ 300