Home | History | Annotate | Download | only in src
      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