1*2d543d20SAndroid Build Coastguard Worker #ifndef _SELABEL_FILE_H_
2*2d543d20SAndroid Build Coastguard Worker #define _SELABEL_FILE_H_
3*2d543d20SAndroid Build Coastguard Worker
4*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
5*2d543d20SAndroid Build Coastguard Worker #include <pthread.h>
6*2d543d20SAndroid Build Coastguard Worker #include <string.h>
7*2d543d20SAndroid Build Coastguard Worker
8*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
9*2d543d20SAndroid Build Coastguard Worker #include <sys/xattr.h>
10*2d543d20SAndroid Build Coastguard Worker
11*2d543d20SAndroid Build Coastguard Worker /*
12*2d543d20SAndroid Build Coastguard Worker * regex.h/c were introduced to hold all dependencies on the regular
13*2d543d20SAndroid Build Coastguard Worker * expression back-end when we started supporting PCRE2. regex.h defines a
14*2d543d20SAndroid Build Coastguard Worker * minimal interface required by libselinux, so that the remaining code
15*2d543d20SAndroid Build Coastguard Worker * can be agnostic about the underlying implementation.
16*2d543d20SAndroid Build Coastguard Worker */
17*2d543d20SAndroid Build Coastguard Worker #include "regex.h"
18*2d543d20SAndroid Build Coastguard Worker
19*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
20*2d543d20SAndroid Build Coastguard Worker #include "label_internal.h"
21*2d543d20SAndroid Build Coastguard Worker #include "selinux_internal.h"
22*2d543d20SAndroid Build Coastguard Worker
23*2d543d20SAndroid Build Coastguard Worker #define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a
24*2d543d20SAndroid Build Coastguard Worker
25*2d543d20SAndroid Build Coastguard Worker /* Version specific changes */
26*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1
27*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2
28*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_MODE 3
29*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4
30*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH 5
31*2d543d20SAndroid Build Coastguard Worker
32*2d543d20SAndroid Build Coastguard Worker #define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
33*2d543d20SAndroid Build Coastguard Worker SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
34*2d543d20SAndroid Build Coastguard Worker
35*2d543d20SAndroid Build Coastguard Worker /* Required selinux_restorecon and selabel_get_digests_all_partial_matches() */
36*2d543d20SAndroid Build Coastguard Worker #define RESTORECON_PARTIAL_MATCH_DIGEST "security.sehash"
37*2d543d20SAndroid Build Coastguard Worker
38*2d543d20SAndroid Build Coastguard Worker struct selabel_sub {
39*2d543d20SAndroid Build Coastguard Worker char *src;
40*2d543d20SAndroid Build Coastguard Worker int slen;
41*2d543d20SAndroid Build Coastguard Worker char *dst;
42*2d543d20SAndroid Build Coastguard Worker struct selabel_sub *next;
43*2d543d20SAndroid Build Coastguard Worker };
44*2d543d20SAndroid Build Coastguard Worker
45*2d543d20SAndroid Build Coastguard Worker /* A file security context specification. */
46*2d543d20SAndroid Build Coastguard Worker struct spec {
47*2d543d20SAndroid Build Coastguard Worker struct selabel_lookup_rec lr; /* holds contexts for lookup result */
48*2d543d20SAndroid Build Coastguard Worker char *regex_str; /* regular expression string for diagnostics */
49*2d543d20SAndroid Build Coastguard Worker char *type_str; /* type string for diagnostic messages */
50*2d543d20SAndroid Build Coastguard Worker struct regex_data * regex; /* backend dependent regular expression data */
51*2d543d20SAndroid Build Coastguard Worker bool regex_compiled; /* bool to indicate if the regex is compiled */
52*2d543d20SAndroid Build Coastguard Worker pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */
53*2d543d20SAndroid Build Coastguard Worker mode_t mode; /* mode format value */
54*2d543d20SAndroid Build Coastguard Worker bool any_matches; /* did any pathname match? */
55*2d543d20SAndroid Build Coastguard Worker int stem_id; /* indicates which stem-compression item */
56*2d543d20SAndroid Build Coastguard Worker char hasMetaChars; /* regular expression has meta-chars */
57*2d543d20SAndroid Build Coastguard Worker char from_mmap; /* this spec is from an mmap of the data */
58*2d543d20SAndroid Build Coastguard Worker size_t prefix_len; /* length of fixed path prefix */
59*2d543d20SAndroid Build Coastguard Worker };
60*2d543d20SAndroid Build Coastguard Worker
61*2d543d20SAndroid Build Coastguard Worker /* A regular expression stem */
62*2d543d20SAndroid Build Coastguard Worker struct stem {
63*2d543d20SAndroid Build Coastguard Worker char *buf;
64*2d543d20SAndroid Build Coastguard Worker int len;
65*2d543d20SAndroid Build Coastguard Worker char from_mmap;
66*2d543d20SAndroid Build Coastguard Worker };
67*2d543d20SAndroid Build Coastguard Worker
68*2d543d20SAndroid Build Coastguard Worker /* Where we map the file in during selabel_open() */
69*2d543d20SAndroid Build Coastguard Worker struct mmap_area {
70*2d543d20SAndroid Build Coastguard Worker void *addr; /* Start addr + len used to release memory at close */
71*2d543d20SAndroid Build Coastguard Worker size_t len;
72*2d543d20SAndroid Build Coastguard Worker void *next_addr; /* Incremented by next_entry() */
73*2d543d20SAndroid Build Coastguard Worker size_t next_len; /* Decremented by next_entry() */
74*2d543d20SAndroid Build Coastguard Worker struct mmap_area *next;
75*2d543d20SAndroid Build Coastguard Worker };
76*2d543d20SAndroid Build Coastguard Worker
77*2d543d20SAndroid Build Coastguard Worker /* Our stored configuration */
78*2d543d20SAndroid Build Coastguard Worker struct saved_data {
79*2d543d20SAndroid Build Coastguard Worker /*
80*2d543d20SAndroid Build Coastguard Worker * The array of specifications, initially in the same order as in
81*2d543d20SAndroid Build Coastguard Worker * the specification file. Sorting occurs based on hasMetaChars.
82*2d543d20SAndroid Build Coastguard Worker */
83*2d543d20SAndroid Build Coastguard Worker struct spec *spec_arr;
84*2d543d20SAndroid Build Coastguard Worker unsigned int nspec;
85*2d543d20SAndroid Build Coastguard Worker unsigned int alloc_specs;
86*2d543d20SAndroid Build Coastguard Worker
87*2d543d20SAndroid Build Coastguard Worker /*
88*2d543d20SAndroid Build Coastguard Worker * The array of regular expression stems.
89*2d543d20SAndroid Build Coastguard Worker */
90*2d543d20SAndroid Build Coastguard Worker struct stem *stem_arr;
91*2d543d20SAndroid Build Coastguard Worker int num_stems;
92*2d543d20SAndroid Build Coastguard Worker int alloc_stems;
93*2d543d20SAndroid Build Coastguard Worker struct mmap_area *mmap_areas;
94*2d543d20SAndroid Build Coastguard Worker
95*2d543d20SAndroid Build Coastguard Worker /* substitution support */
96*2d543d20SAndroid Build Coastguard Worker struct selabel_sub *dist_subs;
97*2d543d20SAndroid Build Coastguard Worker struct selabel_sub *subs;
98*2d543d20SAndroid Build Coastguard Worker };
99*2d543d20SAndroid Build Coastguard Worker
string_to_mode(const char * mode)100*2d543d20SAndroid Build Coastguard Worker static inline mode_t string_to_mode(const char *mode)
101*2d543d20SAndroid Build Coastguard Worker {
102*2d543d20SAndroid Build Coastguard Worker if (mode[0] != '-' || mode[1] == '\0' || mode[2] != '\0')
103*2d543d20SAndroid Build Coastguard Worker return (mode_t)-1;
104*2d543d20SAndroid Build Coastguard Worker switch (mode[1]) {
105*2d543d20SAndroid Build Coastguard Worker case 'b':
106*2d543d20SAndroid Build Coastguard Worker return S_IFBLK;
107*2d543d20SAndroid Build Coastguard Worker case 'c':
108*2d543d20SAndroid Build Coastguard Worker return S_IFCHR;
109*2d543d20SAndroid Build Coastguard Worker case 'd':
110*2d543d20SAndroid Build Coastguard Worker return S_IFDIR;
111*2d543d20SAndroid Build Coastguard Worker case 'p':
112*2d543d20SAndroid Build Coastguard Worker return S_IFIFO;
113*2d543d20SAndroid Build Coastguard Worker case 'l':
114*2d543d20SAndroid Build Coastguard Worker return S_IFLNK;
115*2d543d20SAndroid Build Coastguard Worker case 's':
116*2d543d20SAndroid Build Coastguard Worker return S_IFSOCK;
117*2d543d20SAndroid Build Coastguard Worker case '-':
118*2d543d20SAndroid Build Coastguard Worker return S_IFREG;
119*2d543d20SAndroid Build Coastguard Worker default:
120*2d543d20SAndroid Build Coastguard Worker return (mode_t)-1;
121*2d543d20SAndroid Build Coastguard Worker }
122*2d543d20SAndroid Build Coastguard Worker }
123*2d543d20SAndroid Build Coastguard Worker
grow_specs(struct saved_data * data)124*2d543d20SAndroid Build Coastguard Worker static inline int grow_specs(struct saved_data *data)
125*2d543d20SAndroid Build Coastguard Worker {
126*2d543d20SAndroid Build Coastguard Worker struct spec *specs;
127*2d543d20SAndroid Build Coastguard Worker size_t new_specs, total_specs;
128*2d543d20SAndroid Build Coastguard Worker
129*2d543d20SAndroid Build Coastguard Worker if (data->nspec < data->alloc_specs)
130*2d543d20SAndroid Build Coastguard Worker return 0;
131*2d543d20SAndroid Build Coastguard Worker
132*2d543d20SAndroid Build Coastguard Worker new_specs = data->nspec + 16;
133*2d543d20SAndroid Build Coastguard Worker total_specs = data->nspec + new_specs;
134*2d543d20SAndroid Build Coastguard Worker
135*2d543d20SAndroid Build Coastguard Worker specs = realloc(data->spec_arr, total_specs * sizeof(*specs));
136*2d543d20SAndroid Build Coastguard Worker if (!specs) {
137*2d543d20SAndroid Build Coastguard Worker perror("realloc");
138*2d543d20SAndroid Build Coastguard Worker return -1;
139*2d543d20SAndroid Build Coastguard Worker }
140*2d543d20SAndroid Build Coastguard Worker
141*2d543d20SAndroid Build Coastguard Worker /* blank the new entries */
142*2d543d20SAndroid Build Coastguard Worker memset(&specs[data->nspec], 0, new_specs * sizeof(*specs));
143*2d543d20SAndroid Build Coastguard Worker
144*2d543d20SAndroid Build Coastguard Worker data->spec_arr = specs;
145*2d543d20SAndroid Build Coastguard Worker data->alloc_specs = total_specs;
146*2d543d20SAndroid Build Coastguard Worker return 0;
147*2d543d20SAndroid Build Coastguard Worker }
148*2d543d20SAndroid Build Coastguard Worker
149*2d543d20SAndroid Build Coastguard Worker /* Determine if the regular expression specification has any meta characters. */
spec_hasMetaChars(struct spec * spec)150*2d543d20SAndroid Build Coastguard Worker static inline void spec_hasMetaChars(struct spec *spec)
151*2d543d20SAndroid Build Coastguard Worker {
152*2d543d20SAndroid Build Coastguard Worker char *c;
153*2d543d20SAndroid Build Coastguard Worker int len;
154*2d543d20SAndroid Build Coastguard Worker char *end;
155*2d543d20SAndroid Build Coastguard Worker
156*2d543d20SAndroid Build Coastguard Worker c = spec->regex_str;
157*2d543d20SAndroid Build Coastguard Worker len = strlen(spec->regex_str);
158*2d543d20SAndroid Build Coastguard Worker end = c + len;
159*2d543d20SAndroid Build Coastguard Worker
160*2d543d20SAndroid Build Coastguard Worker spec->hasMetaChars = 0;
161*2d543d20SAndroid Build Coastguard Worker spec->prefix_len = len;
162*2d543d20SAndroid Build Coastguard Worker
163*2d543d20SAndroid Build Coastguard Worker /* Look at each character in the RE specification string for a
164*2d543d20SAndroid Build Coastguard Worker * meta character. Return when any meta character reached. */
165*2d543d20SAndroid Build Coastguard Worker while (c < end) {
166*2d543d20SAndroid Build Coastguard Worker switch (*c) {
167*2d543d20SAndroid Build Coastguard Worker case '.':
168*2d543d20SAndroid Build Coastguard Worker case '^':
169*2d543d20SAndroid Build Coastguard Worker case '$':
170*2d543d20SAndroid Build Coastguard Worker case '?':
171*2d543d20SAndroid Build Coastguard Worker case '*':
172*2d543d20SAndroid Build Coastguard Worker case '+':
173*2d543d20SAndroid Build Coastguard Worker case '|':
174*2d543d20SAndroid Build Coastguard Worker case '[':
175*2d543d20SAndroid Build Coastguard Worker case '(':
176*2d543d20SAndroid Build Coastguard Worker case '{':
177*2d543d20SAndroid Build Coastguard Worker spec->hasMetaChars = 1;
178*2d543d20SAndroid Build Coastguard Worker spec->prefix_len = c - spec->regex_str;
179*2d543d20SAndroid Build Coastguard Worker return;
180*2d543d20SAndroid Build Coastguard Worker case '\\': /* skip the next character */
181*2d543d20SAndroid Build Coastguard Worker c++;
182*2d543d20SAndroid Build Coastguard Worker break;
183*2d543d20SAndroid Build Coastguard Worker default:
184*2d543d20SAndroid Build Coastguard Worker break;
185*2d543d20SAndroid Build Coastguard Worker
186*2d543d20SAndroid Build Coastguard Worker }
187*2d543d20SAndroid Build Coastguard Worker c++;
188*2d543d20SAndroid Build Coastguard Worker }
189*2d543d20SAndroid Build Coastguard Worker }
190*2d543d20SAndroid Build Coastguard Worker
191*2d543d20SAndroid Build Coastguard Worker /* Move exact pathname specifications to the end. */
sort_specs(struct saved_data * data)192*2d543d20SAndroid Build Coastguard Worker static inline int sort_specs(struct saved_data *data)
193*2d543d20SAndroid Build Coastguard Worker {
194*2d543d20SAndroid Build Coastguard Worker struct spec *spec_copy;
195*2d543d20SAndroid Build Coastguard Worker struct spec spec;
196*2d543d20SAndroid Build Coastguard Worker unsigned int i;
197*2d543d20SAndroid Build Coastguard Worker int front, back;
198*2d543d20SAndroid Build Coastguard Worker size_t len = sizeof(*spec_copy);
199*2d543d20SAndroid Build Coastguard Worker
200*2d543d20SAndroid Build Coastguard Worker spec_copy = malloc(len * data->nspec);
201*2d543d20SAndroid Build Coastguard Worker if (!spec_copy)
202*2d543d20SAndroid Build Coastguard Worker return -1;
203*2d543d20SAndroid Build Coastguard Worker
204*2d543d20SAndroid Build Coastguard Worker /* first move the exact pathnames to the back */
205*2d543d20SAndroid Build Coastguard Worker front = 0;
206*2d543d20SAndroid Build Coastguard Worker back = data->nspec - 1;
207*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < data->nspec; i++) {
208*2d543d20SAndroid Build Coastguard Worker if (data->spec_arr[i].hasMetaChars)
209*2d543d20SAndroid Build Coastguard Worker memcpy(&spec_copy[front++], &data->spec_arr[i], len);
210*2d543d20SAndroid Build Coastguard Worker else
211*2d543d20SAndroid Build Coastguard Worker memcpy(&spec_copy[back--], &data->spec_arr[i], len);
212*2d543d20SAndroid Build Coastguard Worker }
213*2d543d20SAndroid Build Coastguard Worker
214*2d543d20SAndroid Build Coastguard Worker /*
215*2d543d20SAndroid Build Coastguard Worker * now the exact pathnames are at the end, but they are in the reverse
216*2d543d20SAndroid Build Coastguard Worker * order. Since 'front' is now the first of the 'exact' we can run
217*2d543d20SAndroid Build Coastguard Worker * that part of the array switching the front and back element.
218*2d543d20SAndroid Build Coastguard Worker */
219*2d543d20SAndroid Build Coastguard Worker back = data->nspec - 1;
220*2d543d20SAndroid Build Coastguard Worker while (front < back) {
221*2d543d20SAndroid Build Coastguard Worker /* save the front */
222*2d543d20SAndroid Build Coastguard Worker memcpy(&spec, &spec_copy[front], len);
223*2d543d20SAndroid Build Coastguard Worker /* move the back to the front */
224*2d543d20SAndroid Build Coastguard Worker memcpy(&spec_copy[front], &spec_copy[back], len);
225*2d543d20SAndroid Build Coastguard Worker /* put the old front in the back */
226*2d543d20SAndroid Build Coastguard Worker memcpy(&spec_copy[back], &spec, len);
227*2d543d20SAndroid Build Coastguard Worker front++;
228*2d543d20SAndroid Build Coastguard Worker back--;
229*2d543d20SAndroid Build Coastguard Worker }
230*2d543d20SAndroid Build Coastguard Worker
231*2d543d20SAndroid Build Coastguard Worker free(data->spec_arr);
232*2d543d20SAndroid Build Coastguard Worker data->spec_arr = spec_copy;
233*2d543d20SAndroid Build Coastguard Worker
234*2d543d20SAndroid Build Coastguard Worker return 0;
235*2d543d20SAndroid Build Coastguard Worker }
236*2d543d20SAndroid Build Coastguard Worker
237*2d543d20SAndroid Build Coastguard Worker /* Return the length of the text that can be considered the stem, returns 0
238*2d543d20SAndroid Build Coastguard Worker * if there is no identifiable stem */
get_stem_from_spec(const char * const buf)239*2d543d20SAndroid Build Coastguard Worker static inline int get_stem_from_spec(const char *const buf)
240*2d543d20SAndroid Build Coastguard Worker {
241*2d543d20SAndroid Build Coastguard Worker const char *tmp = strchr(buf + 1, '/');
242*2d543d20SAndroid Build Coastguard Worker const char *ind;
243*2d543d20SAndroid Build Coastguard Worker
244*2d543d20SAndroid Build Coastguard Worker if (!tmp)
245*2d543d20SAndroid Build Coastguard Worker return 0;
246*2d543d20SAndroid Build Coastguard Worker
247*2d543d20SAndroid Build Coastguard Worker for (ind = buf; ind < tmp; ind++) {
248*2d543d20SAndroid Build Coastguard Worker if (strchr(".^$?*+|[({", (int)*ind))
249*2d543d20SAndroid Build Coastguard Worker return 0;
250*2d543d20SAndroid Build Coastguard Worker }
251*2d543d20SAndroid Build Coastguard Worker return tmp - buf;
252*2d543d20SAndroid Build Coastguard Worker }
253*2d543d20SAndroid Build Coastguard Worker
254*2d543d20SAndroid Build Coastguard Worker /*
255*2d543d20SAndroid Build Coastguard Worker * return the stemid given a string and a length
256*2d543d20SAndroid Build Coastguard Worker */
find_stem(struct saved_data * data,const char * buf,int stem_len)257*2d543d20SAndroid Build Coastguard Worker static inline int find_stem(struct saved_data *data, const char *buf,
258*2d543d20SAndroid Build Coastguard Worker int stem_len)
259*2d543d20SAndroid Build Coastguard Worker {
260*2d543d20SAndroid Build Coastguard Worker int i;
261*2d543d20SAndroid Build Coastguard Worker
262*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < data->num_stems; i++) {
263*2d543d20SAndroid Build Coastguard Worker if (stem_len == data->stem_arr[i].len &&
264*2d543d20SAndroid Build Coastguard Worker !strncmp(buf, data->stem_arr[i].buf, stem_len))
265*2d543d20SAndroid Build Coastguard Worker return i;
266*2d543d20SAndroid Build Coastguard Worker }
267*2d543d20SAndroid Build Coastguard Worker
268*2d543d20SAndroid Build Coastguard Worker return -1;
269*2d543d20SAndroid Build Coastguard Worker }
270*2d543d20SAndroid Build Coastguard Worker
271*2d543d20SAndroid Build Coastguard Worker /* returns the index of the new stored object */
store_stem(struct saved_data * data,char * buf,int stem_len)272*2d543d20SAndroid Build Coastguard Worker static inline int store_stem(struct saved_data *data, char *buf, int stem_len)
273*2d543d20SAndroid Build Coastguard Worker {
274*2d543d20SAndroid Build Coastguard Worker int num = data->num_stems;
275*2d543d20SAndroid Build Coastguard Worker
276*2d543d20SAndroid Build Coastguard Worker if (data->alloc_stems == num) {
277*2d543d20SAndroid Build Coastguard Worker struct stem *tmp_arr;
278*2d543d20SAndroid Build Coastguard Worker int alloc_stems = data->alloc_stems * 2 + 16;
279*2d543d20SAndroid Build Coastguard Worker tmp_arr = realloc(data->stem_arr,
280*2d543d20SAndroid Build Coastguard Worker sizeof(*tmp_arr) * alloc_stems);
281*2d543d20SAndroid Build Coastguard Worker if (!tmp_arr) {
282*2d543d20SAndroid Build Coastguard Worker return -1;
283*2d543d20SAndroid Build Coastguard Worker }
284*2d543d20SAndroid Build Coastguard Worker data->alloc_stems = alloc_stems;
285*2d543d20SAndroid Build Coastguard Worker data->stem_arr = tmp_arr;
286*2d543d20SAndroid Build Coastguard Worker }
287*2d543d20SAndroid Build Coastguard Worker data->stem_arr[num].len = stem_len;
288*2d543d20SAndroid Build Coastguard Worker data->stem_arr[num].buf = buf;
289*2d543d20SAndroid Build Coastguard Worker data->stem_arr[num].from_mmap = 0;
290*2d543d20SAndroid Build Coastguard Worker data->num_stems++;
291*2d543d20SAndroid Build Coastguard Worker
292*2d543d20SAndroid Build Coastguard Worker return num;
293*2d543d20SAndroid Build Coastguard Worker }
294*2d543d20SAndroid Build Coastguard Worker
295*2d543d20SAndroid Build Coastguard Worker /* find the stem of a file spec, returns the index into stem_arr for a new
296*2d543d20SAndroid Build Coastguard Worker * or existing stem, (or -1 if there is no possible stem - IE for a file in
297*2d543d20SAndroid Build Coastguard Worker * the root directory or a regex that is too complex for us). */
find_stem_from_spec(struct saved_data * data,const char * buf)298*2d543d20SAndroid Build Coastguard Worker static inline int find_stem_from_spec(struct saved_data *data, const char *buf)
299*2d543d20SAndroid Build Coastguard Worker {
300*2d543d20SAndroid Build Coastguard Worker int stem_len = get_stem_from_spec(buf);
301*2d543d20SAndroid Build Coastguard Worker int stemid;
302*2d543d20SAndroid Build Coastguard Worker char *stem;
303*2d543d20SAndroid Build Coastguard Worker int r;
304*2d543d20SAndroid Build Coastguard Worker
305*2d543d20SAndroid Build Coastguard Worker if (!stem_len)
306*2d543d20SAndroid Build Coastguard Worker return -1;
307*2d543d20SAndroid Build Coastguard Worker
308*2d543d20SAndroid Build Coastguard Worker stemid = find_stem(data, buf, stem_len);
309*2d543d20SAndroid Build Coastguard Worker if (stemid >= 0)
310*2d543d20SAndroid Build Coastguard Worker return stemid;
311*2d543d20SAndroid Build Coastguard Worker
312*2d543d20SAndroid Build Coastguard Worker /* not found, allocate a new one */
313*2d543d20SAndroid Build Coastguard Worker stem = strndup(buf, stem_len);
314*2d543d20SAndroid Build Coastguard Worker if (!stem)
315*2d543d20SAndroid Build Coastguard Worker return -1;
316*2d543d20SAndroid Build Coastguard Worker
317*2d543d20SAndroid Build Coastguard Worker r = store_stem(data, stem, stem_len);
318*2d543d20SAndroid Build Coastguard Worker if (r < 0)
319*2d543d20SAndroid Build Coastguard Worker free(stem);
320*2d543d20SAndroid Build Coastguard Worker
321*2d543d20SAndroid Build Coastguard Worker return r;
322*2d543d20SAndroid Build Coastguard Worker }
323*2d543d20SAndroid Build Coastguard Worker
324*2d543d20SAndroid Build Coastguard Worker /* This will always check for buffer over-runs and either read the next entry
325*2d543d20SAndroid Build Coastguard Worker * if buf != NULL or skip over the entry (as these areas are mapped in the
326*2d543d20SAndroid Build Coastguard Worker * current buffer). */
next_entry(void * buf,struct mmap_area * fp,size_t bytes)327*2d543d20SAndroid Build Coastguard Worker static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes)
328*2d543d20SAndroid Build Coastguard Worker {
329*2d543d20SAndroid Build Coastguard Worker if (bytes > fp->next_len)
330*2d543d20SAndroid Build Coastguard Worker return -1;
331*2d543d20SAndroid Build Coastguard Worker
332*2d543d20SAndroid Build Coastguard Worker if (buf)
333*2d543d20SAndroid Build Coastguard Worker memcpy(buf, fp->next_addr, bytes);
334*2d543d20SAndroid Build Coastguard Worker
335*2d543d20SAndroid Build Coastguard Worker fp->next_addr = (char *)fp->next_addr + bytes;
336*2d543d20SAndroid Build Coastguard Worker fp->next_len -= bytes;
337*2d543d20SAndroid Build Coastguard Worker return 0;
338*2d543d20SAndroid Build Coastguard Worker }
339*2d543d20SAndroid Build Coastguard Worker
compile_regex(struct spec * spec,const char ** errbuf)340*2d543d20SAndroid Build Coastguard Worker static inline int compile_regex(struct spec *spec, const char **errbuf)
341*2d543d20SAndroid Build Coastguard Worker {
342*2d543d20SAndroid Build Coastguard Worker char *reg_buf, *anchored_regex, *cp;
343*2d543d20SAndroid Build Coastguard Worker struct regex_error_data error_data;
344*2d543d20SAndroid Build Coastguard Worker static char regex_error_format_buffer[256];
345*2d543d20SAndroid Build Coastguard Worker size_t len;
346*2d543d20SAndroid Build Coastguard Worker int rc;
347*2d543d20SAndroid Build Coastguard Worker bool regex_compiled;
348*2d543d20SAndroid Build Coastguard Worker
349*2d543d20SAndroid Build Coastguard Worker /* We really want pthread_once() here, but since its
350*2d543d20SAndroid Build Coastguard Worker * init_routine does not take a parameter, it's not possible
351*2d543d20SAndroid Build Coastguard Worker * to use, so we generate the same effect with atomics and a
352*2d543d20SAndroid Build Coastguard Worker * mutex */
353*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
354*2d543d20SAndroid Build Coastguard Worker regex_compiled =
355*2d543d20SAndroid Build Coastguard Worker __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE);
356*2d543d20SAndroid Build Coastguard Worker #else
357*2d543d20SAndroid Build Coastguard Worker /* GCC <4.7 */
358*2d543d20SAndroid Build Coastguard Worker __sync_synchronize();
359*2d543d20SAndroid Build Coastguard Worker regex_compiled = spec->regex_compiled;
360*2d543d20SAndroid Build Coastguard Worker #endif
361*2d543d20SAndroid Build Coastguard Worker if (regex_compiled) {
362*2d543d20SAndroid Build Coastguard Worker return 0; /* already done */
363*2d543d20SAndroid Build Coastguard Worker }
364*2d543d20SAndroid Build Coastguard Worker
365*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_lock(&spec->regex_lock);
366*2d543d20SAndroid Build Coastguard Worker /* Check if another thread compiled the regex while we waited
367*2d543d20SAndroid Build Coastguard Worker * on the mutex */
368*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
369*2d543d20SAndroid Build Coastguard Worker regex_compiled =
370*2d543d20SAndroid Build Coastguard Worker __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE);
371*2d543d20SAndroid Build Coastguard Worker #else
372*2d543d20SAndroid Build Coastguard Worker /* GCC <4.7 */
373*2d543d20SAndroid Build Coastguard Worker __sync_synchronize();
374*2d543d20SAndroid Build Coastguard Worker regex_compiled = spec->regex_compiled;
375*2d543d20SAndroid Build Coastguard Worker #endif
376*2d543d20SAndroid Build Coastguard Worker if (regex_compiled) {
377*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&spec->regex_lock);
378*2d543d20SAndroid Build Coastguard Worker return 0;
379*2d543d20SAndroid Build Coastguard Worker }
380*2d543d20SAndroid Build Coastguard Worker
381*2d543d20SAndroid Build Coastguard Worker reg_buf = spec->regex_str;
382*2d543d20SAndroid Build Coastguard Worker /* Anchor the regular expression. */
383*2d543d20SAndroid Build Coastguard Worker len = strlen(reg_buf);
384*2d543d20SAndroid Build Coastguard Worker cp = anchored_regex = malloc(len + 3);
385*2d543d20SAndroid Build Coastguard Worker if (!anchored_regex) {
386*2d543d20SAndroid Build Coastguard Worker if (errbuf)
387*2d543d20SAndroid Build Coastguard Worker *errbuf = "out of memory";
388*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&spec->regex_lock);
389*2d543d20SAndroid Build Coastguard Worker return -1;
390*2d543d20SAndroid Build Coastguard Worker }
391*2d543d20SAndroid Build Coastguard Worker
392*2d543d20SAndroid Build Coastguard Worker /* Create ^...$ regexp. */
393*2d543d20SAndroid Build Coastguard Worker *cp++ = '^';
394*2d543d20SAndroid Build Coastguard Worker memcpy(cp, reg_buf, len);
395*2d543d20SAndroid Build Coastguard Worker cp += len;
396*2d543d20SAndroid Build Coastguard Worker *cp++ = '$';
397*2d543d20SAndroid Build Coastguard Worker *cp = '\0';
398*2d543d20SAndroid Build Coastguard Worker
399*2d543d20SAndroid Build Coastguard Worker /* Compile the regular expression. */
400*2d543d20SAndroid Build Coastguard Worker rc = regex_prepare_data(&spec->regex, anchored_regex, &error_data);
401*2d543d20SAndroid Build Coastguard Worker free(anchored_regex);
402*2d543d20SAndroid Build Coastguard Worker if (rc < 0) {
403*2d543d20SAndroid Build Coastguard Worker if (errbuf) {
404*2d543d20SAndroid Build Coastguard Worker regex_format_error(&error_data,
405*2d543d20SAndroid Build Coastguard Worker regex_error_format_buffer,
406*2d543d20SAndroid Build Coastguard Worker sizeof(regex_error_format_buffer));
407*2d543d20SAndroid Build Coastguard Worker *errbuf = ®ex_error_format_buffer[0];
408*2d543d20SAndroid Build Coastguard Worker }
409*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&spec->regex_lock);
410*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
411*2d543d20SAndroid Build Coastguard Worker return -1;
412*2d543d20SAndroid Build Coastguard Worker }
413*2d543d20SAndroid Build Coastguard Worker
414*2d543d20SAndroid Build Coastguard Worker /* Done. */
415*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
416*2d543d20SAndroid Build Coastguard Worker __atomic_store_n(&spec->regex_compiled, true, __ATOMIC_RELEASE);
417*2d543d20SAndroid Build Coastguard Worker #else
418*2d543d20SAndroid Build Coastguard Worker /* GCC <4.7 */
419*2d543d20SAndroid Build Coastguard Worker spec->regex_compiled = true;
420*2d543d20SAndroid Build Coastguard Worker __sync_synchronize();
421*2d543d20SAndroid Build Coastguard Worker #endif
422*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&spec->regex_lock);
423*2d543d20SAndroid Build Coastguard Worker return 0;
424*2d543d20SAndroid Build Coastguard Worker }
425*2d543d20SAndroid Build Coastguard Worker
426*2d543d20SAndroid Build Coastguard Worker /* This service is used by label_file.c process_file() and
427*2d543d20SAndroid Build Coastguard Worker * utils/sefcontext_compile.c */
process_line(struct selabel_handle * rec,const char * path,const char * prefix,char * line_buf,unsigned lineno)428*2d543d20SAndroid Build Coastguard Worker static inline int process_line(struct selabel_handle *rec,
429*2d543d20SAndroid Build Coastguard Worker const char *path, const char *prefix,
430*2d543d20SAndroid Build Coastguard Worker char *line_buf, unsigned lineno)
431*2d543d20SAndroid Build Coastguard Worker {
432*2d543d20SAndroid Build Coastguard Worker int items, len, rc;
433*2d543d20SAndroid Build Coastguard Worker char *regex = NULL, *type = NULL, *context = NULL;
434*2d543d20SAndroid Build Coastguard Worker struct saved_data *data = (struct saved_data *)rec->data;
435*2d543d20SAndroid Build Coastguard Worker struct spec *spec_arr;
436*2d543d20SAndroid Build Coastguard Worker unsigned int nspec = data->nspec;
437*2d543d20SAndroid Build Coastguard Worker const char *errbuf = NULL;
438*2d543d20SAndroid Build Coastguard Worker
439*2d543d20SAndroid Build Coastguard Worker items = read_spec_entries(line_buf, &errbuf, 3, ®ex, &type, &context);
440*2d543d20SAndroid Build Coastguard Worker if (items < 0) {
441*2d543d20SAndroid Build Coastguard Worker if (errbuf) {
442*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
443*2d543d20SAndroid Build Coastguard Worker "%s: line %u error due to: %s\n", path,
444*2d543d20SAndroid Build Coastguard Worker lineno, errbuf);
445*2d543d20SAndroid Build Coastguard Worker } else {
446*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
447*2d543d20SAndroid Build Coastguard Worker "%s: line %u error due to: %m\n", path,
448*2d543d20SAndroid Build Coastguard Worker lineno);
449*2d543d20SAndroid Build Coastguard Worker }
450*2d543d20SAndroid Build Coastguard Worker free(regex);
451*2d543d20SAndroid Build Coastguard Worker free(type);
452*2d543d20SAndroid Build Coastguard Worker free(context);
453*2d543d20SAndroid Build Coastguard Worker return -1;
454*2d543d20SAndroid Build Coastguard Worker }
455*2d543d20SAndroid Build Coastguard Worker
456*2d543d20SAndroid Build Coastguard Worker if (items == 0)
457*2d543d20SAndroid Build Coastguard Worker return items;
458*2d543d20SAndroid Build Coastguard Worker
459*2d543d20SAndroid Build Coastguard Worker if (items < 2) {
460*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_ERROR,
461*2d543d20SAndroid Build Coastguard Worker "%s: line %u is missing fields\n", path,
462*2d543d20SAndroid Build Coastguard Worker lineno);
463*2d543d20SAndroid Build Coastguard Worker if (items == 1)
464*2d543d20SAndroid Build Coastguard Worker free(regex);
465*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
466*2d543d20SAndroid Build Coastguard Worker return -1;
467*2d543d20SAndroid Build Coastguard Worker } else if (items == 2) {
468*2d543d20SAndroid Build Coastguard Worker /* The type field is optional. */
469*2d543d20SAndroid Build Coastguard Worker context = type;
470*2d543d20SAndroid Build Coastguard Worker type = 0;
471*2d543d20SAndroid Build Coastguard Worker }
472*2d543d20SAndroid Build Coastguard Worker
473*2d543d20SAndroid Build Coastguard Worker len = get_stem_from_spec(regex);
474*2d543d20SAndroid Build Coastguard Worker if (len && prefix && strncmp(prefix, regex, len)) {
475*2d543d20SAndroid Build Coastguard Worker /* Stem of regex does not match requested prefix, discard. */
476*2d543d20SAndroid Build Coastguard Worker free(regex);
477*2d543d20SAndroid Build Coastguard Worker free(type);
478*2d543d20SAndroid Build Coastguard Worker free(context);
479*2d543d20SAndroid Build Coastguard Worker return 0;
480*2d543d20SAndroid Build Coastguard Worker }
481*2d543d20SAndroid Build Coastguard Worker
482*2d543d20SAndroid Build Coastguard Worker rc = grow_specs(data);
483*2d543d20SAndroid Build Coastguard Worker if (rc)
484*2d543d20SAndroid Build Coastguard Worker return rc;
485*2d543d20SAndroid Build Coastguard Worker
486*2d543d20SAndroid Build Coastguard Worker spec_arr = data->spec_arr;
487*2d543d20SAndroid Build Coastguard Worker
488*2d543d20SAndroid Build Coastguard Worker /* process and store the specification in spec. */
489*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
490*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].regex_str = regex;
491*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_init(&spec_arr[nspec].regex_lock, NULL);
492*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].regex_compiled = false;
493*2d543d20SAndroid Build Coastguard Worker
494*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].type_str = type;
495*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].mode = 0;
496*2d543d20SAndroid Build Coastguard Worker
497*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].lr.ctx_raw = context;
498*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].lr.lineno = lineno;
499*2d543d20SAndroid Build Coastguard Worker
500*2d543d20SAndroid Build Coastguard Worker /*
501*2d543d20SAndroid Build Coastguard Worker * bump data->nspecs to cause closef() to cover it in its free
502*2d543d20SAndroid Build Coastguard Worker * but do not bump nspec since it's used below.
503*2d543d20SAndroid Build Coastguard Worker */
504*2d543d20SAndroid Build Coastguard Worker data->nspec++;
505*2d543d20SAndroid Build Coastguard Worker
506*2d543d20SAndroid Build Coastguard Worker if (rec->validating
507*2d543d20SAndroid Build Coastguard Worker && compile_regex(&spec_arr[nspec], &errbuf)) {
508*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_ERROR,
509*2d543d20SAndroid Build Coastguard Worker "%s: line %u has invalid regex %s: %s\n",
510*2d543d20SAndroid Build Coastguard Worker path, lineno, regex, errbuf);
511*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
512*2d543d20SAndroid Build Coastguard Worker return -1;
513*2d543d20SAndroid Build Coastguard Worker }
514*2d543d20SAndroid Build Coastguard Worker
515*2d543d20SAndroid Build Coastguard Worker if (type) {
516*2d543d20SAndroid Build Coastguard Worker mode_t mode = string_to_mode(type);
517*2d543d20SAndroid Build Coastguard Worker
518*2d543d20SAndroid Build Coastguard Worker if (mode == (mode_t)-1) {
519*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_ERROR,
520*2d543d20SAndroid Build Coastguard Worker "%s: line %u has invalid file type %s\n",
521*2d543d20SAndroid Build Coastguard Worker path, lineno, type);
522*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
523*2d543d20SAndroid Build Coastguard Worker return -1;
524*2d543d20SAndroid Build Coastguard Worker }
525*2d543d20SAndroid Build Coastguard Worker spec_arr[nspec].mode = mode;
526*2d543d20SAndroid Build Coastguard Worker }
527*2d543d20SAndroid Build Coastguard Worker
528*2d543d20SAndroid Build Coastguard Worker /* Determine if specification has
529*2d543d20SAndroid Build Coastguard Worker * any meta characters in the RE */
530*2d543d20SAndroid Build Coastguard Worker spec_hasMetaChars(&spec_arr[nspec]);
531*2d543d20SAndroid Build Coastguard Worker
532*2d543d20SAndroid Build Coastguard Worker if (strcmp(context, "<<none>>") && rec->validating)
533*2d543d20SAndroid Build Coastguard Worker return compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
534*2d543d20SAndroid Build Coastguard Worker
535*2d543d20SAndroid Build Coastguard Worker return 0;
536*2d543d20SAndroid Build Coastguard Worker }
537*2d543d20SAndroid Build Coastguard Worker
538*2d543d20SAndroid Build Coastguard Worker #endif /* _SELABEL_FILE_H_ */
539