blob: eac6e36479d577c4fa1f31b8ad8a7e60260db4f6 [file] [log] [blame]
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001/*
2 * Generalized labeling frontend for userspace object managers.
3 *
4 * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
5 */
6
7#include <sys/types.h>
Daniel J Walsh20271d92009-06-04 17:15:31 -04008#include <ctype.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -04009#include <errno.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
Richard Hainese40bbea2015-09-30 16:29:20 +010013#include <sys/stat.h>
Daniel J Walsh20271d92009-06-04 17:15:31 -040014#include <selinux/selinux.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040015#include "callbacks.h"
16#include "label_internal.h"
17
18#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
19
Sandeep Patil73c80592017-05-03 07:05:46 -070020#ifdef NO_FILE_BACKEND
21#define CONFIG_FILE_BACKEND(fnptr) NULL
22#else
23#define CONFIG_FILE_BACKEND(fnptr) &fnptr
24#endif
25
William Roberts84d07eb2016-09-26 10:33:38 -070026#ifdef NO_MEDIA_BACKEND
27#define CONFIG_MEDIA_BACKEND(fnptr) NULL
28#else
29#define CONFIG_MEDIA_BACKEND(fnptr) &fnptr
30#endif
31
32#ifdef NO_X_BACKEND
33#define CONFIG_X_BACKEND(fnptr) NULL
34#else
35#define CONFIG_X_BACKEND(fnptr) &fnptr
36#endif
37
38#ifdef NO_DB_BACKEND
39#define CONFIG_DB_BACKEND(fnptr) NULL
40#else
41#define CONFIG_DB_BACKEND(fnptr) &fnptr
42#endif
43
Janis Danisevskise029ace2016-09-29 12:39:19 +010044#ifdef NO_ANDROID_BACKEND
45#define CONFIG_ANDROID_BACKEND(fnptr) NULL
46#else
47#define CONFIG_ANDROID_BACKEND(fnptr) (&(fnptr))
48#endif
49
Joshua Brindle13cd4c82008-08-19 15:30:36 -040050typedef int (*selabel_initfunc)(struct selabel_handle *rec,
Richard Hainesf2cd2f82015-07-10 16:53:54 +010051 const struct selinux_opt *opts,
52 unsigned nopts);
Joshua Brindle13cd4c82008-08-19 15:30:36 -040053
54static selabel_initfunc initfuncs[] = {
Sandeep Patil73c80592017-05-03 07:05:46 -070055 CONFIG_FILE_BACKEND(selabel_file_init),
William Roberts84d07eb2016-09-26 10:33:38 -070056 CONFIG_MEDIA_BACKEND(selabel_media_init),
57 CONFIG_X_BACKEND(selabel_x_init),
58 CONFIG_DB_BACKEND(selabel_db_init),
Janis Danisevskise029ace2016-09-29 12:39:19 +010059 CONFIG_ANDROID_BACKEND(selabel_property_init),
60 CONFIG_ANDROID_BACKEND(selabel_service_init),
Joshua Brindle13cd4c82008-08-19 15:30:36 -040061};
62
Richard Hainese40bbea2015-09-30 16:29:20 +010063static inline struct selabel_digest *selabel_is_digest_set
64 (const struct selinux_opt *opts,
65 unsigned n,
66 struct selabel_digest *entry)
67{
68 struct selabel_digest *digest = NULL;
69
70 while (n--) {
71 if (opts[n].type == SELABEL_OPT_DIGEST &&
72 opts[n].value == (char *)1) {
73 digest = calloc(1, sizeof(*digest));
74 if (!digest)
75 goto err;
76
77 digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1);
78 if (!digest->digest)
79 goto err;
80
81 digest->specfile_list = calloc(DIGEST_FILES_MAX,
82 sizeof(char *));
83 if (!digest->specfile_list)
84 goto err;
85
86 entry = digest;
87 return entry;
88 }
89 }
90 return NULL;
91
92err:
Nicolas Iooss55b5b7a2017-04-07 22:44:26 +020093 if (digest) {
94 free(digest->digest);
95 free(digest->specfile_list);
96 free(digest);
97 }
Richard Hainese40bbea2015-09-30 16:29:20 +010098 return NULL;
99}
100
101static void selabel_digest_fini(struct selabel_digest *ptr)
102{
103 int i;
104
105 free(ptr->digest);
106 free(ptr->hashbuf);
107
108 if (ptr->specfile_list) {
109 for (i = 0; ptr->specfile_list[i]; i++)
110 free(ptr->specfile_list[i]);
111 free(ptr->specfile_list);
112 }
113 free(ptr);
114}
115
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400116/*
117 * Validation functions
118 */
119
Richard Hainesf2cd2f82015-07-10 16:53:54 +0100120static inline int selabel_is_validate_set(const struct selinux_opt *opts,
121 unsigned n)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400122{
123 while (n--)
124 if (opts[n].type == SELABEL_OPT_VALIDATE)
125 return !!opts[n].value;
126
127 return 0;
128}
129
130int selabel_validate(struct selabel_handle *rec,
131 struct selabel_lookup_rec *contexts)
132{
133 int rc = 0;
134
135 if (!rec->validating || contexts->validated)
136 goto out;
137
138 rc = selinux_validate(&contexts->ctx_raw);
139 if (rc < 0)
140 goto out;
141
142 contexts->validated = 1;
143out:
144 return rc;
145}
146
Richard Hainese7f970f2015-05-06 16:11:03 +0100147/* Public API helpers */
Richard Hainese7f970f2015-05-06 16:11:03 +0100148static int selabel_fini(struct selabel_handle *rec,
149 struct selabel_lookup_rec *lr,
150 int translating)
151{
dcashman50400d32016-12-12 10:13:27 -0800152 char *path = NULL;
153
154 if (rec->spec_files)
155 path = rec->spec_files[0];
Nick Kralevich4d254112018-08-06 13:55:59 -0700156 if (compat_validate(rec, lr, path, lr->lineno))
Richard Hainese7f970f2015-05-06 16:11:03 +0100157 return -1;
158
159 if (translating && !lr->ctx_trans &&
160 selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
161 return -1;
162
163 return 0;
164}
165
166static struct selabel_lookup_rec *
167selabel_lookup_common(struct selabel_handle *rec, int translating,
168 const char *key, int type)
169{
170 struct selabel_lookup_rec *lr;
Richard Hainese7f970f2015-05-06 16:11:03 +0100171
172 if (key == NULL) {
173 errno = EINVAL;
174 return NULL;
175 }
176
Stephen Smalley31f532a2017-06-01 15:26:53 -0400177 lr = rec->func_lookup(rec, key, type);
Richard Hainese7f970f2015-05-06 16:11:03 +0100178 if (!lr)
179 return NULL;
180
181 if (selabel_fini(rec, lr, translating))
182 return NULL;
183
184 return lr;
185}
186
187static struct selabel_lookup_rec *
188selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
189 const char *key, int type, const char **aliases)
190{
191 struct selabel_lookup_rec *lr;
Richard Hainese7f970f2015-05-06 16:11:03 +0100192
193 if (key == NULL) {
194 errno = EINVAL;
195 return NULL;
196 }
197
Stephen Smalley31f532a2017-06-01 15:26:53 -0400198 lr = rec->func_lookup_best_match(rec, key, aliases, type);
Richard Hainese7f970f2015-05-06 16:11:03 +0100199 if (!lr)
200 return NULL;
201
202 if (selabel_fini(rec, lr, translating))
203 return NULL;
204
205 return lr;
206}
207
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400208/*
209 * Public API
210 */
211
212struct selabel_handle *selabel_open(unsigned int backend,
Richard Hainesf2cd2f82015-07-10 16:53:54 +0100213 const struct selinux_opt *opts,
214 unsigned nopts)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400215{
216 struct selabel_handle *rec = NULL;
217
218 if (backend >= ARRAY_SIZE(initfuncs)) {
219 errno = EINVAL;
220 goto out;
221 }
222
William Roberts84d07eb2016-09-26 10:33:38 -0700223 if (!initfuncs[backend]) {
224 errno = ENOTSUP;
225 goto out;
226 }
227
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400228 rec = (struct selabel_handle *)malloc(sizeof(*rec));
229 if (!rec)
230 goto out;
231
232 memset(rec, 0, sizeof(*rec));
233 rec->backend = backend;
234 rec->validating = selabel_is_validate_set(opts, nopts);
Daniel J Walsh20b43b32011-04-06 17:08:27 -0400235
Richard Hainese40bbea2015-09-30 16:29:20 +0100236 rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400237
238 if ((*initfuncs[backend])(rec, opts, nopts)) {
dcashman50400d32016-12-12 10:13:27 -0800239 selabel_close(rec);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400240 rec = NULL;
241 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400242out:
243 return rec;
244}
245
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500246int selabel_lookup(struct selabel_handle *rec, char **con,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400247 const char *key, int type)
248{
249 struct selabel_lookup_rec *lr;
250
251 lr = selabel_lookup_common(rec, 1, key, type);
252 if (!lr)
253 return -1;
254
255 *con = strdup(lr->ctx_trans);
256 return *con ? 0 : -1;
257}
258
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500259int selabel_lookup_raw(struct selabel_handle *rec, char **con,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400260 const char *key, int type)
261{
262 struct selabel_lookup_rec *lr;
263
264 lr = selabel_lookup_common(rec, 0, key, type);
265 if (!lr)
266 return -1;
267
268 *con = strdup(lr->ctx_raw);
269 return *con ? 0 : -1;
270}
271
Richard Hainese7f970f2015-05-06 16:11:03 +0100272bool selabel_partial_match(struct selabel_handle *rec, const char *key)
273{
Richard Hainese7f970f2015-05-06 16:11:03 +0100274 if (!rec->func_partial_match) {
275 /*
276 * If the label backend does not support partial matching,
277 * then assume a match is possible.
278 */
279 return true;
280 }
281
Stephen Smalley31f532a2017-06-01 15:26:53 -0400282 return rec->func_partial_match(rec, key);
Richard Hainese7f970f2015-05-06 16:11:03 +0100283}
284
Richard Hainese0165022019-07-06 16:21:14 +0100285bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
286 const char *key,
287 uint8_t **calculated_digest,
288 uint8_t **xattr_digest,
289 size_t *digest_len)
290{
291 if (!rec->func_get_digests_all_partial_matches)
292 return false;
293
294 return rec->func_get_digests_all_partial_matches(rec, key,
295 calculated_digest,
296 xattr_digest,
297 digest_len);
298}
299
xunchang5cff2812019-03-11 15:24:42 -0700300bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
301 const char *key, uint8_t *digest) {
302 if (!rec->func_hash_all_partial_matches) {
303 return false;
304 }
305
306 return rec->func_hash_all_partial_matches(rec, key, digest);
307}
308
Richard Hainese7f970f2015-05-06 16:11:03 +0100309int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
310 const char *key, const char **aliases, int type)
311{
312 struct selabel_lookup_rec *lr;
313
314 if (!rec->func_lookup_best_match) {
315 errno = ENOTSUP;
316 return -1;
317 }
318
319 lr = selabel_lookup_bm_common(rec, 1, key, type, aliases);
320 if (!lr)
321 return -1;
322
323 *con = strdup(lr->ctx_trans);
324 return *con ? 0 : -1;
325}
326
327int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
328 const char *key, const char **aliases, int type)
329{
330 struct selabel_lookup_rec *lr;
331
332 if (!rec->func_lookup_best_match) {
333 errno = ENOTSUP;
334 return -1;
335 }
336
337 lr = selabel_lookup_bm_common(rec, 0, key, type, aliases);
338 if (!lr)
339 return -1;
340
341 *con = strdup(lr->ctx_raw);
342 return *con ? 0 : -1;
343}
344
Stephen Smalley6f295002015-08-05 12:52:33 -0400345enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
346 struct selabel_handle *h2)
347{
348 if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
349 return SELABEL_INCOMPARABLE;
350
351 return h1->func_cmp(h1, h2);
352}
353
Richard Hainese40bbea2015-09-30 16:29:20 +0100354int selabel_digest(struct selabel_handle *rec,
355 unsigned char **digest, size_t *digest_len,
356 char ***specfiles, size_t *num_specfiles)
357{
358 if (!rec->digest) {
359 errno = EINVAL;
360 return -1;
361 }
362
363 *digest = rec->digest->digest;
364 *digest_len = DIGEST_SPECFILE_SIZE;
365 *specfiles = rec->digest->specfile_list;
366 *num_specfiles = rec->digest->specfile_cnt;
367 return 0;
368}
369
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400370void selabel_close(struct selabel_handle *rec)
371{
dcashman50400d32016-12-12 10:13:27 -0800372 size_t i;
Dan Cashman706ddd12017-08-07 14:58:55 -0700373
dcashman50400d32016-12-12 10:13:27 -0800374 if (rec->spec_files) {
375 for (i = 0; i < rec->spec_files_len; i++)
376 free(rec->spec_files[i]);
377 free(rec->spec_files);
378 }
Richard Hainese40bbea2015-09-30 16:29:20 +0100379 if (rec->digest)
380 selabel_digest_fini(rec->digest);
dcashman50400d32016-12-12 10:13:27 -0800381 if (rec->func_close)
382 rec->func_close(rec);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400383 free(rec);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400384}
385
386void selabel_stats(struct selabel_handle *rec)
387{
388 rec->func_stats(rec);
389}