1 /*
2 * Generalized labeling frontend for userspace object managers.
3 *
4 * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
5 */
6
7 #include <sys/types.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <selinux/selinux.h>
15 #include "callbacks.h"
16 #include "label_internal.h"
17
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
19
20 #ifdef NO_MEDIA_BACKEND
21 #define CONFIG_MEDIA_BACKEND(fnptr) NULL
22 #else
23 #define CONFIG_MEDIA_BACKEND(fnptr) &fnptr
24 #endif
25
26 #ifdef NO_X_BACKEND
27 #define CONFIG_X_BACKEND(fnptr) NULL
28 #else
29 #define CONFIG_X_BACKEND(fnptr) &fnptr
30 #endif
31
32 #ifdef NO_DB_BACKEND
33 #define CONFIG_DB_BACKEND(fnptr) NULL
34 #else
35 #define CONFIG_DB_BACKEND(fnptr) &fnptr
36 #endif
37
38 #ifdef NO_ANDROID_BACKEND
39 #define CONFIG_ANDROID_BACKEND(fnptr) NULL
40 #else
41 #define CONFIG_ANDROID_BACKEND(fnptr) (&(fnptr))
42 #endif
43
44 typedef int (*selabel_initfunc)(struct selabel_handle *rec,
45 const struct selinux_opt *opts,
46 unsigned nopts);
47
48 static selabel_initfunc initfuncs[] = {
49 &selabel_file_init,
50 CONFIG_MEDIA_BACKEND(selabel_media_init),
51 CONFIG_X_BACKEND(selabel_x_init),
52 CONFIG_DB_BACKEND(selabel_db_init),
53 CONFIG_ANDROID_BACKEND(selabel_property_init),
54 CONFIG_ANDROID_BACKEND(selabel_service_init),
55 };
56
selabel_is_digest_set(const struct selinux_opt * opts,unsigned n,struct selabel_digest * entry)57 static inline struct selabel_digest *selabel_is_digest_set
58 (const struct selinux_opt *opts,
59 unsigned n,
60 struct selabel_digest *entry)
61 {
62 struct selabel_digest *digest = NULL;
63
64 while (n--) {
65 if (opts[n].type == SELABEL_OPT_DIGEST &&
66 opts[n].value == (char *)1) {
67 digest = calloc(1, sizeof(*digest));
68 if (!digest)
69 goto err;
70
71 digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1);
72 if (!digest->digest)
73 goto err;
74
75 digest->specfile_list = calloc(DIGEST_FILES_MAX,
76 sizeof(char *));
77 if (!digest->specfile_list)
78 goto err;
79
80 entry = digest;
81 return entry;
82 }
83 }
84 return NULL;
85
86 err:
87 if (digest) {
88 free(digest->digest);
89 free(digest->specfile_list);
90 free(digest);
91 }
92 return NULL;
93 }
94
selabel_digest_fini(struct selabel_digest * ptr)95 static void selabel_digest_fini(struct selabel_digest *ptr)
96 {
97 int i;
98
99 free(ptr->digest);
100 free(ptr->hashbuf);
101
102 if (ptr->specfile_list) {
103 for (i = 0; ptr->specfile_list[i]; i++)
104 free(ptr->specfile_list[i]);
105 free(ptr->specfile_list);
106 }
107 free(ptr);
108 }
109
110 /*
111 * Validation functions
112 */
113
selabel_is_validate_set(const struct selinux_opt * opts,unsigned n)114 static inline int selabel_is_validate_set(const struct selinux_opt *opts,
115 unsigned n)
116 {
117 while (n--)
118 if (opts[n].type == SELABEL_OPT_VALIDATE)
119 return !!opts[n].value;
120
121 return 0;
122 }
123
selabel_validate(struct selabel_handle * rec,struct selabel_lookup_rec * contexts)124 int selabel_validate(struct selabel_handle *rec,
125 struct selabel_lookup_rec *contexts)
126 {
127 int rc = 0;
128
129 if (!rec->validating || contexts->validated)
130 goto out;
131
132 rc = selinux_validate(&contexts->ctx_raw);
133 if (rc < 0)
134 goto out;
135
136 contexts->validated = 1;
137 out:
138 return rc;
139 }
140
141 /* Public API helpers */
selabel_fini(struct selabel_handle * rec,struct selabel_lookup_rec * lr,int translating)142 static int selabel_fini(struct selabel_handle *rec,
143 struct selabel_lookup_rec *lr,
144 int translating)
145 {
146 if (compat_validate(rec, lr, rec->spec_file, lr->lineno))
147 return -1;
148
149 if (translating && !lr->ctx_trans &&
150 selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
151 return -1;
152
153 return 0;
154 }
155
156 static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle * rec,int translating,const char * key,int type)157 selabel_lookup_common(struct selabel_handle *rec, int translating,
158 const char *key, int type)
159 {
160 struct selabel_lookup_rec *lr;
161
162 if (key == NULL) {
163 errno = EINVAL;
164 return NULL;
165 }
166
167 lr = rec->func_lookup(rec, key, type);
168 if (!lr)
169 return NULL;
170
171 if (selabel_fini(rec, lr, translating))
172 return NULL;
173
174 return lr;
175 }
176
177 static struct selabel_lookup_rec *
selabel_lookup_bm_common(struct selabel_handle * rec,int translating,const char * key,int type,const char ** aliases)178 selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
179 const char *key, int type, const char **aliases)
180 {
181 struct selabel_lookup_rec *lr;
182
183 if (key == NULL) {
184 errno = EINVAL;
185 return NULL;
186 }
187
188 lr = rec->func_lookup_best_match(rec, key, aliases, type);
189 if (!lr)
190 return NULL;
191
192 if (selabel_fini(rec, lr, translating))
193 return NULL;
194
195 return lr;
196 }
197
198 /*
199 * Public API
200 */
201
selabel_open(unsigned int backend,const struct selinux_opt * opts,unsigned nopts)202 struct selabel_handle *selabel_open(unsigned int backend,
203 const struct selinux_opt *opts,
204 unsigned nopts)
205 {
206 struct selabel_handle *rec = NULL;
207
208 if (backend >= ARRAY_SIZE(initfuncs)) {
209 errno = EINVAL;
210 goto out;
211 }
212
213 if (!initfuncs[backend]) {
214 errno = ENOTSUP;
215 goto out;
216 }
217
218 rec = (struct selabel_handle *)malloc(sizeof(*rec));
219 if (!rec)
220 goto out;
221
222 memset(rec, 0, sizeof(*rec));
223 rec->backend = backend;
224 rec->validating = selabel_is_validate_set(opts, nopts);
225
226 rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
227
228 if ((*initfuncs[backend])(rec, opts, nopts)) {
229 free(rec->spec_file);
230 free(rec);
231 rec = NULL;
232 }
233
234 out:
235 return rec;
236 }
237
selabel_lookup(struct selabel_handle * rec,char ** con,const char * key,int type)238 int selabel_lookup(struct selabel_handle *rec, char **con,
239 const char *key, int type)
240 {
241 struct selabel_lookup_rec *lr;
242
243 lr = selabel_lookup_common(rec, 1, key, type);
244 if (!lr)
245 return -1;
246
247 *con = strdup(lr->ctx_trans);
248 return *con ? 0 : -1;
249 }
250
selabel_lookup_raw(struct selabel_handle * rec,char ** con,const char * key,int type)251 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
252 const char *key, int type)
253 {
254 struct selabel_lookup_rec *lr;
255
256 lr = selabel_lookup_common(rec, 0, key, type);
257 if (!lr)
258 return -1;
259
260 *con = strdup(lr->ctx_raw);
261 return *con ? 0 : -1;
262 }
263
selabel_partial_match(struct selabel_handle * rec,const char * key)264 bool selabel_partial_match(struct selabel_handle *rec, const char *key)
265 {
266 if (!rec->func_partial_match) {
267 /*
268 * If the label backend does not support partial matching,
269 * then assume a match is possible.
270 */
271 return true;
272 }
273
274 return rec->func_partial_match(rec, key);
275 }
276
selabel_get_digests_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t ** calculated_digest,uint8_t ** xattr_digest,size_t * digest_len)277 bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
278 const char *key,
279 uint8_t **calculated_digest,
280 uint8_t **xattr_digest,
281 size_t *digest_len)
282 {
283 if (!rec->func_get_digests_all_partial_matches)
284 return false;
285
286 return rec->func_get_digests_all_partial_matches(rec, key,
287 calculated_digest,
288 xattr_digest,
289 digest_len);
290 }
291
selabel_hash_all_partial_matches(struct selabel_handle * rec,const char * key,uint8_t * digest)292 bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
293 const char *key, uint8_t *digest) {
294 if (!rec->func_hash_all_partial_matches) {
295 return false;
296 }
297
298 return rec->func_hash_all_partial_matches(rec, key, digest);
299 }
300
selabel_lookup_best_match(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)301 int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
302 const char *key, const char **aliases, int type)
303 {
304 struct selabel_lookup_rec *lr;
305
306 if (!rec->func_lookup_best_match) {
307 errno = ENOTSUP;
308 return -1;
309 }
310
311 lr = selabel_lookup_bm_common(rec, 1, key, type, aliases);
312 if (!lr)
313 return -1;
314
315 *con = strdup(lr->ctx_trans);
316 return *con ? 0 : -1;
317 }
318
selabel_lookup_best_match_raw(struct selabel_handle * rec,char ** con,const char * key,const char ** aliases,int type)319 int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
320 const char *key, const char **aliases, int type)
321 {
322 struct selabel_lookup_rec *lr;
323
324 if (!rec->func_lookup_best_match) {
325 errno = ENOTSUP;
326 return -1;
327 }
328
329 lr = selabel_lookup_bm_common(rec, 0, key, type, aliases);
330 if (!lr)
331 return -1;
332
333 *con = strdup(lr->ctx_raw);
334 return *con ? 0 : -1;
335 }
336
selabel_cmp(struct selabel_handle * h1,struct selabel_handle * h2)337 enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
338 struct selabel_handle *h2)
339 {
340 if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
341 return SELABEL_INCOMPARABLE;
342
343 return h1->func_cmp(h1, h2);
344 }
345
selabel_digest(struct selabel_handle * rec,unsigned char ** digest,size_t * digest_len,char *** specfiles,size_t * num_specfiles)346 int selabel_digest(struct selabel_handle *rec,
347 unsigned char **digest, size_t *digest_len,
348 char ***specfiles, size_t *num_specfiles)
349 {
350 if (!rec->digest) {
351 errno = EINVAL;
352 return -1;
353 }
354
355 *digest = rec->digest->digest;
356 *digest_len = DIGEST_SPECFILE_SIZE;
357 *specfiles = rec->digest->specfile_list;
358 *num_specfiles = rec->digest->specfile_cnt;
359 return 0;
360 }
361
selabel_close(struct selabel_handle * rec)362 void selabel_close(struct selabel_handle *rec)
363 {
364 if (rec->digest)
365 selabel_digest_fini(rec->digest);
366 rec->func_close(rec);
367 free(rec->spec_file);
368 free(rec);
369 }
370
selabel_stats(struct selabel_handle * rec)371 void selabel_stats(struct selabel_handle *rec)
372 {
373 rec->func_stats(rec);
374 }
375