1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker * File contexts backend for labeling system
3*2d543d20SAndroid Build Coastguard Worker *
4*2d543d20SAndroid Build Coastguard Worker * Author : Eamon Walsh <[email protected]>
5*2d543d20SAndroid Build Coastguard Worker * Author : Stephen Smalley <[email protected]>
6*2d543d20SAndroid Build Coastguard Worker */
7*2d543d20SAndroid Build Coastguard Worker
8*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
9*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
10*2d543d20SAndroid Build Coastguard Worker #include <stdarg.h>
11*2d543d20SAndroid Build Coastguard Worker #include <string.h>
12*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
13*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
14*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
15*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
16*2d543d20SAndroid Build Coastguard Worker #include <stdint.h>
17*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
18*2d543d20SAndroid Build Coastguard Worker #include <sys/mman.h>
19*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
20*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
21*2d543d20SAndroid Build Coastguard Worker
22*2d543d20SAndroid Build Coastguard Worker #include "hashtab.h"
23*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
24*2d543d20SAndroid Build Coastguard Worker #include "label_internal.h"
25*2d543d20SAndroid Build Coastguard Worker #include "label_file.h"
26*2d543d20SAndroid Build Coastguard Worker
27*2d543d20SAndroid Build Coastguard Worker /* controls the shrink multiple of the hashtab length */
28*2d543d20SAndroid Build Coastguard Worker #define SHRINK_MULTIS 1
29*2d543d20SAndroid Build Coastguard Worker
30*2d543d20SAndroid Build Coastguard Worker struct chkdups_key {
31*2d543d20SAndroid Build Coastguard Worker char *regex;
32*2d543d20SAndroid Build Coastguard Worker unsigned int mode;
33*2d543d20SAndroid Build Coastguard Worker };
34*2d543d20SAndroid Build Coastguard Worker
35*2d543d20SAndroid Build Coastguard Worker /*
36*2d543d20SAndroid Build Coastguard Worker * Internals, mostly moved over from matchpathcon.c
37*2d543d20SAndroid Build Coastguard Worker */
38*2d543d20SAndroid Build Coastguard Worker
39*2d543d20SAndroid Build Coastguard Worker /* return the length of the text that is the stem of a file name */
get_stem_from_file_name(const char * const buf)40*2d543d20SAndroid Build Coastguard Worker static int get_stem_from_file_name(const char *const buf)
41*2d543d20SAndroid Build Coastguard Worker {
42*2d543d20SAndroid Build Coastguard Worker const char *tmp = strchr(buf + 1, '/');
43*2d543d20SAndroid Build Coastguard Worker
44*2d543d20SAndroid Build Coastguard Worker if (!tmp)
45*2d543d20SAndroid Build Coastguard Worker return 0;
46*2d543d20SAndroid Build Coastguard Worker return tmp - buf;
47*2d543d20SAndroid Build Coastguard Worker }
48*2d543d20SAndroid Build Coastguard Worker
49*2d543d20SAndroid Build Coastguard Worker /* find the stem of a file name, returns the index into stem_arr (or -1 if
50*2d543d20SAndroid Build Coastguard Worker * there is no match - IE for a file in the root directory or a regex that is
51*2d543d20SAndroid Build Coastguard Worker * too complex for us). */
find_stem_from_file(struct saved_data * data,const char * key)52*2d543d20SAndroid Build Coastguard Worker static int find_stem_from_file(struct saved_data *data, const char *key)
53*2d543d20SAndroid Build Coastguard Worker {
54*2d543d20SAndroid Build Coastguard Worker int i;
55*2d543d20SAndroid Build Coastguard Worker int stem_len = get_stem_from_file_name(key);
56*2d543d20SAndroid Build Coastguard Worker
57*2d543d20SAndroid Build Coastguard Worker if (!stem_len)
58*2d543d20SAndroid Build Coastguard Worker return -1;
59*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < data->num_stems; i++) {
60*2d543d20SAndroid Build Coastguard Worker if (stem_len == data->stem_arr[i].len
61*2d543d20SAndroid Build Coastguard Worker && !strncmp(key, data->stem_arr[i].buf, stem_len)) {
62*2d543d20SAndroid Build Coastguard Worker return i;
63*2d543d20SAndroid Build Coastguard Worker }
64*2d543d20SAndroid Build Coastguard Worker }
65*2d543d20SAndroid Build Coastguard Worker return -1;
66*2d543d20SAndroid Build Coastguard Worker }
67*2d543d20SAndroid Build Coastguard Worker
68*2d543d20SAndroid Build Coastguard Worker /*
69*2d543d20SAndroid Build Coastguard Worker * hash calculation and key comparison of hash table
70*2d543d20SAndroid Build Coastguard Worker */
71*2d543d20SAndroid Build Coastguard Worker ignore_unsigned_overflow_
symhash(hashtab_t h,const_hashtab_key_t key)72*2d543d20SAndroid Build Coastguard Worker static unsigned int symhash(hashtab_t h, const_hashtab_key_t key)
73*2d543d20SAndroid Build Coastguard Worker {
74*2d543d20SAndroid Build Coastguard Worker const struct chkdups_key *k = (const struct chkdups_key *)key;
75*2d543d20SAndroid Build Coastguard Worker const char *p = NULL;
76*2d543d20SAndroid Build Coastguard Worker size_t size;
77*2d543d20SAndroid Build Coastguard Worker unsigned int val = 0;
78*2d543d20SAndroid Build Coastguard Worker
79*2d543d20SAndroid Build Coastguard Worker size = strlen(k->regex);
80*2d543d20SAndroid Build Coastguard Worker for (p = k->regex; ((size_t) (p - k->regex)) < size; p++)
81*2d543d20SAndroid Build Coastguard Worker val =
82*2d543d20SAndroid Build Coastguard Worker ((val << 4) | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
83*2d543d20SAndroid Build Coastguard Worker return val % h->size;
84*2d543d20SAndroid Build Coastguard Worker }
85*2d543d20SAndroid Build Coastguard Worker
symcmp(hashtab_t h,const_hashtab_key_t key1,const_hashtab_key_t key2)86*2d543d20SAndroid Build Coastguard Worker static int symcmp(hashtab_t h
87*2d543d20SAndroid Build Coastguard Worker __attribute__ ((unused)), const_hashtab_key_t key1,
88*2d543d20SAndroid Build Coastguard Worker const_hashtab_key_t key2)
89*2d543d20SAndroid Build Coastguard Worker {
90*2d543d20SAndroid Build Coastguard Worker const struct chkdups_key *a = (const struct chkdups_key *)key1;
91*2d543d20SAndroid Build Coastguard Worker const struct chkdups_key *b = (const struct chkdups_key *)key2;
92*2d543d20SAndroid Build Coastguard Worker
93*2d543d20SAndroid Build Coastguard Worker return strcmp(a->regex, b->regex) || (a->mode && b->mode && a->mode != b->mode);
94*2d543d20SAndroid Build Coastguard Worker }
95*2d543d20SAndroid Build Coastguard Worker
destroy_chkdups_key(hashtab_key_t key)96*2d543d20SAndroid Build Coastguard Worker static int destroy_chkdups_key(hashtab_key_t key)
97*2d543d20SAndroid Build Coastguard Worker {
98*2d543d20SAndroid Build Coastguard Worker free(key);
99*2d543d20SAndroid Build Coastguard Worker
100*2d543d20SAndroid Build Coastguard Worker return 0;
101*2d543d20SAndroid Build Coastguard Worker }
102*2d543d20SAndroid Build Coastguard Worker
103*2d543d20SAndroid Build Coastguard Worker /*
104*2d543d20SAndroid Build Coastguard Worker * Warn about duplicate specifications.
105*2d543d20SAndroid Build Coastguard Worker */
nodups_specs(struct saved_data * data,const char * path)106*2d543d20SAndroid Build Coastguard Worker static int nodups_specs(struct saved_data *data, const char *path)
107*2d543d20SAndroid Build Coastguard Worker {
108*2d543d20SAndroid Build Coastguard Worker int rc = 0, ret = 0;
109*2d543d20SAndroid Build Coastguard Worker unsigned int ii;
110*2d543d20SAndroid Build Coastguard Worker struct spec *curr_spec, *spec_arr = data->spec_arr;
111*2d543d20SAndroid Build Coastguard Worker struct chkdups_key *new = NULL;
112*2d543d20SAndroid Build Coastguard Worker unsigned int hashtab_len = (data->nspec / SHRINK_MULTIS) ? data->nspec / SHRINK_MULTIS : 1;
113*2d543d20SAndroid Build Coastguard Worker
114*2d543d20SAndroid Build Coastguard Worker hashtab_t hash_table = selinux_hashtab_create(symhash, symcmp, hashtab_len);
115*2d543d20SAndroid Build Coastguard Worker if (!hash_table) {
116*2d543d20SAndroid Build Coastguard Worker rc = -1;
117*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_ERROR, "%s: hashtab create failed.\n", path);
118*2d543d20SAndroid Build Coastguard Worker return rc;
119*2d543d20SAndroid Build Coastguard Worker }
120*2d543d20SAndroid Build Coastguard Worker for (ii = 0; ii < data->nspec; ii++) {
121*2d543d20SAndroid Build Coastguard Worker new = (struct chkdups_key *)malloc(sizeof(struct chkdups_key));
122*2d543d20SAndroid Build Coastguard Worker if (!new) {
123*2d543d20SAndroid Build Coastguard Worker rc = -1;
124*2d543d20SAndroid Build Coastguard Worker selinux_hashtab_destroy_key(hash_table, destroy_chkdups_key);
125*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_ERROR, "%s: hashtab key create failed.\n", path);
126*2d543d20SAndroid Build Coastguard Worker return rc;
127*2d543d20SAndroid Build Coastguard Worker }
128*2d543d20SAndroid Build Coastguard Worker new->regex = spec_arr[ii].regex_str;
129*2d543d20SAndroid Build Coastguard Worker new->mode = spec_arr[ii].mode;
130*2d543d20SAndroid Build Coastguard Worker ret = selinux_hashtab_insert(hash_table, (hashtab_key_t)new, &spec_arr[ii]);
131*2d543d20SAndroid Build Coastguard Worker if (ret == HASHTAB_SUCCESS)
132*2d543d20SAndroid Build Coastguard Worker continue;
133*2d543d20SAndroid Build Coastguard Worker if (ret == HASHTAB_PRESENT) {
134*2d543d20SAndroid Build Coastguard Worker curr_spec =
135*2d543d20SAndroid Build Coastguard Worker (struct spec *)selinux_hashtab_search(hash_table, (hashtab_key_t)new);
136*2d543d20SAndroid Build Coastguard Worker rc = -1;
137*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
138*2d543d20SAndroid Build Coastguard Worker free(new);
139*2d543d20SAndroid Build Coastguard Worker if (strcmp(spec_arr[ii].lr.ctx_raw, curr_spec->lr.ctx_raw)) {
140*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG
141*2d543d20SAndroid Build Coastguard Worker (SELINUX_ERROR,
142*2d543d20SAndroid Build Coastguard Worker "%s: Multiple different specifications for %s (%s and %s).\n",
143*2d543d20SAndroid Build Coastguard Worker path, curr_spec->regex_str,
144*2d543d20SAndroid Build Coastguard Worker spec_arr[ii].lr.ctx_raw,
145*2d543d20SAndroid Build Coastguard Worker curr_spec->lr.ctx_raw);
146*2d543d20SAndroid Build Coastguard Worker } else {
147*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG
148*2d543d20SAndroid Build Coastguard Worker (SELINUX_ERROR,
149*2d543d20SAndroid Build Coastguard Worker "%s: Multiple same specifications for %s.\n",
150*2d543d20SAndroid Build Coastguard Worker path, curr_spec->regex_str);
151*2d543d20SAndroid Build Coastguard Worker }
152*2d543d20SAndroid Build Coastguard Worker }
153*2d543d20SAndroid Build Coastguard Worker if (ret == HASHTAB_OVERFLOW) {
154*2d543d20SAndroid Build Coastguard Worker rc = -1;
155*2d543d20SAndroid Build Coastguard Worker free(new);
156*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG
157*2d543d20SAndroid Build Coastguard Worker (SELINUX_ERROR,
158*2d543d20SAndroid Build Coastguard Worker "%s: hashtab happen memory error.\n",
159*2d543d20SAndroid Build Coastguard Worker path);
160*2d543d20SAndroid Build Coastguard Worker break;
161*2d543d20SAndroid Build Coastguard Worker }
162*2d543d20SAndroid Build Coastguard Worker }
163*2d543d20SAndroid Build Coastguard Worker
164*2d543d20SAndroid Build Coastguard Worker selinux_hashtab_destroy_key(hash_table, destroy_chkdups_key);
165*2d543d20SAndroid Build Coastguard Worker
166*2d543d20SAndroid Build Coastguard Worker return rc;
167*2d543d20SAndroid Build Coastguard Worker }
168*2d543d20SAndroid Build Coastguard Worker
process_text_file(FILE * fp,const char * prefix,struct selabel_handle * rec,const char * path)169*2d543d20SAndroid Build Coastguard Worker static int process_text_file(FILE *fp, const char *prefix,
170*2d543d20SAndroid Build Coastguard Worker struct selabel_handle *rec, const char *path)
171*2d543d20SAndroid Build Coastguard Worker {
172*2d543d20SAndroid Build Coastguard Worker int rc;
173*2d543d20SAndroid Build Coastguard Worker size_t line_len;
174*2d543d20SAndroid Build Coastguard Worker unsigned int lineno = 0;
175*2d543d20SAndroid Build Coastguard Worker char *line_buf = NULL;
176*2d543d20SAndroid Build Coastguard Worker
177*2d543d20SAndroid Build Coastguard Worker while (getline(&line_buf, &line_len, fp) > 0) {
178*2d543d20SAndroid Build Coastguard Worker rc = process_line(rec, path, prefix, line_buf, ++lineno);
179*2d543d20SAndroid Build Coastguard Worker if (rc)
180*2d543d20SAndroid Build Coastguard Worker goto out;
181*2d543d20SAndroid Build Coastguard Worker }
182*2d543d20SAndroid Build Coastguard Worker rc = 0;
183*2d543d20SAndroid Build Coastguard Worker out:
184*2d543d20SAndroid Build Coastguard Worker free(line_buf);
185*2d543d20SAndroid Build Coastguard Worker return rc;
186*2d543d20SAndroid Build Coastguard Worker }
187*2d543d20SAndroid Build Coastguard Worker
load_mmap(FILE * fp,size_t len,struct selabel_handle * rec,const char * path)188*2d543d20SAndroid Build Coastguard Worker static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
189*2d543d20SAndroid Build Coastguard Worker const char *path)
190*2d543d20SAndroid Build Coastguard Worker {
191*2d543d20SAndroid Build Coastguard Worker struct saved_data *data = (struct saved_data *)rec->data;
192*2d543d20SAndroid Build Coastguard Worker int rc;
193*2d543d20SAndroid Build Coastguard Worker char *addr, *str_buf;
194*2d543d20SAndroid Build Coastguard Worker int *stem_map;
195*2d543d20SAndroid Build Coastguard Worker struct mmap_area *mmap_area;
196*2d543d20SAndroid Build Coastguard Worker uint32_t i, magic, version;
197*2d543d20SAndroid Build Coastguard Worker uint32_t entry_len, stem_map_len, regex_array_len;
198*2d543d20SAndroid Build Coastguard Worker const char *reg_version;
199*2d543d20SAndroid Build Coastguard Worker const char *reg_arch;
200*2d543d20SAndroid Build Coastguard Worker char reg_arch_matches = 0;
201*2d543d20SAndroid Build Coastguard Worker
202*2d543d20SAndroid Build Coastguard Worker mmap_area = malloc(sizeof(*mmap_area));
203*2d543d20SAndroid Build Coastguard Worker if (!mmap_area) {
204*2d543d20SAndroid Build Coastguard Worker return -1;
205*2d543d20SAndroid Build Coastguard Worker }
206*2d543d20SAndroid Build Coastguard Worker
207*2d543d20SAndroid Build Coastguard Worker addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
208*2d543d20SAndroid Build Coastguard Worker if (addr == MAP_FAILED) {
209*2d543d20SAndroid Build Coastguard Worker free(mmap_area);
210*2d543d20SAndroid Build Coastguard Worker perror("mmap");
211*2d543d20SAndroid Build Coastguard Worker return -1;
212*2d543d20SAndroid Build Coastguard Worker }
213*2d543d20SAndroid Build Coastguard Worker
214*2d543d20SAndroid Build Coastguard Worker /* save where we mmap'd the file to cleanup on close() */
215*2d543d20SAndroid Build Coastguard Worker mmap_area->addr = mmap_area->next_addr = addr;
216*2d543d20SAndroid Build Coastguard Worker mmap_area->len = mmap_area->next_len = len;
217*2d543d20SAndroid Build Coastguard Worker mmap_area->next = data->mmap_areas;
218*2d543d20SAndroid Build Coastguard Worker data->mmap_areas = mmap_area;
219*2d543d20SAndroid Build Coastguard Worker
220*2d543d20SAndroid Build Coastguard Worker /* check if this looks like an fcontext file */
221*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&magic, mmap_area, sizeof(uint32_t));
222*2d543d20SAndroid Build Coastguard Worker if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT)
223*2d543d20SAndroid Build Coastguard Worker return -1;
224*2d543d20SAndroid Build Coastguard Worker
225*2d543d20SAndroid Build Coastguard Worker /* check if this version is higher than we understand */
226*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&version, mmap_area, sizeof(uint32_t));
227*2d543d20SAndroid Build Coastguard Worker if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS)
228*2d543d20SAndroid Build Coastguard Worker return -1;
229*2d543d20SAndroid Build Coastguard Worker
230*2d543d20SAndroid Build Coastguard Worker reg_version = regex_version();
231*2d543d20SAndroid Build Coastguard Worker if (!reg_version)
232*2d543d20SAndroid Build Coastguard Worker return -1;
233*2d543d20SAndroid Build Coastguard Worker
234*2d543d20SAndroid Build Coastguard Worker reg_arch = regex_arch_string();
235*2d543d20SAndroid Build Coastguard Worker if (!reg_arch)
236*2d543d20SAndroid Build Coastguard Worker return -1;
237*2d543d20SAndroid Build Coastguard Worker
238*2d543d20SAndroid Build Coastguard Worker if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
239*2d543d20SAndroid Build Coastguard Worker
240*2d543d20SAndroid Build Coastguard Worker len = strlen(reg_version);
241*2d543d20SAndroid Build Coastguard Worker
242*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
243*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
244*2d543d20SAndroid Build Coastguard Worker return -1;
245*2d543d20SAndroid Build Coastguard Worker
246*2d543d20SAndroid Build Coastguard Worker /* Check version lengths */
247*2d543d20SAndroid Build Coastguard Worker if (len != entry_len)
248*2d543d20SAndroid Build Coastguard Worker return -1;
249*2d543d20SAndroid Build Coastguard Worker
250*2d543d20SAndroid Build Coastguard Worker /* Check if regex version mismatch */
251*2d543d20SAndroid Build Coastguard Worker str_buf = malloc(entry_len + 1);
252*2d543d20SAndroid Build Coastguard Worker if (!str_buf)
253*2d543d20SAndroid Build Coastguard Worker return -1;
254*2d543d20SAndroid Build Coastguard Worker
255*2d543d20SAndroid Build Coastguard Worker rc = next_entry(str_buf, mmap_area, entry_len);
256*2d543d20SAndroid Build Coastguard Worker if (rc < 0) {
257*2d543d20SAndroid Build Coastguard Worker free(str_buf);
258*2d543d20SAndroid Build Coastguard Worker return -1;
259*2d543d20SAndroid Build Coastguard Worker }
260*2d543d20SAndroid Build Coastguard Worker
261*2d543d20SAndroid Build Coastguard Worker str_buf[entry_len] = '\0';
262*2d543d20SAndroid Build Coastguard Worker if ((strcmp(str_buf, reg_version) != 0)) {
263*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_ERROR,
264*2d543d20SAndroid Build Coastguard Worker "Regex version mismatch, expected: %s actual: %s\n",
265*2d543d20SAndroid Build Coastguard Worker reg_version, str_buf);
266*2d543d20SAndroid Build Coastguard Worker free(str_buf);
267*2d543d20SAndroid Build Coastguard Worker return -1;
268*2d543d20SAndroid Build Coastguard Worker }
269*2d543d20SAndroid Build Coastguard Worker free(str_buf);
270*2d543d20SAndroid Build Coastguard Worker
271*2d543d20SAndroid Build Coastguard Worker if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
272*2d543d20SAndroid Build Coastguard Worker len = strlen(reg_arch);
273*2d543d20SAndroid Build Coastguard Worker
274*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&entry_len, mmap_area,
275*2d543d20SAndroid Build Coastguard Worker sizeof(uint32_t));
276*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
277*2d543d20SAndroid Build Coastguard Worker return -1;
278*2d543d20SAndroid Build Coastguard Worker
279*2d543d20SAndroid Build Coastguard Worker /* Check arch string lengths */
280*2d543d20SAndroid Build Coastguard Worker if (len != entry_len) {
281*2d543d20SAndroid Build Coastguard Worker /*
282*2d543d20SAndroid Build Coastguard Worker * Skip the entry and conclude that we have
283*2d543d20SAndroid Build Coastguard Worker * a mismatch, which is not fatal.
284*2d543d20SAndroid Build Coastguard Worker */
285*2d543d20SAndroid Build Coastguard Worker next_entry(NULL, mmap_area, entry_len);
286*2d543d20SAndroid Build Coastguard Worker goto end_arch_check;
287*2d543d20SAndroid Build Coastguard Worker }
288*2d543d20SAndroid Build Coastguard Worker
289*2d543d20SAndroid Build Coastguard Worker /* Check if arch string mismatch */
290*2d543d20SAndroid Build Coastguard Worker str_buf = malloc(entry_len + 1);
291*2d543d20SAndroid Build Coastguard Worker if (!str_buf)
292*2d543d20SAndroid Build Coastguard Worker return -1;
293*2d543d20SAndroid Build Coastguard Worker
294*2d543d20SAndroid Build Coastguard Worker rc = next_entry(str_buf, mmap_area, entry_len);
295*2d543d20SAndroid Build Coastguard Worker if (rc < 0) {
296*2d543d20SAndroid Build Coastguard Worker free(str_buf);
297*2d543d20SAndroid Build Coastguard Worker return -1;
298*2d543d20SAndroid Build Coastguard Worker }
299*2d543d20SAndroid Build Coastguard Worker
300*2d543d20SAndroid Build Coastguard Worker str_buf[entry_len] = '\0';
301*2d543d20SAndroid Build Coastguard Worker reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
302*2d543d20SAndroid Build Coastguard Worker free(str_buf);
303*2d543d20SAndroid Build Coastguard Worker }
304*2d543d20SAndroid Build Coastguard Worker }
305*2d543d20SAndroid Build Coastguard Worker end_arch_check:
306*2d543d20SAndroid Build Coastguard Worker
307*2d543d20SAndroid Build Coastguard Worker /* allocate the stems_data array */
308*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
309*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
310*2d543d20SAndroid Build Coastguard Worker return -1;
311*2d543d20SAndroid Build Coastguard Worker
312*2d543d20SAndroid Build Coastguard Worker /*
313*2d543d20SAndroid Build Coastguard Worker * map indexed by the stem # in the mmap file and contains the stem
314*2d543d20SAndroid Build Coastguard Worker * number in the data stem_arr
315*2d543d20SAndroid Build Coastguard Worker */
316*2d543d20SAndroid Build Coastguard Worker stem_map = calloc(stem_map_len, sizeof(*stem_map));
317*2d543d20SAndroid Build Coastguard Worker if (!stem_map)
318*2d543d20SAndroid Build Coastguard Worker return -1;
319*2d543d20SAndroid Build Coastguard Worker
320*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < stem_map_len; i++) {
321*2d543d20SAndroid Build Coastguard Worker char *buf;
322*2d543d20SAndroid Build Coastguard Worker uint32_t stem_len;
323*2d543d20SAndroid Build Coastguard Worker int newid;
324*2d543d20SAndroid Build Coastguard Worker
325*2d543d20SAndroid Build Coastguard Worker /* the length does not include the nul */
326*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t));
327*2d543d20SAndroid Build Coastguard Worker if (rc < 0 || !stem_len) {
328*2d543d20SAndroid Build Coastguard Worker rc = -1;
329*2d543d20SAndroid Build Coastguard Worker goto out;
330*2d543d20SAndroid Build Coastguard Worker }
331*2d543d20SAndroid Build Coastguard Worker
332*2d543d20SAndroid Build Coastguard Worker /* Check for stem_len wrap around. */
333*2d543d20SAndroid Build Coastguard Worker if (stem_len < UINT32_MAX) {
334*2d543d20SAndroid Build Coastguard Worker buf = (char *)mmap_area->next_addr;
335*2d543d20SAndroid Build Coastguard Worker /* Check if over-run before null check. */
336*2d543d20SAndroid Build Coastguard Worker rc = next_entry(NULL, mmap_area, (stem_len + 1));
337*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
338*2d543d20SAndroid Build Coastguard Worker goto out;
339*2d543d20SAndroid Build Coastguard Worker
340*2d543d20SAndroid Build Coastguard Worker if (buf[stem_len] != '\0') {
341*2d543d20SAndroid Build Coastguard Worker rc = -1;
342*2d543d20SAndroid Build Coastguard Worker goto out;
343*2d543d20SAndroid Build Coastguard Worker }
344*2d543d20SAndroid Build Coastguard Worker } else {
345*2d543d20SAndroid Build Coastguard Worker rc = -1;
346*2d543d20SAndroid Build Coastguard Worker goto out;
347*2d543d20SAndroid Build Coastguard Worker }
348*2d543d20SAndroid Build Coastguard Worker
349*2d543d20SAndroid Build Coastguard Worker /* store the mapping between old and new */
350*2d543d20SAndroid Build Coastguard Worker newid = find_stem(data, buf, stem_len);
351*2d543d20SAndroid Build Coastguard Worker if (newid < 0) {
352*2d543d20SAndroid Build Coastguard Worker newid = store_stem(data, buf, stem_len);
353*2d543d20SAndroid Build Coastguard Worker if (newid < 0) {
354*2d543d20SAndroid Build Coastguard Worker rc = newid;
355*2d543d20SAndroid Build Coastguard Worker goto out;
356*2d543d20SAndroid Build Coastguard Worker }
357*2d543d20SAndroid Build Coastguard Worker data->stem_arr[newid].from_mmap = 1;
358*2d543d20SAndroid Build Coastguard Worker }
359*2d543d20SAndroid Build Coastguard Worker stem_map[i] = newid;
360*2d543d20SAndroid Build Coastguard Worker }
361*2d543d20SAndroid Build Coastguard Worker
362*2d543d20SAndroid Build Coastguard Worker /* allocate the regex array */
363*2d543d20SAndroid Build Coastguard Worker rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t));
364*2d543d20SAndroid Build Coastguard Worker if (rc < 0 || !regex_array_len) {
365*2d543d20SAndroid Build Coastguard Worker rc = -1;
366*2d543d20SAndroid Build Coastguard Worker goto out;
367*2d543d20SAndroid Build Coastguard Worker }
368*2d543d20SAndroid Build Coastguard Worker
369*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < regex_array_len; i++) {
370*2d543d20SAndroid Build Coastguard Worker struct spec *spec;
371*2d543d20SAndroid Build Coastguard Worker int32_t stem_id, meta_chars;
372*2d543d20SAndroid Build Coastguard Worker uint32_t mode = 0, prefix_len = 0;
373*2d543d20SAndroid Build Coastguard Worker
374*2d543d20SAndroid Build Coastguard Worker rc = grow_specs(data);
375*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
376*2d543d20SAndroid Build Coastguard Worker goto out;
377*2d543d20SAndroid Build Coastguard Worker
378*2d543d20SAndroid Build Coastguard Worker spec = &data->spec_arr[data->nspec];
379*2d543d20SAndroid Build Coastguard Worker spec->from_mmap = 1;
380*2d543d20SAndroid Build Coastguard Worker
381*2d543d20SAndroid Build Coastguard Worker /* Process context */
382*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
383*2d543d20SAndroid Build Coastguard Worker if (rc < 0 || !entry_len) {
384*2d543d20SAndroid Build Coastguard Worker rc = -1;
385*2d543d20SAndroid Build Coastguard Worker goto out;
386*2d543d20SAndroid Build Coastguard Worker }
387*2d543d20SAndroid Build Coastguard Worker
388*2d543d20SAndroid Build Coastguard Worker str_buf = malloc(entry_len);
389*2d543d20SAndroid Build Coastguard Worker if (!str_buf) {
390*2d543d20SAndroid Build Coastguard Worker rc = -1;
391*2d543d20SAndroid Build Coastguard Worker goto out;
392*2d543d20SAndroid Build Coastguard Worker }
393*2d543d20SAndroid Build Coastguard Worker rc = next_entry(str_buf, mmap_area, entry_len);
394*2d543d20SAndroid Build Coastguard Worker if (rc < 0) {
395*2d543d20SAndroid Build Coastguard Worker free(str_buf);
396*2d543d20SAndroid Build Coastguard Worker goto out;
397*2d543d20SAndroid Build Coastguard Worker }
398*2d543d20SAndroid Build Coastguard Worker
399*2d543d20SAndroid Build Coastguard Worker if (str_buf[entry_len - 1] != '\0') {
400*2d543d20SAndroid Build Coastguard Worker free(str_buf);
401*2d543d20SAndroid Build Coastguard Worker rc = -1;
402*2d543d20SAndroid Build Coastguard Worker goto out;
403*2d543d20SAndroid Build Coastguard Worker }
404*2d543d20SAndroid Build Coastguard Worker spec->lr.ctx_raw = str_buf;
405*2d543d20SAndroid Build Coastguard Worker
406*2d543d20SAndroid Build Coastguard Worker if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) {
407*2d543d20SAndroid Build Coastguard Worker if (selabel_validate(&spec->lr) < 0) {
408*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
409*2d543d20SAndroid Build Coastguard Worker "%s: context %s is invalid\n",
410*2d543d20SAndroid Build Coastguard Worker path, spec->lr.ctx_raw);
411*2d543d20SAndroid Build Coastguard Worker goto out;
412*2d543d20SAndroid Build Coastguard Worker }
413*2d543d20SAndroid Build Coastguard Worker }
414*2d543d20SAndroid Build Coastguard Worker
415*2d543d20SAndroid Build Coastguard Worker /* Process regex string */
416*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
417*2d543d20SAndroid Build Coastguard Worker if (rc < 0 || !entry_len) {
418*2d543d20SAndroid Build Coastguard Worker rc = -1;
419*2d543d20SAndroid Build Coastguard Worker goto out;
420*2d543d20SAndroid Build Coastguard Worker }
421*2d543d20SAndroid Build Coastguard Worker
422*2d543d20SAndroid Build Coastguard Worker spec->regex_str = (char *)mmap_area->next_addr;
423*2d543d20SAndroid Build Coastguard Worker rc = next_entry(NULL, mmap_area, entry_len);
424*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
425*2d543d20SAndroid Build Coastguard Worker goto out;
426*2d543d20SAndroid Build Coastguard Worker
427*2d543d20SAndroid Build Coastguard Worker if (spec->regex_str[entry_len - 1] != '\0') {
428*2d543d20SAndroid Build Coastguard Worker rc = -1;
429*2d543d20SAndroid Build Coastguard Worker goto out;
430*2d543d20SAndroid Build Coastguard Worker }
431*2d543d20SAndroid Build Coastguard Worker
432*2d543d20SAndroid Build Coastguard Worker /* Process mode */
433*2d543d20SAndroid Build Coastguard Worker if (version >= SELINUX_COMPILED_FCONTEXT_MODE)
434*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&mode, mmap_area, sizeof(uint32_t));
435*2d543d20SAndroid Build Coastguard Worker else
436*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&mode, mmap_area, sizeof(mode_t));
437*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
438*2d543d20SAndroid Build Coastguard Worker goto out;
439*2d543d20SAndroid Build Coastguard Worker
440*2d543d20SAndroid Build Coastguard Worker spec->mode = mode;
441*2d543d20SAndroid Build Coastguard Worker
442*2d543d20SAndroid Build Coastguard Worker /* map the stem id from the mmap file to the data->stem_arr */
443*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&stem_id, mmap_area, sizeof(int32_t));
444*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
445*2d543d20SAndroid Build Coastguard Worker goto out;
446*2d543d20SAndroid Build Coastguard Worker
447*2d543d20SAndroid Build Coastguard Worker if (stem_id < 0 || stem_id >= (int32_t)stem_map_len)
448*2d543d20SAndroid Build Coastguard Worker spec->stem_id = -1;
449*2d543d20SAndroid Build Coastguard Worker else
450*2d543d20SAndroid Build Coastguard Worker spec->stem_id = stem_map[stem_id];
451*2d543d20SAndroid Build Coastguard Worker
452*2d543d20SAndroid Build Coastguard Worker /* retrieve the hasMetaChars bit */
453*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t));
454*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
455*2d543d20SAndroid Build Coastguard Worker goto out;
456*2d543d20SAndroid Build Coastguard Worker
457*2d543d20SAndroid Build Coastguard Worker spec->hasMetaChars = meta_chars;
458*2d543d20SAndroid Build Coastguard Worker /* and prefix length for use by selabel_lookup_best_match */
459*2d543d20SAndroid Build Coastguard Worker if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) {
460*2d543d20SAndroid Build Coastguard Worker rc = next_entry(&prefix_len, mmap_area,
461*2d543d20SAndroid Build Coastguard Worker sizeof(uint32_t));
462*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
463*2d543d20SAndroid Build Coastguard Worker goto out;
464*2d543d20SAndroid Build Coastguard Worker
465*2d543d20SAndroid Build Coastguard Worker spec->prefix_len = prefix_len;
466*2d543d20SAndroid Build Coastguard Worker }
467*2d543d20SAndroid Build Coastguard Worker
468*2d543d20SAndroid Build Coastguard Worker rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches,
469*2d543d20SAndroid Build Coastguard Worker &spec->regex_compiled);
470*2d543d20SAndroid Build Coastguard Worker if (rc < 0)
471*2d543d20SAndroid Build Coastguard Worker goto out;
472*2d543d20SAndroid Build Coastguard Worker
473*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_init(&spec->regex_lock, NULL);
474*2d543d20SAndroid Build Coastguard Worker data->nspec++;
475*2d543d20SAndroid Build Coastguard Worker }
476*2d543d20SAndroid Build Coastguard Worker
477*2d543d20SAndroid Build Coastguard Worker rc = 0;
478*2d543d20SAndroid Build Coastguard Worker out:
479*2d543d20SAndroid Build Coastguard Worker free(stem_map);
480*2d543d20SAndroid Build Coastguard Worker
481*2d543d20SAndroid Build Coastguard Worker return rc;
482*2d543d20SAndroid Build Coastguard Worker }
483*2d543d20SAndroid Build Coastguard Worker
484*2d543d20SAndroid Build Coastguard Worker struct file_details {
485*2d543d20SAndroid Build Coastguard Worker const char *suffix;
486*2d543d20SAndroid Build Coastguard Worker struct stat sb;
487*2d543d20SAndroid Build Coastguard Worker };
488*2d543d20SAndroid Build Coastguard Worker
rolling_append(char * current,const char * suffix,size_t max)489*2d543d20SAndroid Build Coastguard Worker static char *rolling_append(char *current, const char *suffix, size_t max)
490*2d543d20SAndroid Build Coastguard Worker {
491*2d543d20SAndroid Build Coastguard Worker size_t size;
492*2d543d20SAndroid Build Coastguard Worker size_t suffix_size;
493*2d543d20SAndroid Build Coastguard Worker size_t current_size;
494*2d543d20SAndroid Build Coastguard Worker
495*2d543d20SAndroid Build Coastguard Worker if (!suffix)
496*2d543d20SAndroid Build Coastguard Worker return current;
497*2d543d20SAndroid Build Coastguard Worker
498*2d543d20SAndroid Build Coastguard Worker current_size = strlen(current);
499*2d543d20SAndroid Build Coastguard Worker suffix_size = strlen(suffix);
500*2d543d20SAndroid Build Coastguard Worker
501*2d543d20SAndroid Build Coastguard Worker size = current_size + suffix_size;
502*2d543d20SAndroid Build Coastguard Worker if (size < current_size || size < suffix_size)
503*2d543d20SAndroid Build Coastguard Worker return NULL;
504*2d543d20SAndroid Build Coastguard Worker
505*2d543d20SAndroid Build Coastguard Worker /* ensure space for the '.' and the '\0' characters. */
506*2d543d20SAndroid Build Coastguard Worker if (size >= (SIZE_MAX - 2))
507*2d543d20SAndroid Build Coastguard Worker return NULL;
508*2d543d20SAndroid Build Coastguard Worker
509*2d543d20SAndroid Build Coastguard Worker size += 2;
510*2d543d20SAndroid Build Coastguard Worker
511*2d543d20SAndroid Build Coastguard Worker if (size > max)
512*2d543d20SAndroid Build Coastguard Worker return NULL;
513*2d543d20SAndroid Build Coastguard Worker
514*2d543d20SAndroid Build Coastguard Worker /* Append any given suffix */
515*2d543d20SAndroid Build Coastguard Worker char *to = current + current_size;
516*2d543d20SAndroid Build Coastguard Worker *to++ = '.';
517*2d543d20SAndroid Build Coastguard Worker strcpy(to, suffix);
518*2d543d20SAndroid Build Coastguard Worker
519*2d543d20SAndroid Build Coastguard Worker return current;
520*2d543d20SAndroid Build Coastguard Worker }
521*2d543d20SAndroid Build Coastguard Worker
fcontext_is_binary(FILE * fp)522*2d543d20SAndroid Build Coastguard Worker static int fcontext_is_binary(FILE *fp)
523*2d543d20SAndroid Build Coastguard Worker {
524*2d543d20SAndroid Build Coastguard Worker uint32_t magic;
525*2d543d20SAndroid Build Coastguard Worker int rc;
526*2d543d20SAndroid Build Coastguard Worker
527*2d543d20SAndroid Build Coastguard Worker size_t len = fread(&magic, sizeof(magic), 1, fp);
528*2d543d20SAndroid Build Coastguard Worker
529*2d543d20SAndroid Build Coastguard Worker rc = fseek(fp, 0L, SEEK_SET);
530*2d543d20SAndroid Build Coastguard Worker if (rc == -1)
531*2d543d20SAndroid Build Coastguard Worker return -1;
532*2d543d20SAndroid Build Coastguard Worker
533*2d543d20SAndroid Build Coastguard Worker return (len && (magic == SELINUX_MAGIC_COMPILED_FCONTEXT));
534*2d543d20SAndroid Build Coastguard Worker }
535*2d543d20SAndroid Build Coastguard Worker
536*2d543d20SAndroid Build Coastguard Worker #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
537*2d543d20SAndroid Build Coastguard Worker
open_file(const char * path,const char * suffix,char * save_path,size_t len,struct stat * sb,bool open_oldest)538*2d543d20SAndroid Build Coastguard Worker static FILE *open_file(const char *path, const char *suffix,
539*2d543d20SAndroid Build Coastguard Worker char *save_path, size_t len, struct stat *sb, bool open_oldest)
540*2d543d20SAndroid Build Coastguard Worker {
541*2d543d20SAndroid Build Coastguard Worker unsigned int i;
542*2d543d20SAndroid Build Coastguard Worker int rc;
543*2d543d20SAndroid Build Coastguard Worker char stack_path[len];
544*2d543d20SAndroid Build Coastguard Worker struct file_details *found = NULL;
545*2d543d20SAndroid Build Coastguard Worker
546*2d543d20SAndroid Build Coastguard Worker /*
547*2d543d20SAndroid Build Coastguard Worker * Rolling append of suffix. Try to open with path.suffix then the
548*2d543d20SAndroid Build Coastguard Worker * next as path.suffix.suffix and so forth.
549*2d543d20SAndroid Build Coastguard Worker */
550*2d543d20SAndroid Build Coastguard Worker struct file_details fdetails[2] = {
551*2d543d20SAndroid Build Coastguard Worker { .suffix = suffix },
552*2d543d20SAndroid Build Coastguard Worker { .suffix = "bin" }
553*2d543d20SAndroid Build Coastguard Worker };
554*2d543d20SAndroid Build Coastguard Worker
555*2d543d20SAndroid Build Coastguard Worker rc = snprintf(stack_path, sizeof(stack_path), "%s", path);
556*2d543d20SAndroid Build Coastguard Worker if (rc >= (int) sizeof(stack_path)) {
557*2d543d20SAndroid Build Coastguard Worker errno = ENAMETOOLONG;
558*2d543d20SAndroid Build Coastguard Worker return NULL;
559*2d543d20SAndroid Build Coastguard Worker }
560*2d543d20SAndroid Build Coastguard Worker
561*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(fdetails); i++) {
562*2d543d20SAndroid Build Coastguard Worker
563*2d543d20SAndroid Build Coastguard Worker /* This handles the case if suffix is null */
564*2d543d20SAndroid Build Coastguard Worker path = rolling_append(stack_path, fdetails[i].suffix,
565*2d543d20SAndroid Build Coastguard Worker sizeof(stack_path));
566*2d543d20SAndroid Build Coastguard Worker if (!path) {
567*2d543d20SAndroid Build Coastguard Worker errno = ENOMEM;
568*2d543d20SAndroid Build Coastguard Worker return NULL;
569*2d543d20SAndroid Build Coastguard Worker }
570*2d543d20SAndroid Build Coastguard Worker
571*2d543d20SAndroid Build Coastguard Worker rc = stat(path, &fdetails[i].sb);
572*2d543d20SAndroid Build Coastguard Worker if (rc)
573*2d543d20SAndroid Build Coastguard Worker continue;
574*2d543d20SAndroid Build Coastguard Worker
575*2d543d20SAndroid Build Coastguard Worker /* first file thing found, just take it */
576*2d543d20SAndroid Build Coastguard Worker if (!found) {
577*2d543d20SAndroid Build Coastguard Worker strcpy(save_path, path);
578*2d543d20SAndroid Build Coastguard Worker found = &fdetails[i];
579*2d543d20SAndroid Build Coastguard Worker continue;
580*2d543d20SAndroid Build Coastguard Worker }
581*2d543d20SAndroid Build Coastguard Worker
582*2d543d20SAndroid Build Coastguard Worker /*
583*2d543d20SAndroid Build Coastguard Worker * Keep picking the newest file found. Where "newest"
584*2d543d20SAndroid Build Coastguard Worker * includes equality. This provides a precedence on
585*2d543d20SAndroid Build Coastguard Worker * secondary suffixes even when the timestamp is the
586*2d543d20SAndroid Build Coastguard Worker * same. Ie choose file_contexts.bin over file_contexts
587*2d543d20SAndroid Build Coastguard Worker * even if the time stamp is the same. Invert this logic
588*2d543d20SAndroid Build Coastguard Worker * on open_oldest set to true. The idea is that if the
589*2d543d20SAndroid Build Coastguard Worker * newest file failed to process, we can attempt to
590*2d543d20SAndroid Build Coastguard Worker * process the oldest. The logic here is subtle and depends
591*2d543d20SAndroid Build Coastguard Worker * on the array ordering in fdetails for the case when time
592*2d543d20SAndroid Build Coastguard Worker * stamps are the same.
593*2d543d20SAndroid Build Coastguard Worker */
594*2d543d20SAndroid Build Coastguard Worker if (open_oldest ^
595*2d543d20SAndroid Build Coastguard Worker (fdetails[i].sb.st_mtime >= found->sb.st_mtime)) {
596*2d543d20SAndroid Build Coastguard Worker found = &fdetails[i];
597*2d543d20SAndroid Build Coastguard Worker strcpy(save_path, path);
598*2d543d20SAndroid Build Coastguard Worker }
599*2d543d20SAndroid Build Coastguard Worker }
600*2d543d20SAndroid Build Coastguard Worker
601*2d543d20SAndroid Build Coastguard Worker if (!found) {
602*2d543d20SAndroid Build Coastguard Worker errno = ENOENT;
603*2d543d20SAndroid Build Coastguard Worker return NULL;
604*2d543d20SAndroid Build Coastguard Worker }
605*2d543d20SAndroid Build Coastguard Worker
606*2d543d20SAndroid Build Coastguard Worker memcpy(sb, &found->sb, sizeof(*sb));
607*2d543d20SAndroid Build Coastguard Worker return fopen(save_path, "re");
608*2d543d20SAndroid Build Coastguard Worker }
609*2d543d20SAndroid Build Coastguard Worker
process_file(const char * path,const char * suffix,struct selabel_handle * rec,const char * prefix,struct selabel_digest * digest)610*2d543d20SAndroid Build Coastguard Worker static int process_file(const char *path, const char *suffix,
611*2d543d20SAndroid Build Coastguard Worker struct selabel_handle *rec,
612*2d543d20SAndroid Build Coastguard Worker const char *prefix, struct selabel_digest *digest)
613*2d543d20SAndroid Build Coastguard Worker {
614*2d543d20SAndroid Build Coastguard Worker int rc;
615*2d543d20SAndroid Build Coastguard Worker unsigned int i;
616*2d543d20SAndroid Build Coastguard Worker struct stat sb;
617*2d543d20SAndroid Build Coastguard Worker FILE *fp = NULL;
618*2d543d20SAndroid Build Coastguard Worker char found_path[PATH_MAX];
619*2d543d20SAndroid Build Coastguard Worker
620*2d543d20SAndroid Build Coastguard Worker /*
621*2d543d20SAndroid Build Coastguard Worker * On the first pass open the newest modified file. If it fails to
622*2d543d20SAndroid Build Coastguard Worker * process, then the second pass shall open the oldest file. If both
623*2d543d20SAndroid Build Coastguard Worker * passes fail, then it's a fatal error.
624*2d543d20SAndroid Build Coastguard Worker */
625*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < 2; i++) {
626*2d543d20SAndroid Build Coastguard Worker fp = open_file(path, suffix, found_path, sizeof(found_path),
627*2d543d20SAndroid Build Coastguard Worker &sb, i > 0);
628*2d543d20SAndroid Build Coastguard Worker if (fp == NULL)
629*2d543d20SAndroid Build Coastguard Worker return -1;
630*2d543d20SAndroid Build Coastguard Worker
631*2d543d20SAndroid Build Coastguard Worker rc = fcontext_is_binary(fp);
632*2d543d20SAndroid Build Coastguard Worker if (rc < 0) {
633*2d543d20SAndroid Build Coastguard Worker fclose_errno_safe(fp);
634*2d543d20SAndroid Build Coastguard Worker return -1;
635*2d543d20SAndroid Build Coastguard Worker }
636*2d543d20SAndroid Build Coastguard Worker
637*2d543d20SAndroid Build Coastguard Worker rc = rc ?
638*2d543d20SAndroid Build Coastguard Worker load_mmap(fp, sb.st_size, rec, found_path) :
639*2d543d20SAndroid Build Coastguard Worker process_text_file(fp, prefix, rec, found_path);
640*2d543d20SAndroid Build Coastguard Worker if (!rc)
641*2d543d20SAndroid Build Coastguard Worker rc = digest_add_specfile(digest, fp, NULL, sb.st_size,
642*2d543d20SAndroid Build Coastguard Worker found_path);
643*2d543d20SAndroid Build Coastguard Worker
644*2d543d20SAndroid Build Coastguard Worker fclose_errno_safe(fp);
645*2d543d20SAndroid Build Coastguard Worker
646*2d543d20SAndroid Build Coastguard Worker if (!rc)
647*2d543d20SAndroid Build Coastguard Worker return 0;
648*2d543d20SAndroid Build Coastguard Worker }
649*2d543d20SAndroid Build Coastguard Worker return -1;
650*2d543d20SAndroid Build Coastguard Worker }
651*2d543d20SAndroid Build Coastguard Worker
selabel_subs_fini(struct selabel_sub * ptr)652*2d543d20SAndroid Build Coastguard Worker static void selabel_subs_fini(struct selabel_sub *ptr)
653*2d543d20SAndroid Build Coastguard Worker {
654*2d543d20SAndroid Build Coastguard Worker struct selabel_sub *next;
655*2d543d20SAndroid Build Coastguard Worker
656*2d543d20SAndroid Build Coastguard Worker while (ptr) {
657*2d543d20SAndroid Build Coastguard Worker next = ptr->next;
658*2d543d20SAndroid Build Coastguard Worker free(ptr->src);
659*2d543d20SAndroid Build Coastguard Worker free(ptr->dst);
660*2d543d20SAndroid Build Coastguard Worker free(ptr);
661*2d543d20SAndroid Build Coastguard Worker ptr = next;
662*2d543d20SAndroid Build Coastguard Worker }
663*2d543d20SAndroid Build Coastguard Worker }
664*2d543d20SAndroid Build Coastguard Worker
selabel_sub(struct selabel_sub * ptr,const char * src)665*2d543d20SAndroid Build Coastguard Worker static char *selabel_sub(struct selabel_sub *ptr, const char *src)
666*2d543d20SAndroid Build Coastguard Worker {
667*2d543d20SAndroid Build Coastguard Worker char *dst = NULL;
668*2d543d20SAndroid Build Coastguard Worker int len;
669*2d543d20SAndroid Build Coastguard Worker
670*2d543d20SAndroid Build Coastguard Worker while (ptr) {
671*2d543d20SAndroid Build Coastguard Worker if (strncmp(src, ptr->src, ptr->slen) == 0 ) {
672*2d543d20SAndroid Build Coastguard Worker if (src[ptr->slen] == '/' ||
673*2d543d20SAndroid Build Coastguard Worker src[ptr->slen] == 0) {
674*2d543d20SAndroid Build Coastguard Worker if ((src[ptr->slen] == '/') &&
675*2d543d20SAndroid Build Coastguard Worker (strcmp(ptr->dst, "/") == 0))
676*2d543d20SAndroid Build Coastguard Worker len = ptr->slen + 1;
677*2d543d20SAndroid Build Coastguard Worker else
678*2d543d20SAndroid Build Coastguard Worker len = ptr->slen;
679*2d543d20SAndroid Build Coastguard Worker if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0)
680*2d543d20SAndroid Build Coastguard Worker return NULL;
681*2d543d20SAndroid Build Coastguard Worker return dst;
682*2d543d20SAndroid Build Coastguard Worker }
683*2d543d20SAndroid Build Coastguard Worker }
684*2d543d20SAndroid Build Coastguard Worker ptr = ptr->next;
685*2d543d20SAndroid Build Coastguard Worker }
686*2d543d20SAndroid Build Coastguard Worker return NULL;
687*2d543d20SAndroid Build Coastguard Worker }
688*2d543d20SAndroid Build Coastguard Worker
689*2d543d20SAndroid Build Coastguard Worker #if !defined(BUILD_HOST) && !defined(ANDROID)
selabel_subs_init(const char * path,struct selabel_digest * digest,struct selabel_sub ** out_subs)690*2d543d20SAndroid Build Coastguard Worker static int selabel_subs_init(const char *path, struct selabel_digest *digest,
691*2d543d20SAndroid Build Coastguard Worker struct selabel_sub **out_subs)
692*2d543d20SAndroid Build Coastguard Worker {
693*2d543d20SAndroid Build Coastguard Worker char buf[1024];
694*2d543d20SAndroid Build Coastguard Worker FILE *cfg = fopen(path, "re");
695*2d543d20SAndroid Build Coastguard Worker struct selabel_sub *list = NULL, *sub = NULL;
696*2d543d20SAndroid Build Coastguard Worker struct stat sb;
697*2d543d20SAndroid Build Coastguard Worker int status = -1;
698*2d543d20SAndroid Build Coastguard Worker
699*2d543d20SAndroid Build Coastguard Worker *out_subs = NULL;
700*2d543d20SAndroid Build Coastguard Worker if (!cfg) {
701*2d543d20SAndroid Build Coastguard Worker /* If the file does not exist, it is not fatal */
702*2d543d20SAndroid Build Coastguard Worker return (errno == ENOENT) ? 0 : -1;
703*2d543d20SAndroid Build Coastguard Worker }
704*2d543d20SAndroid Build Coastguard Worker
705*2d543d20SAndroid Build Coastguard Worker if (fstat(fileno(cfg), &sb) < 0)
706*2d543d20SAndroid Build Coastguard Worker goto out;
707*2d543d20SAndroid Build Coastguard Worker
708*2d543d20SAndroid Build Coastguard Worker while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) {
709*2d543d20SAndroid Build Coastguard Worker char *ptr = NULL;
710*2d543d20SAndroid Build Coastguard Worker char *src = buf;
711*2d543d20SAndroid Build Coastguard Worker char *dst = NULL;
712*2d543d20SAndroid Build Coastguard Worker
713*2d543d20SAndroid Build Coastguard Worker while (*src && isspace((unsigned char)*src))
714*2d543d20SAndroid Build Coastguard Worker src++;
715*2d543d20SAndroid Build Coastguard Worker if (src[0] == '#') continue;
716*2d543d20SAndroid Build Coastguard Worker ptr = src;
717*2d543d20SAndroid Build Coastguard Worker while (*ptr && ! isspace((unsigned char)*ptr))
718*2d543d20SAndroid Build Coastguard Worker ptr++;
719*2d543d20SAndroid Build Coastguard Worker *ptr++ = '\0';
720*2d543d20SAndroid Build Coastguard Worker if (! *src) continue;
721*2d543d20SAndroid Build Coastguard Worker
722*2d543d20SAndroid Build Coastguard Worker dst = ptr;
723*2d543d20SAndroid Build Coastguard Worker while (*dst && isspace((unsigned char)*dst))
724*2d543d20SAndroid Build Coastguard Worker dst++;
725*2d543d20SAndroid Build Coastguard Worker ptr = dst;
726*2d543d20SAndroid Build Coastguard Worker while (*ptr && ! isspace((unsigned char)*ptr))
727*2d543d20SAndroid Build Coastguard Worker ptr++;
728*2d543d20SAndroid Build Coastguard Worker *ptr = '\0';
729*2d543d20SAndroid Build Coastguard Worker if (! *dst)
730*2d543d20SAndroid Build Coastguard Worker continue;
731*2d543d20SAndroid Build Coastguard Worker
732*2d543d20SAndroid Build Coastguard Worker sub = calloc(1, sizeof(*sub));
733*2d543d20SAndroid Build Coastguard Worker if (! sub)
734*2d543d20SAndroid Build Coastguard Worker goto err;
735*2d543d20SAndroid Build Coastguard Worker
736*2d543d20SAndroid Build Coastguard Worker sub->src = strdup(src);
737*2d543d20SAndroid Build Coastguard Worker if (! sub->src)
738*2d543d20SAndroid Build Coastguard Worker goto err;
739*2d543d20SAndroid Build Coastguard Worker
740*2d543d20SAndroid Build Coastguard Worker sub->dst = strdup(dst);
741*2d543d20SAndroid Build Coastguard Worker if (! sub->dst)
742*2d543d20SAndroid Build Coastguard Worker goto err;
743*2d543d20SAndroid Build Coastguard Worker
744*2d543d20SAndroid Build Coastguard Worker sub->slen = strlen(src);
745*2d543d20SAndroid Build Coastguard Worker sub->next = list;
746*2d543d20SAndroid Build Coastguard Worker list = sub;
747*2d543d20SAndroid Build Coastguard Worker sub = NULL;
748*2d543d20SAndroid Build Coastguard Worker }
749*2d543d20SAndroid Build Coastguard Worker
750*2d543d20SAndroid Build Coastguard Worker if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0)
751*2d543d20SAndroid Build Coastguard Worker goto err;
752*2d543d20SAndroid Build Coastguard Worker
753*2d543d20SAndroid Build Coastguard Worker *out_subs = list;
754*2d543d20SAndroid Build Coastguard Worker status = 0;
755*2d543d20SAndroid Build Coastguard Worker
756*2d543d20SAndroid Build Coastguard Worker out:
757*2d543d20SAndroid Build Coastguard Worker fclose(cfg);
758*2d543d20SAndroid Build Coastguard Worker return status;
759*2d543d20SAndroid Build Coastguard Worker err:
760*2d543d20SAndroid Build Coastguard Worker if (sub)
761*2d543d20SAndroid Build Coastguard Worker free(sub->src);
762*2d543d20SAndroid Build Coastguard Worker free(sub);
763*2d543d20SAndroid Build Coastguard Worker while (list) {
764*2d543d20SAndroid Build Coastguard Worker sub = list->next;
765*2d543d20SAndroid Build Coastguard Worker free(list->src);
766*2d543d20SAndroid Build Coastguard Worker free(list->dst);
767*2d543d20SAndroid Build Coastguard Worker free(list);
768*2d543d20SAndroid Build Coastguard Worker list = sub;
769*2d543d20SAndroid Build Coastguard Worker }
770*2d543d20SAndroid Build Coastguard Worker goto out;
771*2d543d20SAndroid Build Coastguard Worker }
772*2d543d20SAndroid Build Coastguard Worker #endif
773*2d543d20SAndroid Build Coastguard Worker
selabel_sub_key(struct saved_data * data,const char * key)774*2d543d20SAndroid Build Coastguard Worker static char *selabel_sub_key(struct saved_data *data, const char *key)
775*2d543d20SAndroid Build Coastguard Worker {
776*2d543d20SAndroid Build Coastguard Worker char *ptr = NULL;
777*2d543d20SAndroid Build Coastguard Worker char *dptr = NULL;
778*2d543d20SAndroid Build Coastguard Worker
779*2d543d20SAndroid Build Coastguard Worker ptr = selabel_sub(data->subs, key);
780*2d543d20SAndroid Build Coastguard Worker if (ptr) {
781*2d543d20SAndroid Build Coastguard Worker dptr = selabel_sub(data->dist_subs, ptr);
782*2d543d20SAndroid Build Coastguard Worker if (dptr) {
783*2d543d20SAndroid Build Coastguard Worker free(ptr);
784*2d543d20SAndroid Build Coastguard Worker ptr = dptr;
785*2d543d20SAndroid Build Coastguard Worker }
786*2d543d20SAndroid Build Coastguard Worker } else {
787*2d543d20SAndroid Build Coastguard Worker ptr = selabel_sub(data->dist_subs, key);
788*2d543d20SAndroid Build Coastguard Worker }
789*2d543d20SAndroid Build Coastguard Worker if (ptr)
790*2d543d20SAndroid Build Coastguard Worker return ptr;
791*2d543d20SAndroid Build Coastguard Worker
792*2d543d20SAndroid Build Coastguard Worker return NULL;
793*2d543d20SAndroid Build Coastguard Worker }
794*2d543d20SAndroid Build Coastguard Worker
795*2d543d20SAndroid Build Coastguard Worker static void closef(struct selabel_handle *rec);
796*2d543d20SAndroid Build Coastguard Worker
init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned n)797*2d543d20SAndroid Build Coastguard Worker static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
798*2d543d20SAndroid Build Coastguard Worker unsigned n)
799*2d543d20SAndroid Build Coastguard Worker {
800*2d543d20SAndroid Build Coastguard Worker struct saved_data *data = (struct saved_data *)rec->data;
801*2d543d20SAndroid Build Coastguard Worker size_t num_paths = 0;
802*2d543d20SAndroid Build Coastguard Worker char **path = NULL;
803*2d543d20SAndroid Build Coastguard Worker const char *prefix = NULL;
804*2d543d20SAndroid Build Coastguard Worker int status = -1;
805*2d543d20SAndroid Build Coastguard Worker size_t i;
806*2d543d20SAndroid Build Coastguard Worker bool baseonly = false;
807*2d543d20SAndroid Build Coastguard Worker bool path_provided;
808*2d543d20SAndroid Build Coastguard Worker
809*2d543d20SAndroid Build Coastguard Worker /* Process arguments */
810*2d543d20SAndroid Build Coastguard Worker i = n;
811*2d543d20SAndroid Build Coastguard Worker while (i--) {
812*2d543d20SAndroid Build Coastguard Worker switch(opts[i].type) {
813*2d543d20SAndroid Build Coastguard Worker case SELABEL_OPT_PATH:
814*2d543d20SAndroid Build Coastguard Worker num_paths++;
815*2d543d20SAndroid Build Coastguard Worker break;
816*2d543d20SAndroid Build Coastguard Worker case SELABEL_OPT_SUBSET:
817*2d543d20SAndroid Build Coastguard Worker prefix = opts[i].value;
818*2d543d20SAndroid Build Coastguard Worker break;
819*2d543d20SAndroid Build Coastguard Worker case SELABEL_OPT_BASEONLY:
820*2d543d20SAndroid Build Coastguard Worker baseonly = !!opts[i].value;
821*2d543d20SAndroid Build Coastguard Worker break;
822*2d543d20SAndroid Build Coastguard Worker case SELABEL_OPT_UNUSED:
823*2d543d20SAndroid Build Coastguard Worker case SELABEL_OPT_VALIDATE:
824*2d543d20SAndroid Build Coastguard Worker case SELABEL_OPT_DIGEST:
825*2d543d20SAndroid Build Coastguard Worker break;
826*2d543d20SAndroid Build Coastguard Worker default:
827*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
828*2d543d20SAndroid Build Coastguard Worker return -1;
829*2d543d20SAndroid Build Coastguard Worker }
830*2d543d20SAndroid Build Coastguard Worker }
831*2d543d20SAndroid Build Coastguard Worker
832*2d543d20SAndroid Build Coastguard Worker if (!num_paths) {
833*2d543d20SAndroid Build Coastguard Worker num_paths = 1;
834*2d543d20SAndroid Build Coastguard Worker path_provided = false;
835*2d543d20SAndroid Build Coastguard Worker } else {
836*2d543d20SAndroid Build Coastguard Worker path_provided = true;
837*2d543d20SAndroid Build Coastguard Worker }
838*2d543d20SAndroid Build Coastguard Worker
839*2d543d20SAndroid Build Coastguard Worker path = calloc(num_paths, sizeof(*path));
840*2d543d20SAndroid Build Coastguard Worker if (path == NULL) {
841*2d543d20SAndroid Build Coastguard Worker goto finish;
842*2d543d20SAndroid Build Coastguard Worker }
843*2d543d20SAndroid Build Coastguard Worker rec->spec_files = path;
844*2d543d20SAndroid Build Coastguard Worker rec->spec_files_len = num_paths;
845*2d543d20SAndroid Build Coastguard Worker
846*2d543d20SAndroid Build Coastguard Worker if (path_provided) {
847*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < n; i++) {
848*2d543d20SAndroid Build Coastguard Worker switch(opts[i].type) {
849*2d543d20SAndroid Build Coastguard Worker case SELABEL_OPT_PATH:
850*2d543d20SAndroid Build Coastguard Worker *path = strdup(opts[i].value);
851*2d543d20SAndroid Build Coastguard Worker if (*path == NULL)
852*2d543d20SAndroid Build Coastguard Worker goto finish;
853*2d543d20SAndroid Build Coastguard Worker path++;
854*2d543d20SAndroid Build Coastguard Worker break;
855*2d543d20SAndroid Build Coastguard Worker default:
856*2d543d20SAndroid Build Coastguard Worker break;
857*2d543d20SAndroid Build Coastguard Worker }
858*2d543d20SAndroid Build Coastguard Worker }
859*2d543d20SAndroid Build Coastguard Worker }
860*2d543d20SAndroid Build Coastguard Worker #if !defined(BUILD_HOST) && !defined(ANDROID)
861*2d543d20SAndroid Build Coastguard Worker char subs_file[PATH_MAX + 1];
862*2d543d20SAndroid Build Coastguard Worker /* Process local and distribution substitution files */
863*2d543d20SAndroid Build Coastguard Worker if (!path_provided) {
864*2d543d20SAndroid Build Coastguard Worker status = selabel_subs_init(
865*2d543d20SAndroid Build Coastguard Worker selinux_file_context_subs_dist_path(),
866*2d543d20SAndroid Build Coastguard Worker rec->digest, &data->dist_subs);
867*2d543d20SAndroid Build Coastguard Worker if (status)
868*2d543d20SAndroid Build Coastguard Worker goto finish;
869*2d543d20SAndroid Build Coastguard Worker status = selabel_subs_init(selinux_file_context_subs_path(),
870*2d543d20SAndroid Build Coastguard Worker rec->digest, &data->subs);
871*2d543d20SAndroid Build Coastguard Worker if (status)
872*2d543d20SAndroid Build Coastguard Worker goto finish;
873*2d543d20SAndroid Build Coastguard Worker rec->spec_files[0] = strdup(selinux_file_context_path());
874*2d543d20SAndroid Build Coastguard Worker if (rec->spec_files[0] == NULL)
875*2d543d20SAndroid Build Coastguard Worker goto finish;
876*2d543d20SAndroid Build Coastguard Worker } else {
877*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < num_paths; i++) {
878*2d543d20SAndroid Build Coastguard Worker snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", rec->spec_files[i]);
879*2d543d20SAndroid Build Coastguard Worker status = selabel_subs_init(subs_file, rec->digest,
880*2d543d20SAndroid Build Coastguard Worker &data->dist_subs);
881*2d543d20SAndroid Build Coastguard Worker if (status)
882*2d543d20SAndroid Build Coastguard Worker goto finish;
883*2d543d20SAndroid Build Coastguard Worker snprintf(subs_file, sizeof(subs_file), "%s.subs", rec->spec_files[i]);
884*2d543d20SAndroid Build Coastguard Worker status = selabel_subs_init(subs_file, rec->digest,
885*2d543d20SAndroid Build Coastguard Worker &data->subs);
886*2d543d20SAndroid Build Coastguard Worker if (status)
887*2d543d20SAndroid Build Coastguard Worker goto finish;
888*2d543d20SAndroid Build Coastguard Worker }
889*2d543d20SAndroid Build Coastguard Worker }
890*2d543d20SAndroid Build Coastguard Worker #else
891*2d543d20SAndroid Build Coastguard Worker if (!path_provided) {
892*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "No path given to file labeling backend\n");
893*2d543d20SAndroid Build Coastguard Worker goto finish;
894*2d543d20SAndroid Build Coastguard Worker }
895*2d543d20SAndroid Build Coastguard Worker #endif
896*2d543d20SAndroid Build Coastguard Worker
897*2d543d20SAndroid Build Coastguard Worker /*
898*2d543d20SAndroid Build Coastguard Worker * Do detailed validation of the input and fill the spec array
899*2d543d20SAndroid Build Coastguard Worker */
900*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < num_paths; i++) {
901*2d543d20SAndroid Build Coastguard Worker status = process_file(rec->spec_files[i], NULL, rec, prefix, rec->digest);
902*2d543d20SAndroid Build Coastguard Worker if (status)
903*2d543d20SAndroid Build Coastguard Worker goto finish;
904*2d543d20SAndroid Build Coastguard Worker
905*2d543d20SAndroid Build Coastguard Worker if (rec->validating) {
906*2d543d20SAndroid Build Coastguard Worker status = nodups_specs(data, rec->spec_files[i]);
907*2d543d20SAndroid Build Coastguard Worker if (status)
908*2d543d20SAndroid Build Coastguard Worker goto finish;
909*2d543d20SAndroid Build Coastguard Worker }
910*2d543d20SAndroid Build Coastguard Worker }
911*2d543d20SAndroid Build Coastguard Worker
912*2d543d20SAndroid Build Coastguard Worker if (!baseonly) {
913*2d543d20SAndroid Build Coastguard Worker status = process_file(rec->spec_files[0], "homedirs", rec, prefix,
914*2d543d20SAndroid Build Coastguard Worker rec->digest);
915*2d543d20SAndroid Build Coastguard Worker if (status && errno != ENOENT)
916*2d543d20SAndroid Build Coastguard Worker goto finish;
917*2d543d20SAndroid Build Coastguard Worker
918*2d543d20SAndroid Build Coastguard Worker status = process_file(rec->spec_files[0], "local", rec, prefix,
919*2d543d20SAndroid Build Coastguard Worker rec->digest);
920*2d543d20SAndroid Build Coastguard Worker if (status && errno != ENOENT)
921*2d543d20SAndroid Build Coastguard Worker goto finish;
922*2d543d20SAndroid Build Coastguard Worker }
923*2d543d20SAndroid Build Coastguard Worker
924*2d543d20SAndroid Build Coastguard Worker digest_gen_hash(rec->digest);
925*2d543d20SAndroid Build Coastguard Worker
926*2d543d20SAndroid Build Coastguard Worker status = sort_specs(data);
927*2d543d20SAndroid Build Coastguard Worker
928*2d543d20SAndroid Build Coastguard Worker finish:
929*2d543d20SAndroid Build Coastguard Worker if (status)
930*2d543d20SAndroid Build Coastguard Worker closef(rec);
931*2d543d20SAndroid Build Coastguard Worker
932*2d543d20SAndroid Build Coastguard Worker return status;
933*2d543d20SAndroid Build Coastguard Worker }
934*2d543d20SAndroid Build Coastguard Worker
935*2d543d20SAndroid Build Coastguard Worker /*
936*2d543d20SAndroid Build Coastguard Worker * Backend interface routines
937*2d543d20SAndroid Build Coastguard Worker */
closef(struct selabel_handle * rec)938*2d543d20SAndroid Build Coastguard Worker static void closef(struct selabel_handle *rec)
939*2d543d20SAndroid Build Coastguard Worker {
940*2d543d20SAndroid Build Coastguard Worker struct saved_data *data = (struct saved_data *)rec->data;
941*2d543d20SAndroid Build Coastguard Worker struct mmap_area *area, *last_area;
942*2d543d20SAndroid Build Coastguard Worker struct spec *spec;
943*2d543d20SAndroid Build Coastguard Worker struct stem *stem;
944*2d543d20SAndroid Build Coastguard Worker unsigned int i;
945*2d543d20SAndroid Build Coastguard Worker
946*2d543d20SAndroid Build Coastguard Worker if (!data)
947*2d543d20SAndroid Build Coastguard Worker return;
948*2d543d20SAndroid Build Coastguard Worker
949*2d543d20SAndroid Build Coastguard Worker /* make sure successive ->func_close() calls are harmless */
950*2d543d20SAndroid Build Coastguard Worker rec->data = NULL;
951*2d543d20SAndroid Build Coastguard Worker
952*2d543d20SAndroid Build Coastguard Worker selabel_subs_fini(data->subs);
953*2d543d20SAndroid Build Coastguard Worker selabel_subs_fini(data->dist_subs);
954*2d543d20SAndroid Build Coastguard Worker
955*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < data->nspec; i++) {
956*2d543d20SAndroid Build Coastguard Worker spec = &data->spec_arr[i];
957*2d543d20SAndroid Build Coastguard Worker free(spec->lr.ctx_trans);
958*2d543d20SAndroid Build Coastguard Worker free(spec->lr.ctx_raw);
959*2d543d20SAndroid Build Coastguard Worker regex_data_free(spec->regex);
960*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_destroy(&spec->regex_lock);
961*2d543d20SAndroid Build Coastguard Worker if (spec->from_mmap)
962*2d543d20SAndroid Build Coastguard Worker continue;
963*2d543d20SAndroid Build Coastguard Worker free(spec->regex_str);
964*2d543d20SAndroid Build Coastguard Worker free(spec->type_str);
965*2d543d20SAndroid Build Coastguard Worker }
966*2d543d20SAndroid Build Coastguard Worker
967*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < (unsigned int)data->num_stems; i++) {
968*2d543d20SAndroid Build Coastguard Worker stem = &data->stem_arr[i];
969*2d543d20SAndroid Build Coastguard Worker if (stem->from_mmap)
970*2d543d20SAndroid Build Coastguard Worker continue;
971*2d543d20SAndroid Build Coastguard Worker free(stem->buf);
972*2d543d20SAndroid Build Coastguard Worker }
973*2d543d20SAndroid Build Coastguard Worker
974*2d543d20SAndroid Build Coastguard Worker if (data->spec_arr)
975*2d543d20SAndroid Build Coastguard Worker free(data->spec_arr);
976*2d543d20SAndroid Build Coastguard Worker if (data->stem_arr)
977*2d543d20SAndroid Build Coastguard Worker free(data->stem_arr);
978*2d543d20SAndroid Build Coastguard Worker
979*2d543d20SAndroid Build Coastguard Worker area = data->mmap_areas;
980*2d543d20SAndroid Build Coastguard Worker while (area) {
981*2d543d20SAndroid Build Coastguard Worker munmap(area->addr, area->len);
982*2d543d20SAndroid Build Coastguard Worker last_area = area;
983*2d543d20SAndroid Build Coastguard Worker area = area->next;
984*2d543d20SAndroid Build Coastguard Worker free(last_area);
985*2d543d20SAndroid Build Coastguard Worker }
986*2d543d20SAndroid Build Coastguard Worker free(data);
987*2d543d20SAndroid Build Coastguard Worker rec->data = NULL;
988*2d543d20SAndroid Build Coastguard Worker }
989*2d543d20SAndroid Build Coastguard Worker
990*2d543d20SAndroid Build Coastguard Worker // Finds all the matches of |key| in the given context. Returns the result in
991*2d543d20SAndroid Build Coastguard Worker // the allocated array and updates the match count. If match_count is NULL,
992*2d543d20SAndroid Build Coastguard Worker // stops early once the 1st match is found.
lookup_all(struct selabel_handle * rec,const char * key,int type,bool partial,size_t * match_count)993*2d543d20SAndroid Build Coastguard Worker static struct spec **lookup_all(struct selabel_handle *rec,
994*2d543d20SAndroid Build Coastguard Worker const char *key,
995*2d543d20SAndroid Build Coastguard Worker int type,
996*2d543d20SAndroid Build Coastguard Worker bool partial,
997*2d543d20SAndroid Build Coastguard Worker size_t *match_count)
998*2d543d20SAndroid Build Coastguard Worker {
999*2d543d20SAndroid Build Coastguard Worker struct saved_data *data = (struct saved_data *)rec->data;
1000*2d543d20SAndroid Build Coastguard Worker struct spec *spec_arr = data->spec_arr;
1001*2d543d20SAndroid Build Coastguard Worker int i, rc, file_stem;
1002*2d543d20SAndroid Build Coastguard Worker size_t len;
1003*2d543d20SAndroid Build Coastguard Worker mode_t mode = (mode_t)type;
1004*2d543d20SAndroid Build Coastguard Worker char *clean_key = NULL;
1005*2d543d20SAndroid Build Coastguard Worker const char *prev_slash, *next_slash;
1006*2d543d20SAndroid Build Coastguard Worker unsigned int sofar = 0;
1007*2d543d20SAndroid Build Coastguard Worker char *sub = NULL;
1008*2d543d20SAndroid Build Coastguard Worker
1009*2d543d20SAndroid Build Coastguard Worker struct spec **result = NULL;
1010*2d543d20SAndroid Build Coastguard Worker if (match_count) {
1011*2d543d20SAndroid Build Coastguard Worker *match_count = 0;
1012*2d543d20SAndroid Build Coastguard Worker result = calloc(data->nspec, sizeof(struct spec*));
1013*2d543d20SAndroid Build Coastguard Worker } else {
1014*2d543d20SAndroid Build Coastguard Worker result = calloc(1, sizeof(struct spec*));
1015*2d543d20SAndroid Build Coastguard Worker }
1016*2d543d20SAndroid Build Coastguard Worker if (!result) {
1017*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "Failed to allocate %zu bytes of data\n",
1018*2d543d20SAndroid Build Coastguard Worker data->nspec * sizeof(struct spec*));
1019*2d543d20SAndroid Build Coastguard Worker goto finish;
1020*2d543d20SAndroid Build Coastguard Worker }
1021*2d543d20SAndroid Build Coastguard Worker
1022*2d543d20SAndroid Build Coastguard Worker if (!data->nspec) {
1023*2d543d20SAndroid Build Coastguard Worker errno = ENOENT;
1024*2d543d20SAndroid Build Coastguard Worker goto finish;
1025*2d543d20SAndroid Build Coastguard Worker }
1026*2d543d20SAndroid Build Coastguard Worker
1027*2d543d20SAndroid Build Coastguard Worker /* Remove duplicate slashes */
1028*2d543d20SAndroid Build Coastguard Worker if ((next_slash = strstr(key, "//"))) {
1029*2d543d20SAndroid Build Coastguard Worker clean_key = (char *) malloc(strlen(key) + 1);
1030*2d543d20SAndroid Build Coastguard Worker if (!clean_key)
1031*2d543d20SAndroid Build Coastguard Worker goto finish;
1032*2d543d20SAndroid Build Coastguard Worker prev_slash = key;
1033*2d543d20SAndroid Build Coastguard Worker while (next_slash) {
1034*2d543d20SAndroid Build Coastguard Worker memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash);
1035*2d543d20SAndroid Build Coastguard Worker sofar += next_slash - prev_slash;
1036*2d543d20SAndroid Build Coastguard Worker prev_slash = next_slash + 1;
1037*2d543d20SAndroid Build Coastguard Worker next_slash = strstr(prev_slash, "//");
1038*2d543d20SAndroid Build Coastguard Worker }
1039*2d543d20SAndroid Build Coastguard Worker strcpy(clean_key + sofar, prev_slash);
1040*2d543d20SAndroid Build Coastguard Worker key = clean_key;
1041*2d543d20SAndroid Build Coastguard Worker }
1042*2d543d20SAndroid Build Coastguard Worker
1043*2d543d20SAndroid Build Coastguard Worker /* remove trailing slash */
1044*2d543d20SAndroid Build Coastguard Worker len = strlen(key);
1045*2d543d20SAndroid Build Coastguard Worker if (len == 0) {
1046*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
1047*2d543d20SAndroid Build Coastguard Worker goto finish;
1048*2d543d20SAndroid Build Coastguard Worker }
1049*2d543d20SAndroid Build Coastguard Worker
1050*2d543d20SAndroid Build Coastguard Worker if (len > 1 && key[len - 1] == '/') {
1051*2d543d20SAndroid Build Coastguard Worker /* reuse clean_key from above if available */
1052*2d543d20SAndroid Build Coastguard Worker if (!clean_key) {
1053*2d543d20SAndroid Build Coastguard Worker clean_key = (char *) malloc(len);
1054*2d543d20SAndroid Build Coastguard Worker if (!clean_key)
1055*2d543d20SAndroid Build Coastguard Worker goto finish;
1056*2d543d20SAndroid Build Coastguard Worker
1057*2d543d20SAndroid Build Coastguard Worker memcpy(clean_key, key, len - 1);
1058*2d543d20SAndroid Build Coastguard Worker }
1059*2d543d20SAndroid Build Coastguard Worker
1060*2d543d20SAndroid Build Coastguard Worker clean_key[len - 1] = '\0';
1061*2d543d20SAndroid Build Coastguard Worker key = clean_key;
1062*2d543d20SAndroid Build Coastguard Worker }
1063*2d543d20SAndroid Build Coastguard Worker
1064*2d543d20SAndroid Build Coastguard Worker sub = selabel_sub_key(data, key);
1065*2d543d20SAndroid Build Coastguard Worker if (sub)
1066*2d543d20SAndroid Build Coastguard Worker key = sub;
1067*2d543d20SAndroid Build Coastguard Worker
1068*2d543d20SAndroid Build Coastguard Worker file_stem = find_stem_from_file(data, key);
1069*2d543d20SAndroid Build Coastguard Worker mode &= S_IFMT;
1070*2d543d20SAndroid Build Coastguard Worker
1071*2d543d20SAndroid Build Coastguard Worker /*
1072*2d543d20SAndroid Build Coastguard Worker * Check for matching specifications in reverse order, so that
1073*2d543d20SAndroid Build Coastguard Worker * the last matching specification is used.
1074*2d543d20SAndroid Build Coastguard Worker */
1075*2d543d20SAndroid Build Coastguard Worker for (i = data->nspec - 1; i >= 0; i--) {
1076*2d543d20SAndroid Build Coastguard Worker struct spec *spec = &spec_arr[i];
1077*2d543d20SAndroid Build Coastguard Worker /* if the spec in question matches no stem or has the same
1078*2d543d20SAndroid Build Coastguard Worker * stem as the file AND if the spec in question has no mode
1079*2d543d20SAndroid Build Coastguard Worker * specified or if the mode matches the file mode then we do
1080*2d543d20SAndroid Build Coastguard Worker * a regex check */
1081*2d543d20SAndroid Build Coastguard Worker bool stem_matches = spec->stem_id == -1 || spec->stem_id == file_stem;
1082*2d543d20SAndroid Build Coastguard Worker // Don't check the stem if we want to find partial matches.
1083*2d543d20SAndroid Build Coastguard Worker // Otherwise the case "/abc/efg/(/.*)?" will be considered
1084*2d543d20SAndroid Build Coastguard Worker //a miss for "/abc".
1085*2d543d20SAndroid Build Coastguard Worker if ((partial || stem_matches) &&
1086*2d543d20SAndroid Build Coastguard Worker (!mode || !spec->mode || mode == spec->mode)) {
1087*2d543d20SAndroid Build Coastguard Worker if (compile_regex(spec, NULL) < 0)
1088*2d543d20SAndroid Build Coastguard Worker goto finish;
1089*2d543d20SAndroid Build Coastguard Worker rc = regex_match(spec->regex, key, partial);
1090*2d543d20SAndroid Build Coastguard Worker if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) {
1091*2d543d20SAndroid Build Coastguard Worker if (rc == REGEX_MATCH) {
1092*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
1093*2d543d20SAndroid Build Coastguard Worker __atomic_store_n(&spec->any_matches,
1094*2d543d20SAndroid Build Coastguard Worker true, __ATOMIC_RELAXED);
1095*2d543d20SAndroid Build Coastguard Worker #else
1096*2d543d20SAndroid Build Coastguard Worker #error "Please use a compiler that supports __atomic builtins"
1097*2d543d20SAndroid Build Coastguard Worker #endif
1098*2d543d20SAndroid Build Coastguard Worker }
1099*2d543d20SAndroid Build Coastguard Worker
1100*2d543d20SAndroid Build Coastguard Worker if (strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
1101*2d543d20SAndroid Build Coastguard Worker errno = ENOENT;
1102*2d543d20SAndroid Build Coastguard Worker goto finish;
1103*2d543d20SAndroid Build Coastguard Worker }
1104*2d543d20SAndroid Build Coastguard Worker
1105*2d543d20SAndroid Build Coastguard Worker if (match_count) {
1106*2d543d20SAndroid Build Coastguard Worker result[*match_count] = spec;
1107*2d543d20SAndroid Build Coastguard Worker *match_count += 1;
1108*2d543d20SAndroid Build Coastguard Worker // Continue to find all the matches.
1109*2d543d20SAndroid Build Coastguard Worker continue;
1110*2d543d20SAndroid Build Coastguard Worker }
1111*2d543d20SAndroid Build Coastguard Worker result[0] = spec;
1112*2d543d20SAndroid Build Coastguard Worker break;
1113*2d543d20SAndroid Build Coastguard Worker }
1114*2d543d20SAndroid Build Coastguard Worker
1115*2d543d20SAndroid Build Coastguard Worker if (rc == REGEX_NO_MATCH)
1116*2d543d20SAndroid Build Coastguard Worker continue;
1117*2d543d20SAndroid Build Coastguard Worker
1118*2d543d20SAndroid Build Coastguard Worker errno = ENOENT;
1119*2d543d20SAndroid Build Coastguard Worker /* else it's an error */
1120*2d543d20SAndroid Build Coastguard Worker goto finish;
1121*2d543d20SAndroid Build Coastguard Worker }
1122*2d543d20SAndroid Build Coastguard Worker }
1123*2d543d20SAndroid Build Coastguard Worker if (!result[0])
1124*2d543d20SAndroid Build Coastguard Worker errno = ENOENT;
1125*2d543d20SAndroid Build Coastguard Worker
1126*2d543d20SAndroid Build Coastguard Worker finish:
1127*2d543d20SAndroid Build Coastguard Worker free(clean_key);
1128*2d543d20SAndroid Build Coastguard Worker free(sub);
1129*2d543d20SAndroid Build Coastguard Worker if (result && !result[0]) {
1130*2d543d20SAndroid Build Coastguard Worker free(result);
1131*2d543d20SAndroid Build Coastguard Worker result = NULL;
1132*2d543d20SAndroid Build Coastguard Worker }
1133*2d543d20SAndroid Build Coastguard Worker return result;
1134*2d543d20SAndroid Build Coastguard Worker }
1135*2d543d20SAndroid Build Coastguard Worker
lookup_common(struct selabel_handle * rec,const char * key,int type,bool partial)1136*2d543d20SAndroid Build Coastguard Worker static struct spec *lookup_common(struct selabel_handle *rec,
1137*2d543d20SAndroid Build Coastguard Worker const char *key,
1138*2d543d20SAndroid Build Coastguard Worker int type,
1139*2d543d20SAndroid Build Coastguard Worker bool partial) {
1140*2d543d20SAndroid Build Coastguard Worker struct spec **matches = lookup_all(rec, key, type, partial, NULL);
1141*2d543d20SAndroid Build Coastguard Worker if (!matches) {
1142*2d543d20SAndroid Build Coastguard Worker return NULL;
1143*2d543d20SAndroid Build Coastguard Worker }
1144*2d543d20SAndroid Build Coastguard Worker struct spec *result = matches[0];
1145*2d543d20SAndroid Build Coastguard Worker free(matches);
1146*2d543d20SAndroid Build Coastguard Worker return result;
1147*2d543d20SAndroid Build Coastguard Worker }
1148*2d543d20SAndroid Build Coastguard Worker
1149*2d543d20SAndroid Build Coastguard Worker /*
1150*2d543d20SAndroid Build Coastguard Worker * Returns true if the digest of all partial matched contexts is the same as
1151*2d543d20SAndroid Build Coastguard Worker * the one saved by setxattr, otherwise returns false. The length of the SHA1
1152*2d543d20SAndroid Build Coastguard Worker * digest will always be returned. The caller must free any returned digests.
1153*2d543d20SAndroid Build Coastguard Worker */
get_digests_all_partial_matches(struct selabel_handle * rec,const char * pathname,uint8_t ** calculated_digest,uint8_t ** xattr_digest,size_t * digest_len)1154*2d543d20SAndroid Build Coastguard Worker static bool get_digests_all_partial_matches(struct selabel_handle *rec,
1155*2d543d20SAndroid Build Coastguard Worker const char *pathname,
1156*2d543d20SAndroid Build Coastguard Worker uint8_t **calculated_digest,
1157*2d543d20SAndroid Build Coastguard Worker uint8_t **xattr_digest,
1158*2d543d20SAndroid Build Coastguard Worker size_t *digest_len)
1159*2d543d20SAndroid Build Coastguard Worker {
1160*2d543d20SAndroid Build Coastguard Worker uint8_t read_digest[SHA1_HASH_SIZE];
1161*2d543d20SAndroid Build Coastguard Worker ssize_t read_size = getxattr(pathname, RESTORECON_PARTIAL_MATCH_DIGEST,
1162*2d543d20SAndroid Build Coastguard Worker read_digest, SHA1_HASH_SIZE
1163*2d543d20SAndroid Build Coastguard Worker #ifdef __APPLE__
1164*2d543d20SAndroid Build Coastguard Worker , 0, 0
1165*2d543d20SAndroid Build Coastguard Worker #endif /* __APPLE __ */
1166*2d543d20SAndroid Build Coastguard Worker );
1167*2d543d20SAndroid Build Coastguard Worker uint8_t hash_digest[SHA1_HASH_SIZE];
1168*2d543d20SAndroid Build Coastguard Worker bool status = selabel_hash_all_partial_matches(rec, pathname,
1169*2d543d20SAndroid Build Coastguard Worker hash_digest);
1170*2d543d20SAndroid Build Coastguard Worker
1171*2d543d20SAndroid Build Coastguard Worker *xattr_digest = NULL;
1172*2d543d20SAndroid Build Coastguard Worker *calculated_digest = NULL;
1173*2d543d20SAndroid Build Coastguard Worker *digest_len = SHA1_HASH_SIZE;
1174*2d543d20SAndroid Build Coastguard Worker
1175*2d543d20SAndroid Build Coastguard Worker if (read_size == SHA1_HASH_SIZE) {
1176*2d543d20SAndroid Build Coastguard Worker *xattr_digest = calloc(1, SHA1_HASH_SIZE + 1);
1177*2d543d20SAndroid Build Coastguard Worker if (!*xattr_digest)
1178*2d543d20SAndroid Build Coastguard Worker goto oom;
1179*2d543d20SAndroid Build Coastguard Worker
1180*2d543d20SAndroid Build Coastguard Worker memcpy(*xattr_digest, read_digest, SHA1_HASH_SIZE);
1181*2d543d20SAndroid Build Coastguard Worker }
1182*2d543d20SAndroid Build Coastguard Worker
1183*2d543d20SAndroid Build Coastguard Worker if (status) {
1184*2d543d20SAndroid Build Coastguard Worker *calculated_digest = calloc(1, SHA1_HASH_SIZE + 1);
1185*2d543d20SAndroid Build Coastguard Worker if (!*calculated_digest)
1186*2d543d20SAndroid Build Coastguard Worker goto oom;
1187*2d543d20SAndroid Build Coastguard Worker
1188*2d543d20SAndroid Build Coastguard Worker memcpy(*calculated_digest, hash_digest, SHA1_HASH_SIZE);
1189*2d543d20SAndroid Build Coastguard Worker }
1190*2d543d20SAndroid Build Coastguard Worker
1191*2d543d20SAndroid Build Coastguard Worker if (status && read_size == SHA1_HASH_SIZE &&
1192*2d543d20SAndroid Build Coastguard Worker memcmp(read_digest, hash_digest, SHA1_HASH_SIZE) == 0)
1193*2d543d20SAndroid Build Coastguard Worker return true;
1194*2d543d20SAndroid Build Coastguard Worker
1195*2d543d20SAndroid Build Coastguard Worker return false;
1196*2d543d20SAndroid Build Coastguard Worker
1197*2d543d20SAndroid Build Coastguard Worker oom:
1198*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "SELinux: %s: Out of memory\n", __func__);
1199*2d543d20SAndroid Build Coastguard Worker return false;
1200*2d543d20SAndroid Build Coastguard Worker }
1201*2d543d20SAndroid Build Coastguard Worker
hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)1202*2d543d20SAndroid Build Coastguard Worker static bool hash_all_partial_matches(struct selabel_handle *rec, const char *key, uint8_t *digest)
1203*2d543d20SAndroid Build Coastguard Worker {
1204*2d543d20SAndroid Build Coastguard Worker assert(digest);
1205*2d543d20SAndroid Build Coastguard Worker
1206*2d543d20SAndroid Build Coastguard Worker size_t total_matches;
1207*2d543d20SAndroid Build Coastguard Worker struct spec **matches = lookup_all(rec, key, 0, true, &total_matches);
1208*2d543d20SAndroid Build Coastguard Worker if (!matches) {
1209*2d543d20SAndroid Build Coastguard Worker return false;
1210*2d543d20SAndroid Build Coastguard Worker }
1211*2d543d20SAndroid Build Coastguard Worker
1212*2d543d20SAndroid Build Coastguard Worker Sha1Context context;
1213*2d543d20SAndroid Build Coastguard Worker Sha1Initialise(&context);
1214*2d543d20SAndroid Build Coastguard Worker size_t i;
1215*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < total_matches; i++) {
1216*2d543d20SAndroid Build Coastguard Worker char* regex_str = matches[i]->regex_str;
1217*2d543d20SAndroid Build Coastguard Worker mode_t mode = matches[i]->mode;
1218*2d543d20SAndroid Build Coastguard Worker char* ctx_raw = matches[i]->lr.ctx_raw;
1219*2d543d20SAndroid Build Coastguard Worker
1220*2d543d20SAndroid Build Coastguard Worker Sha1Update(&context, regex_str, strlen(regex_str) + 1);
1221*2d543d20SAndroid Build Coastguard Worker Sha1Update(&context, &mode, sizeof(mode_t));
1222*2d543d20SAndroid Build Coastguard Worker Sha1Update(&context, ctx_raw, strlen(ctx_raw) + 1);
1223*2d543d20SAndroid Build Coastguard Worker }
1224*2d543d20SAndroid Build Coastguard Worker
1225*2d543d20SAndroid Build Coastguard Worker SHA1_HASH sha1_hash;
1226*2d543d20SAndroid Build Coastguard Worker Sha1Finalise(&context, &sha1_hash);
1227*2d543d20SAndroid Build Coastguard Worker memcpy(digest, sha1_hash.bytes, SHA1_HASH_SIZE);
1228*2d543d20SAndroid Build Coastguard Worker
1229*2d543d20SAndroid Build Coastguard Worker free(matches);
1230*2d543d20SAndroid Build Coastguard Worker return true;
1231*2d543d20SAndroid Build Coastguard Worker }
1232*2d543d20SAndroid Build Coastguard Worker
lookup(struct selabel_handle * rec,const char * key,int type)1233*2d543d20SAndroid Build Coastguard Worker static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
1234*2d543d20SAndroid Build Coastguard Worker const char *key, int type)
1235*2d543d20SAndroid Build Coastguard Worker {
1236*2d543d20SAndroid Build Coastguard Worker struct spec *spec;
1237*2d543d20SAndroid Build Coastguard Worker
1238*2d543d20SAndroid Build Coastguard Worker spec = lookup_common(rec, key, type, false);
1239*2d543d20SAndroid Build Coastguard Worker if (spec)
1240*2d543d20SAndroid Build Coastguard Worker return &spec->lr;
1241*2d543d20SAndroid Build Coastguard Worker return NULL;
1242*2d543d20SAndroid Build Coastguard Worker }
1243*2d543d20SAndroid Build Coastguard Worker
partial_match(struct selabel_handle * rec,const char * key)1244*2d543d20SAndroid Build Coastguard Worker static bool partial_match(struct selabel_handle *rec, const char *key)
1245*2d543d20SAndroid Build Coastguard Worker {
1246*2d543d20SAndroid Build Coastguard Worker return lookup_common(rec, key, 0, true) ? true : false;
1247*2d543d20SAndroid Build Coastguard Worker }
1248*2d543d20SAndroid Build Coastguard Worker
lookup_best_match(struct selabel_handle * rec,const char * key,const char ** aliases,int type)1249*2d543d20SAndroid Build Coastguard Worker static struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec,
1250*2d543d20SAndroid Build Coastguard Worker const char *key,
1251*2d543d20SAndroid Build Coastguard Worker const char **aliases,
1252*2d543d20SAndroid Build Coastguard Worker int type)
1253*2d543d20SAndroid Build Coastguard Worker {
1254*2d543d20SAndroid Build Coastguard Worker size_t n, i;
1255*2d543d20SAndroid Build Coastguard Worker int best = -1;
1256*2d543d20SAndroid Build Coastguard Worker struct spec **specs;
1257*2d543d20SAndroid Build Coastguard Worker size_t prefix_len = 0;
1258*2d543d20SAndroid Build Coastguard Worker struct selabel_lookup_rec *lr = NULL;
1259*2d543d20SAndroid Build Coastguard Worker
1260*2d543d20SAndroid Build Coastguard Worker if (!aliases || !aliases[0])
1261*2d543d20SAndroid Build Coastguard Worker return lookup(rec, key, type);
1262*2d543d20SAndroid Build Coastguard Worker
1263*2d543d20SAndroid Build Coastguard Worker for (n = 0; aliases[n]; n++)
1264*2d543d20SAndroid Build Coastguard Worker ;
1265*2d543d20SAndroid Build Coastguard Worker
1266*2d543d20SAndroid Build Coastguard Worker specs = calloc(n+1, sizeof(struct spec *));
1267*2d543d20SAndroid Build Coastguard Worker if (!specs)
1268*2d543d20SAndroid Build Coastguard Worker return NULL;
1269*2d543d20SAndroid Build Coastguard Worker specs[0] = lookup_common(rec, key, type, false);
1270*2d543d20SAndroid Build Coastguard Worker if (specs[0]) {
1271*2d543d20SAndroid Build Coastguard Worker if (!specs[0]->hasMetaChars) {
1272*2d543d20SAndroid Build Coastguard Worker /* exact match on key */
1273*2d543d20SAndroid Build Coastguard Worker lr = &specs[0]->lr;
1274*2d543d20SAndroid Build Coastguard Worker goto out;
1275*2d543d20SAndroid Build Coastguard Worker }
1276*2d543d20SAndroid Build Coastguard Worker best = 0;
1277*2d543d20SAndroid Build Coastguard Worker prefix_len = specs[0]->prefix_len;
1278*2d543d20SAndroid Build Coastguard Worker }
1279*2d543d20SAndroid Build Coastguard Worker for (i = 1; i <= n; i++) {
1280*2d543d20SAndroid Build Coastguard Worker specs[i] = lookup_common(rec, aliases[i-1], type, false);
1281*2d543d20SAndroid Build Coastguard Worker if (specs[i]) {
1282*2d543d20SAndroid Build Coastguard Worker if (!specs[i]->hasMetaChars) {
1283*2d543d20SAndroid Build Coastguard Worker /* exact match on alias */
1284*2d543d20SAndroid Build Coastguard Worker lr = &specs[i]->lr;
1285*2d543d20SAndroid Build Coastguard Worker goto out;
1286*2d543d20SAndroid Build Coastguard Worker }
1287*2d543d20SAndroid Build Coastguard Worker if (specs[i]->prefix_len > prefix_len) {
1288*2d543d20SAndroid Build Coastguard Worker best = i;
1289*2d543d20SAndroid Build Coastguard Worker prefix_len = specs[i]->prefix_len;
1290*2d543d20SAndroid Build Coastguard Worker }
1291*2d543d20SAndroid Build Coastguard Worker }
1292*2d543d20SAndroid Build Coastguard Worker }
1293*2d543d20SAndroid Build Coastguard Worker
1294*2d543d20SAndroid Build Coastguard Worker if (best >= 0) {
1295*2d543d20SAndroid Build Coastguard Worker /* longest fixed prefix match on key or alias */
1296*2d543d20SAndroid Build Coastguard Worker lr = &specs[best]->lr;
1297*2d543d20SAndroid Build Coastguard Worker } else {
1298*2d543d20SAndroid Build Coastguard Worker errno = ENOENT;
1299*2d543d20SAndroid Build Coastguard Worker }
1300*2d543d20SAndroid Build Coastguard Worker
1301*2d543d20SAndroid Build Coastguard Worker out:
1302*2d543d20SAndroid Build Coastguard Worker free(specs);
1303*2d543d20SAndroid Build Coastguard Worker return lr;
1304*2d543d20SAndroid Build Coastguard Worker }
1305*2d543d20SAndroid Build Coastguard Worker
incomp(const struct spec * spec1,const struct spec * spec2,const char * reason,int i,int j)1306*2d543d20SAndroid Build Coastguard Worker static enum selabel_cmp_result incomp(const struct spec *spec1, const struct spec *spec2, const char *reason, int i, int j)
1307*2d543d20SAndroid Build Coastguard Worker {
1308*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_INFO,
1309*2d543d20SAndroid Build Coastguard Worker "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n",
1310*2d543d20SAndroid Build Coastguard Worker reason,
1311*2d543d20SAndroid Build Coastguard Worker i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw,
1312*2d543d20SAndroid Build Coastguard Worker j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw);
1313*2d543d20SAndroid Build Coastguard Worker return SELABEL_INCOMPARABLE;
1314*2d543d20SAndroid Build Coastguard Worker }
1315*2d543d20SAndroid Build Coastguard Worker
cmp(const struct selabel_handle * h1,const struct selabel_handle * h2)1316*2d543d20SAndroid Build Coastguard Worker static enum selabel_cmp_result cmp(const struct selabel_handle *h1,
1317*2d543d20SAndroid Build Coastguard Worker const struct selabel_handle *h2)
1318*2d543d20SAndroid Build Coastguard Worker {
1319*2d543d20SAndroid Build Coastguard Worker const struct saved_data *data1 = (const struct saved_data *)h1->data;
1320*2d543d20SAndroid Build Coastguard Worker const struct saved_data *data2 = (const struct saved_data *)h2->data;
1321*2d543d20SAndroid Build Coastguard Worker unsigned int i, nspec1 = data1->nspec, j, nspec2 = data2->nspec;
1322*2d543d20SAndroid Build Coastguard Worker const struct spec *spec_arr1 = data1->spec_arr, *spec_arr2 = data2->spec_arr;
1323*2d543d20SAndroid Build Coastguard Worker const struct stem *stem_arr1 = data1->stem_arr, *stem_arr2 = data2->stem_arr;
1324*2d543d20SAndroid Build Coastguard Worker bool skipped1 = false, skipped2 = false;
1325*2d543d20SAndroid Build Coastguard Worker
1326*2d543d20SAndroid Build Coastguard Worker i = 0;
1327*2d543d20SAndroid Build Coastguard Worker j = 0;
1328*2d543d20SAndroid Build Coastguard Worker while (i < nspec1 && j < nspec2) {
1329*2d543d20SAndroid Build Coastguard Worker const struct spec *spec1 = &spec_arr1[i];
1330*2d543d20SAndroid Build Coastguard Worker const struct spec *spec2 = &spec_arr2[j];
1331*2d543d20SAndroid Build Coastguard Worker
1332*2d543d20SAndroid Build Coastguard Worker /*
1333*2d543d20SAndroid Build Coastguard Worker * Because sort_specs() moves exact pathnames to the
1334*2d543d20SAndroid Build Coastguard Worker * end, we might need to skip over additional regex
1335*2d543d20SAndroid Build Coastguard Worker * entries that only exist in one of the configurations.
1336*2d543d20SAndroid Build Coastguard Worker */
1337*2d543d20SAndroid Build Coastguard Worker if (!spec1->hasMetaChars && spec2->hasMetaChars) {
1338*2d543d20SAndroid Build Coastguard Worker j++;
1339*2d543d20SAndroid Build Coastguard Worker skipped2 = true;
1340*2d543d20SAndroid Build Coastguard Worker continue;
1341*2d543d20SAndroid Build Coastguard Worker }
1342*2d543d20SAndroid Build Coastguard Worker
1343*2d543d20SAndroid Build Coastguard Worker if (spec1->hasMetaChars && !spec2->hasMetaChars) {
1344*2d543d20SAndroid Build Coastguard Worker i++;
1345*2d543d20SAndroid Build Coastguard Worker skipped1 = true;
1346*2d543d20SAndroid Build Coastguard Worker continue;
1347*2d543d20SAndroid Build Coastguard Worker }
1348*2d543d20SAndroid Build Coastguard Worker
1349*2d543d20SAndroid Build Coastguard Worker if (spec1->regex && spec2->regex) {
1350*2d543d20SAndroid Build Coastguard Worker if (regex_cmp(spec1->regex, spec2->regex) == SELABEL_INCOMPARABLE){
1351*2d543d20SAndroid Build Coastguard Worker return incomp(spec1, spec2, "regex", i, j);
1352*2d543d20SAndroid Build Coastguard Worker }
1353*2d543d20SAndroid Build Coastguard Worker } else {
1354*2d543d20SAndroid Build Coastguard Worker if (strcmp(spec1->regex_str, spec2->regex_str))
1355*2d543d20SAndroid Build Coastguard Worker return incomp(spec1, spec2, "regex_str", i, j);
1356*2d543d20SAndroid Build Coastguard Worker }
1357*2d543d20SAndroid Build Coastguard Worker
1358*2d543d20SAndroid Build Coastguard Worker if (spec1->mode != spec2->mode)
1359*2d543d20SAndroid Build Coastguard Worker return incomp(spec1, spec2, "mode", i, j);
1360*2d543d20SAndroid Build Coastguard Worker
1361*2d543d20SAndroid Build Coastguard Worker if (spec1->stem_id == -1 && spec2->stem_id != -1)
1362*2d543d20SAndroid Build Coastguard Worker return incomp(spec1, spec2, "stem_id", i, j);
1363*2d543d20SAndroid Build Coastguard Worker if (spec2->stem_id == -1 && spec1->stem_id != -1)
1364*2d543d20SAndroid Build Coastguard Worker return incomp(spec1, spec2, "stem_id", i, j);
1365*2d543d20SAndroid Build Coastguard Worker if (spec1->stem_id != -1 && spec2->stem_id != -1) {
1366*2d543d20SAndroid Build Coastguard Worker const struct stem *stem1 = &stem_arr1[spec1->stem_id];
1367*2d543d20SAndroid Build Coastguard Worker const struct stem *stem2 = &stem_arr2[spec2->stem_id];
1368*2d543d20SAndroid Build Coastguard Worker if (stem1->len != stem2->len ||
1369*2d543d20SAndroid Build Coastguard Worker strncmp(stem1->buf, stem2->buf, stem1->len))
1370*2d543d20SAndroid Build Coastguard Worker return incomp(spec1, spec2, "stem", i, j);
1371*2d543d20SAndroid Build Coastguard Worker }
1372*2d543d20SAndroid Build Coastguard Worker
1373*2d543d20SAndroid Build Coastguard Worker if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw))
1374*2d543d20SAndroid Build Coastguard Worker return incomp(spec1, spec2, "ctx_raw", i, j);
1375*2d543d20SAndroid Build Coastguard Worker
1376*2d543d20SAndroid Build Coastguard Worker i++;
1377*2d543d20SAndroid Build Coastguard Worker j++;
1378*2d543d20SAndroid Build Coastguard Worker }
1379*2d543d20SAndroid Build Coastguard Worker
1380*2d543d20SAndroid Build Coastguard Worker if ((skipped1 || i < nspec1) && !skipped2)
1381*2d543d20SAndroid Build Coastguard Worker return SELABEL_SUPERSET;
1382*2d543d20SAndroid Build Coastguard Worker if ((skipped2 || j < nspec2) && !skipped1)
1383*2d543d20SAndroid Build Coastguard Worker return SELABEL_SUBSET;
1384*2d543d20SAndroid Build Coastguard Worker if (skipped1 && skipped2)
1385*2d543d20SAndroid Build Coastguard Worker return SELABEL_INCOMPARABLE;
1386*2d543d20SAndroid Build Coastguard Worker return SELABEL_EQUAL;
1387*2d543d20SAndroid Build Coastguard Worker }
1388*2d543d20SAndroid Build Coastguard Worker
1389*2d543d20SAndroid Build Coastguard Worker
stats(struct selabel_handle * rec)1390*2d543d20SAndroid Build Coastguard Worker static void stats(struct selabel_handle *rec)
1391*2d543d20SAndroid Build Coastguard Worker {
1392*2d543d20SAndroid Build Coastguard Worker struct saved_data *data = (struct saved_data *)rec->data;
1393*2d543d20SAndroid Build Coastguard Worker unsigned int i, nspec = data->nspec;
1394*2d543d20SAndroid Build Coastguard Worker struct spec *spec_arr = data->spec_arr;
1395*2d543d20SAndroid Build Coastguard Worker bool any_matches;
1396*2d543d20SAndroid Build Coastguard Worker
1397*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < nspec; i++) {
1398*2d543d20SAndroid Build Coastguard Worker #ifdef __ATOMIC_RELAXED
1399*2d543d20SAndroid Build Coastguard Worker any_matches = __atomic_load_n(&spec_arr[i].any_matches, __ATOMIC_RELAXED);
1400*2d543d20SAndroid Build Coastguard Worker #else
1401*2d543d20SAndroid Build Coastguard Worker #error "Please use a compiler that supports __atomic builtins"
1402*2d543d20SAndroid Build Coastguard Worker #endif
1403*2d543d20SAndroid Build Coastguard Worker if (!any_matches) {
1404*2d543d20SAndroid Build Coastguard Worker if (spec_arr[i].type_str) {
1405*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_WARNING,
1406*2d543d20SAndroid Build Coastguard Worker "Warning! No matches for (%s, %s, %s)\n",
1407*2d543d20SAndroid Build Coastguard Worker spec_arr[i].regex_str,
1408*2d543d20SAndroid Build Coastguard Worker spec_arr[i].type_str,
1409*2d543d20SAndroid Build Coastguard Worker spec_arr[i].lr.ctx_raw);
1410*2d543d20SAndroid Build Coastguard Worker } else {
1411*2d543d20SAndroid Build Coastguard Worker COMPAT_LOG(SELINUX_WARNING,
1412*2d543d20SAndroid Build Coastguard Worker "Warning! No matches for (%s, %s)\n",
1413*2d543d20SAndroid Build Coastguard Worker spec_arr[i].regex_str,
1414*2d543d20SAndroid Build Coastguard Worker spec_arr[i].lr.ctx_raw);
1415*2d543d20SAndroid Build Coastguard Worker }
1416*2d543d20SAndroid Build Coastguard Worker }
1417*2d543d20SAndroid Build Coastguard Worker }
1418*2d543d20SAndroid Build Coastguard Worker }
1419*2d543d20SAndroid Build Coastguard Worker
selabel_file_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)1420*2d543d20SAndroid Build Coastguard Worker int selabel_file_init(struct selabel_handle *rec,
1421*2d543d20SAndroid Build Coastguard Worker const struct selinux_opt *opts,
1422*2d543d20SAndroid Build Coastguard Worker unsigned nopts)
1423*2d543d20SAndroid Build Coastguard Worker {
1424*2d543d20SAndroid Build Coastguard Worker struct saved_data *data;
1425*2d543d20SAndroid Build Coastguard Worker
1426*2d543d20SAndroid Build Coastguard Worker data = (struct saved_data *)calloc(1, sizeof(*data));
1427*2d543d20SAndroid Build Coastguard Worker if (!data)
1428*2d543d20SAndroid Build Coastguard Worker return -1;
1429*2d543d20SAndroid Build Coastguard Worker
1430*2d543d20SAndroid Build Coastguard Worker rec->data = data;
1431*2d543d20SAndroid Build Coastguard Worker rec->func_close = &closef;
1432*2d543d20SAndroid Build Coastguard Worker rec->func_stats = &stats;
1433*2d543d20SAndroid Build Coastguard Worker rec->func_lookup = &lookup;
1434*2d543d20SAndroid Build Coastguard Worker rec->func_partial_match = &partial_match;
1435*2d543d20SAndroid Build Coastguard Worker rec->func_get_digests_all_partial_matches =
1436*2d543d20SAndroid Build Coastguard Worker &get_digests_all_partial_matches;
1437*2d543d20SAndroid Build Coastguard Worker rec->func_hash_all_partial_matches = &hash_all_partial_matches;
1438*2d543d20SAndroid Build Coastguard Worker rec->func_lookup_best_match = &lookup_best_match;
1439*2d543d20SAndroid Build Coastguard Worker rec->func_cmp = &cmp;
1440*2d543d20SAndroid Build Coastguard Worker
1441*2d543d20SAndroid Build Coastguard Worker return init(rec, opts, nopts);
1442*2d543d20SAndroid Build Coastguard Worker }
1443