Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 1 | #ifndef _SELABEL_FILE_H_ |
| 2 | #define _SELABEL_FILE_H_ |
| 3 | |
Eric Paris | f744f23 | 2012-08-22 14:20:38 -0400 | [diff] [blame] | 4 | #include <sys/stat.h> |
| 5 | |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 6 | #include "label_internal.h" |
| 7 | |
Eric Paris | 9ebd779 | 2012-08-30 13:43:54 -0700 | [diff] [blame] | 8 | #define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a |
Stephen Smalley | ac33098 | 2014-07-09 13:02:46 -0400 | [diff] [blame] | 9 | #define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 |
| 10 | #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 |
| 11 | #define SELINUX_COMPILED_FCONTEXT_MAX_VERS 2 |
Eric Paris | 9ebd779 | 2012-08-30 13:43:54 -0700 | [diff] [blame] | 12 | |
Joe MacDonald | 2864f75 | 2013-10-22 12:57:36 -0400 | [diff] [blame] | 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 | |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 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 */ |
Eric Paris | 9ebd779 | 2012-08-30 13:43:54 -0700 | [diff] [blame] | 24 | union { |
| 25 | pcre_extra *sd; /* pointer to extra compiled stuff */ |
| 26 | pcre_extra lsd; /* used to hold the mmap'd version */ |
| 27 | }; |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 28 | mode_t mode; /* mode format value */ |
| 29 | int matches; /* number of matching pathnames */ |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 30 | int stem_id; /* indicates which stem-compression item */ |
Eric Paris | 36ab97d | 2012-08-30 14:13:55 -0700 | [diff] [blame] | 31 | char hasMetaChars; /* regular expression has meta-chars */ |
| 32 | char regcomp; /* regex_str has been compiled to regex */ |
Eric Paris | 9ebd779 | 2012-08-30 13:43:54 -0700 | [diff] [blame] | 33 | char from_mmap; /* this spec is from an mmap of the data */ |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 34 | }; |
| 35 | |
| 36 | /* A regular expression stem */ |
| 37 | struct stem { |
| 38 | char *buf; |
| 39 | int len; |
Eric Paris | 9ebd779 | 2012-08-30 13:43:54 -0700 | [diff] [blame] | 40 | char from_mmap; |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 41 | }; |
| 42 | |
Eric Paris | efb6347 | 2013-01-23 14:45:23 -0500 | [diff] [blame] | 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 | |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 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; |
Eric Paris | 79b6a8d | 2012-08-29 15:54:17 -0700 | [diff] [blame] | 58 | unsigned int alloc_specs; |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 59 | |
| 60 | /* |
| 61 | * The array of regular expression stems. |
| 62 | */ |
| 63 | struct stem *stem_arr; |
| 64 | int num_stems; |
| 65 | int alloc_stems; |
Eric Paris | efb6347 | 2013-01-23 14:45:23 -0500 | [diff] [blame] | 66 | struct mmap_area *mmap_areas; |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 67 | }; |
Eric Paris | f744f23 | 2012-08-22 14:20:38 -0400 | [diff] [blame] | 68 | |
Eric Paris | ee88185 | 2012-08-27 14:43:51 -0400 | [diff] [blame] | 69 | static inline pcre_extra *get_pcre_extra(struct spec *spec) |
| 70 | { |
Eric Paris | 9ebd779 | 2012-08-30 13:43:54 -0700 | [diff] [blame] | 71 | if (spec->from_mmap) |
| 72 | return &spec->lsd; |
| 73 | else |
| 74 | return spec->sd; |
Eric Paris | ee88185 | 2012-08-27 14:43:51 -0400 | [diff] [blame] | 75 | } |
| 76 | |
Eric Paris | b948294 | 2012-08-22 16:03:27 -0400 | [diff] [blame] | 77 | static inline mode_t string_to_mode(char *mode) |
Eric Paris | f744f23 | 2012-08-22 14:20:38 -0400 | [diff] [blame] | 78 | { |
| 79 | size_t len; |
| 80 | |
Eric Paris | b948294 | 2012-08-22 16:03:27 -0400 | [diff] [blame] | 81 | if (!mode) |
Eric Paris | f744f23 | 2012-08-22 14:20:38 -0400 | [diff] [blame] | 82 | return 0; |
Eric Paris | b948294 | 2012-08-22 16:03:27 -0400 | [diff] [blame] | 83 | len = strlen(mode); |
| 84 | if (mode[0] != '-' || len != 2) |
| 85 | return -1; |
Eric Paris | f744f23 | 2012-08-22 14:20:38 -0400 | [diff] [blame] | 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: |
Eric Paris | b948294 | 2012-08-22 16:03:27 -0400 | [diff] [blame] | 102 | return -1; |
Eric Paris | f744f23 | 2012-08-22 14:20:38 -0400 | [diff] [blame] | 103 | } |
| 104 | /* impossible to get here */ |
| 105 | return 0; |
| 106 | } |
| 107 | |
Eric Paris | 79b6a8d | 2012-08-29 15:54:17 -0700 | [diff] [blame] | 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 | |
Eric Paris | 48682e2 | 2012-08-27 13:21:28 -0400 | [diff] [blame] | 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. */ |
Eric Paris | dd61029 | 2012-08-27 13:27:53 -0400 | [diff] [blame] | 148 | while (c < end) { |
Eric Paris | 48682e2 | 2012-08-27 13:21:28 -0400 | [diff] [blame] | 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 | |
Eric Paris | 2477590 | 2012-08-29 15:16:43 -0700 | [diff] [blame] | 174 | /* Move exact pathname specifications to the end. */ |
| 175 | static inline int sort_specs(struct saved_data *data) |
| 176 | { |
| 177 | struct spec *spec_copy; |
Eric Paris | 4d04f4c | 2012-08-30 18:17:26 -0700 | [diff] [blame] | 178 | struct spec spec; |
Nicolas Iooss | ae5de8a | 2014-09-14 23:41:40 +0200 | [diff] [blame] | 179 | unsigned int i; |
Eric Paris | 4d04f4c | 2012-08-30 18:17:26 -0700 | [diff] [blame] | 180 | int front, back; |
| 181 | size_t len = sizeof(*spec_copy); |
Eric Paris | 2477590 | 2012-08-29 15:16:43 -0700 | [diff] [blame] | 182 | |
Eric Paris | 4d04f4c | 2012-08-30 18:17:26 -0700 | [diff] [blame] | 183 | spec_copy = malloc(len * data->nspec); |
Eric Paris | 2477590 | 2012-08-29 15:16:43 -0700 | [diff] [blame] | 184 | if (!spec_copy) |
| 185 | return -1; |
Eric Paris | 4d04f4c | 2012-08-30 18:17:26 -0700 | [diff] [blame] | 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++) { |
Eric Paris | 2477590 | 2012-08-29 15:16:43 -0700 | [diff] [blame] | 191 | if (data->spec_arr[i].hasMetaChars) |
Eric Paris | 4d04f4c | 2012-08-30 18:17:26 -0700 | [diff] [blame] | 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 | |
Eric Paris | 2477590 | 2012-08-29 15:16:43 -0700 | [diff] [blame] | 214 | free(data->spec_arr); |
| 215 | data->spec_arr = spec_copy; |
| 216 | |
| 217 | return 0; |
| 218 | } |
| 219 | |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 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 | |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 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) |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 241 | { |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 242 | int i; |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 243 | |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 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)) |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 247 | return i; |
| 248 | } |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 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 | |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 258 | if (data->alloc_stems == num) { |
| 259 | struct stem *tmp_arr; |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 260 | |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 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; |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 269 | data->stem_arr[num].buf = buf; |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 270 | data->num_stems++; |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 271 | |
Eric Paris | 9937685 | 2012-08-22 14:41:46 -0400 | [diff] [blame] | 272 | return num; |
| 273 | } |
| 274 | |
Eric Paris | de5bc06 | 2012-08-30 11:43:36 -0700 | [diff] [blame] | 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 | |
Eric Paris | c27101a | 2012-08-22 14:02:01 -0400 | [diff] [blame] | 299 | #endif /* _SELABEL_FILE_H_ */ |