Home | History | Annotate | Download | only in src
      1 /*
      2  * Generalized labeling frontend for userspace object managers.
      3  *
      4  * Author : Eamon Walsh <ewalsh (at) 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_FILE_BACKEND
     21 #define CONFIG_FILE_BACKEND(fnptr) NULL
     22 #else
     23 #define CONFIG_FILE_BACKEND(fnptr) &fnptr
     24 #endif
     25 
     26 #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 
     44 #ifdef NO_ANDROID_BACKEND
     45 #define CONFIG_ANDROID_BACKEND(fnptr) NULL
     46 #else
     47 #define CONFIG_ANDROID_BACKEND(fnptr) (&(fnptr))
     48 #endif
     49 
     50 typedef int (*selabel_initfunc)(struct selabel_handle *rec,
     51 				const struct selinux_opt *opts,
     52 				unsigned nopts);
     53 
     54 static selabel_initfunc initfuncs[] = {
     55 	CONFIG_FILE_BACKEND(selabel_file_init),
     56 	CONFIG_MEDIA_BACKEND(selabel_media_init),
     57 	CONFIG_X_BACKEND(selabel_x_init),
     58 	CONFIG_DB_BACKEND(selabel_db_init),
     59 	CONFIG_ANDROID_BACKEND(selabel_property_init),
     60 	CONFIG_ANDROID_BACKEND(selabel_service_init),
     61 };
     62 
     63 static 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 
     92 err:
     93 	if (digest) {
     94 		free(digest->digest);
     95 		free(digest->specfile_list);
     96 		free(digest);
     97 	}
     98 	return NULL;
     99 }
    100 
    101 static 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 
    116 /*
    117  * Validation functions
    118  */
    119 
    120 static inline int selabel_is_validate_set(const struct selinux_opt *opts,
    121 					  unsigned n)
    122 {
    123 	while (n--)
    124 		if (opts[n].type == SELABEL_OPT_VALIDATE)
    125 			return !!opts[n].value;
    126 
    127 	return 0;
    128 }
    129 
    130 int 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;
    143 out:
    144 	return rc;
    145 }
    146 
    147 /* Public API helpers */
    148 static int selabel_fini(struct selabel_handle *rec,
    149 			    struct selabel_lookup_rec *lr,
    150 			    int translating)
    151 {
    152 	char *path = NULL;
    153 
    154 	if (rec->spec_files)
    155 		path = rec->spec_files[0];
    156 	if (compat_validate(rec, lr, path, lr->lineno))
    157 		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 
    166 static struct selabel_lookup_rec *
    167 selabel_lookup_common(struct selabel_handle *rec, int translating,
    168 		      const char *key, int type)
    169 {
    170 	struct selabel_lookup_rec *lr;
    171 
    172 	if (key == NULL) {
    173 		errno = EINVAL;
    174 		return NULL;
    175 	}
    176 
    177 	lr = rec->func_lookup(rec, key, type);
    178 	if (!lr)
    179 		return NULL;
    180 
    181 	if (selabel_fini(rec, lr, translating))
    182 		return NULL;
    183 
    184 	return lr;
    185 }
    186 
    187 static struct selabel_lookup_rec *
    188 selabel_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;
    192 
    193 	if (key == NULL) {
    194 		errno = EINVAL;
    195 		return NULL;
    196 	}
    197 
    198 	lr = rec->func_lookup_best_match(rec, key, aliases, type);
    199 	if (!lr)
    200 		return NULL;
    201 
    202 	if (selabel_fini(rec, lr, translating))
    203 		return NULL;
    204 
    205 	return lr;
    206 }
    207 
    208 /*
    209  * Public API
    210  */
    211 
    212 struct selabel_handle *selabel_open(unsigned int backend,
    213 				    const struct selinux_opt *opts,
    214 				    unsigned nopts)
    215 {
    216 	struct selabel_handle *rec = NULL;
    217 
    218 	if (backend >= ARRAY_SIZE(initfuncs)) {
    219 		errno = EINVAL;
    220 		goto out;
    221 	}
    222 
    223 	if (!initfuncs[backend]) {
    224 		errno = ENOTSUP;
    225 		goto out;
    226 	}
    227 
    228 	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);
    235 
    236 	rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
    237 
    238 	if ((*initfuncs[backend])(rec, opts, nopts)) {
    239 		selabel_close(rec);
    240 		rec = NULL;
    241 	}
    242 out:
    243 	return rec;
    244 }
    245 
    246 int selabel_lookup(struct selabel_handle *rec, char **con,
    247 		   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 
    259 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
    260 		       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 
    272 bool selabel_partial_match(struct selabel_handle *rec, const char *key)
    273 {
    274 	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 
    282 	return rec->func_partial_match(rec, key);
    283 }
    284 
    285 bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
    286                                       const char *key, uint8_t *digest) {
    287 	if (!rec->func_hash_all_partial_matches) {
    288 		return false;
    289 	}
    290 
    291 	return rec->func_hash_all_partial_matches(rec, key, digest);
    292 }
    293 
    294 int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
    295 			      const char *key, const char **aliases, int type)
    296 {
    297 	struct selabel_lookup_rec *lr;
    298 
    299 	if (!rec->func_lookup_best_match) {
    300 		errno = ENOTSUP;
    301 		return -1;
    302 	}
    303 
    304 	lr = selabel_lookup_bm_common(rec, 1, key, type, aliases);
    305 	if (!lr)
    306 		return -1;
    307 
    308 	*con = strdup(lr->ctx_trans);
    309 	return *con ? 0 : -1;
    310 }
    311 
    312 int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
    313 			      const char *key, const char **aliases, int type)
    314 {
    315 	struct selabel_lookup_rec *lr;
    316 
    317 	if (!rec->func_lookup_best_match) {
    318 		errno = ENOTSUP;
    319 		return -1;
    320 	}
    321 
    322 	lr = selabel_lookup_bm_common(rec, 0, key, type, aliases);
    323 	if (!lr)
    324 		return -1;
    325 
    326 	*con = strdup(lr->ctx_raw);
    327 	return *con ? 0 : -1;
    328 }
    329 
    330 enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
    331 				    struct selabel_handle *h2)
    332 {
    333 	if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
    334 		return SELABEL_INCOMPARABLE;
    335 
    336 	return h1->func_cmp(h1, h2);
    337 }
    338 
    339 int selabel_digest(struct selabel_handle *rec,
    340 				    unsigned char **digest, size_t *digest_len,
    341 				    char ***specfiles, size_t *num_specfiles)
    342 {
    343 	if (!rec->digest) {
    344 		errno = EINVAL;
    345 		return -1;
    346 	}
    347 
    348 	*digest = rec->digest->digest;
    349 	*digest_len = DIGEST_SPECFILE_SIZE;
    350 	*specfiles = rec->digest->specfile_list;
    351 	*num_specfiles = rec->digest->specfile_cnt;
    352 	return 0;
    353 }
    354 
    355 void selabel_close(struct selabel_handle *rec)
    356 {
    357 	size_t i;
    358 
    359 	if (rec->spec_files) {
    360 		for (i = 0; i < rec->spec_files_len; i++)
    361 			free(rec->spec_files[i]);
    362 		free(rec->spec_files);
    363 	}
    364 	if (rec->digest)
    365 		selabel_digest_fini(rec->digest);
    366 	if (rec->func_close)
    367 		rec->func_close(rec);
    368 	free(rec);
    369 }
    370 
    371 void selabel_stats(struct selabel_handle *rec)
    372 {
    373 	rec->func_stats(rec);
    374 }
    375