blob: e3a0445da30a5371db3b03a49d349663ee2e91c3 [file] [log] [blame]
Eric Parisc27101a2012-08-22 14:02:01 -04001#ifndef _SELABEL_FILE_H_
2#define _SELABEL_FILE_H_
3
Eric Parisf744f232012-08-22 14:20:38 -04004#include <sys/stat.h>
5
Eric Parisc27101a2012-08-22 14:02:01 -04006#include "label_internal.h"
7
Eric Paris9ebd7792012-08-30 13:43:54 -07008#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a
Stephen Smalleyac330982014-07-09 13:02:46 -04009#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1
10#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2
11#define SELINUX_COMPILED_FCONTEXT_MAX_VERS 2
Eric Paris9ebd7792012-08-30 13:43:54 -070012
Joe MacDonald2864f752013-10-22 12:57:36 -040013/* 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 Parisc27101a2012-08-22 14:02:01 -040018/* A file security context specification. */
19struct 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 Paris9ebd7792012-08-30 13:43:54 -070024 union {
25 pcre_extra *sd; /* pointer to extra compiled stuff */
26 pcre_extra lsd; /* used to hold the mmap'd version */
27 };
Eric Parisc27101a2012-08-22 14:02:01 -040028 mode_t mode; /* mode format value */
29 int matches; /* number of matching pathnames */
Eric Parisc27101a2012-08-22 14:02:01 -040030 int stem_id; /* indicates which stem-compression item */
Eric Paris36ab97d2012-08-30 14:13:55 -070031 char hasMetaChars; /* regular expression has meta-chars */
32 char regcomp; /* regex_str has been compiled to regex */
Eric Paris9ebd7792012-08-30 13:43:54 -070033 char from_mmap; /* this spec is from an mmap of the data */
Eric Parisc27101a2012-08-22 14:02:01 -040034};
35
36/* A regular expression stem */
37struct stem {
38 char *buf;
39 int len;
Eric Paris9ebd7792012-08-30 13:43:54 -070040 char from_mmap;
Eric Parisc27101a2012-08-22 14:02:01 -040041};
42
Eric Parisefb63472013-01-23 14:45:23 -050043/* Where we map the file in during selabel_open() */
44struct mmap_area {
45 void *addr;
46 size_t len;
47 struct mmap_area *next;
48};
49
Eric Parisc27101a2012-08-22 14:02:01 -040050/* Our stored configuration */
51struct 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 Paris79b6a8d2012-08-29 15:54:17 -070058 unsigned int alloc_specs;
Eric Parisc27101a2012-08-22 14:02:01 -040059
60 /*
61 * The array of regular expression stems.
62 */
63 struct stem *stem_arr;
64 int num_stems;
65 int alloc_stems;
Eric Parisefb63472013-01-23 14:45:23 -050066 struct mmap_area *mmap_areas;
Eric Parisc27101a2012-08-22 14:02:01 -040067};
Eric Parisf744f232012-08-22 14:20:38 -040068
Eric Parisee881852012-08-27 14:43:51 -040069static inline pcre_extra *get_pcre_extra(struct spec *spec)
70{
Eric Paris9ebd7792012-08-30 13:43:54 -070071 if (spec->from_mmap)
72 return &spec->lsd;
73 else
74 return spec->sd;
Eric Parisee881852012-08-27 14:43:51 -040075}
76
Eric Parisb9482942012-08-22 16:03:27 -040077static inline mode_t string_to_mode(char *mode)
Eric Parisf744f232012-08-22 14:20:38 -040078{
79 size_t len;
80
Eric Parisb9482942012-08-22 16:03:27 -040081 if (!mode)
Eric Parisf744f232012-08-22 14:20:38 -040082 return 0;
Eric Parisb9482942012-08-22 16:03:27 -040083 len = strlen(mode);
84 if (mode[0] != '-' || len != 2)
85 return -1;
Eric Parisf744f232012-08-22 14:20:38 -040086 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 Parisb9482942012-08-22 16:03:27 -0400102 return -1;
Eric Parisf744f232012-08-22 14:20:38 -0400103 }
104 /* impossible to get here */
105 return 0;
106}
107
Eric Paris79b6a8d2012-08-29 15:54:17 -0700108static 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 Paris48682e22012-08-27 13:21:28 -0400133/* Determine if the regular expression specification has any meta characters. */
134static 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 Parisdd610292012-08-27 13:27:53 -0400148 while (c < end) {
Eric Paris48682e22012-08-27 13:21:28 -0400149 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 Paris24775902012-08-29 15:16:43 -0700174/* Move exact pathname specifications to the end. */
175static inline int sort_specs(struct saved_data *data)
176{
177 struct spec *spec_copy;
Eric Paris4d04f4c2012-08-30 18:17:26 -0700178 struct spec spec;
Nicolas Ioossae5de8a2014-09-14 23:41:40 +0200179 unsigned int i;
Eric Paris4d04f4c2012-08-30 18:17:26 -0700180 int front, back;
181 size_t len = sizeof(*spec_copy);
Eric Paris24775902012-08-29 15:16:43 -0700182
Eric Paris4d04f4c2012-08-30 18:17:26 -0700183 spec_copy = malloc(len * data->nspec);
Eric Paris24775902012-08-29 15:16:43 -0700184 if (!spec_copy)
185 return -1;
Eric Paris4d04f4c2012-08-30 18:17:26 -0700186
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 Paris24775902012-08-29 15:16:43 -0700191 if (data->spec_arr[i].hasMetaChars)
Eric Paris4d04f4c2012-08-30 18:17:26 -0700192 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 Paris24775902012-08-29 15:16:43 -0700214 free(data->spec_arr);
215 data->spec_arr = spec_copy;
216
217 return 0;
218}
219
Eric Paris99376852012-08-22 14:41:46 -0400220/* Return the length of the text that can be considered the stem, returns 0
221 * if there is no identifiable stem */
222static 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 Parisde5bc062012-08-30 11:43:36 -0700237/*
238 * return the stemid given a string and a length
239 */
240static inline int find_stem(struct saved_data *data, const char *buf, int stem_len)
Eric Paris99376852012-08-22 14:41:46 -0400241{
Eric Parisde5bc062012-08-30 11:43:36 -0700242 int i;
Eric Paris99376852012-08-22 14:41:46 -0400243
Eric Parisde5bc062012-08-30 11:43:36 -0700244 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 Paris99376852012-08-22 14:41:46 -0400247 return i;
248 }
Eric Parisde5bc062012-08-30 11:43:36 -0700249
250 return -1;
251}
252
253/* returns the index of the new stored object */
254static inline int store_stem(struct saved_data *data, char *buf, int stem_len)
255{
256 int num = data->num_stems;
257
Eric Paris99376852012-08-22 14:41:46 -0400258 if (data->alloc_stems == num) {
259 struct stem *tmp_arr;
Eric Parisde5bc062012-08-30 11:43:36 -0700260
Eric Paris99376852012-08-22 14:41:46 -0400261 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 Parisde5bc062012-08-30 11:43:36 -0700269 data->stem_arr[num].buf = buf;
Eric Paris99376852012-08-22 14:41:46 -0400270 data->num_stems++;
Eric Parisde5bc062012-08-30 11:43:36 -0700271
Eric Paris99376852012-08-22 14:41:46 -0400272 return num;
273}
274
Eric Parisde5bc062012-08-30 11:43:36 -0700275/* 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). */
278static 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 Parisc27101a2012-08-22 14:02:01 -0400299#endif /* _SELABEL_FILE_H_ */