• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_pcre_extra(struct spec * spec)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 
string_to_mode(char * mode)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 
grow_specs(struct saved_data * data)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. */
spec_hasMetaChars(struct spec * spec)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. */
sort_specs(struct saved_data * data)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 */
get_stem_from_spec(const char * const buf)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  */
find_stem(struct saved_data * data,const char * buf,int stem_len)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 */
store_stem(struct saved_data * data,char * buf,int stem_len)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). */
find_stem_from_spec(struct saved_data * data,const char * buf)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