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 44typedef int (*selabel_initfunc)(struct selabel_handle *rec, 45 const struct selinux_opt *opts, 46 unsigned nopts); 47 48static 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 57static 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 86err: 87 if (digest) { 88 free(digest->digest); 89 free(digest->specfile_list); 90 free(digest); 91 } 92 return NULL; 93} 94 95static 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 114static 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 124int 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; 137out: 138 return rc; 139} 140 141/* Public API helpers */ 142static int selabel_fini(struct selabel_handle *rec, 143 struct selabel_lookup_rec *lr, 144 int translating) 145{ 146#ifdef OHOS_FC_INIT 147 char *path = NULL; 148 if (rec->spec_file != NULL) { 149 path = rec->spec_file[0]; 150 } 151 if (compat_validate(rec, lr, path, lr->lineno)) 152 return -1; 153#else 154 if (compat_validate(rec, lr, rec->spec_file, lr->lineno)) 155 return -1; 156#endif 157 158 if (translating && !lr->ctx_trans && 159 selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans)) 160 return -1; 161 162 return 0; 163} 164 165static struct selabel_lookup_rec * 166selabel_lookup_common(struct selabel_handle *rec, int translating, 167 const char *key, int type) 168{ 169 struct selabel_lookup_rec *lr; 170 171 if (key == NULL) { 172 errno = EINVAL; 173 return NULL; 174 } 175 176 lr = rec->func_lookup(rec, key, type); 177 if (!lr) 178 return NULL; 179 180 if (selabel_fini(rec, lr, translating)) 181 return NULL; 182 183 return lr; 184} 185 186static struct selabel_lookup_rec * 187selabel_lookup_bm_common(struct selabel_handle *rec, int translating, 188 const char *key, int type, const char **aliases) 189{ 190 struct selabel_lookup_rec *lr; 191 192 if (key == NULL) { 193 errno = EINVAL; 194 return NULL; 195 } 196 197 lr = rec->func_lookup_best_match(rec, key, aliases, type); 198 if (!lr) 199 return NULL; 200 201 if (selabel_fini(rec, lr, translating)) 202 return NULL; 203 204 return lr; 205} 206 207#ifdef OHOS_FC_INIT 208static void free_spec_files(struct selabel_handle *rec) 209{ 210 if (rec->spec_file != NULL) { 211 for (int path_index = 0; path_index < rec->spec_file_nums; path_index++) { 212 if (rec->spec_file[path_index] != NULL) { 213 free(rec->spec_file[path_index]); 214 } 215 } 216 free(rec->spec_file); 217 } 218} 219#endif 220 221/* 222 * Public API 223 */ 224 225struct selabel_handle *selabel_open(unsigned int backend, 226 const struct selinux_opt *opts, 227 unsigned nopts) 228{ 229 struct selabel_handle *rec = NULL; 230 231 if (backend >= ARRAY_SIZE(initfuncs)) { 232 errno = EINVAL; 233 goto out; 234 } 235 236 if (!initfuncs[backend]) { 237 errno = ENOTSUP; 238 goto out; 239 } 240 241 rec = (struct selabel_handle *)malloc(sizeof(*rec)); 242 if (!rec) 243 goto out; 244 245 memset(rec, 0, sizeof(*rec)); 246 rec->backend = backend; 247 rec->validating = selabel_is_validate_set(opts, nopts); 248 249 rec->digest = selabel_is_digest_set(opts, nopts, rec->digest); 250 251 if ((*initfuncs[backend])(rec, opts, nopts)) { 252 if (rec->digest) 253 selabel_digest_fini(rec->digest); 254#ifdef OHOS_FC_INIT 255 free_spec_files(rec); 256#else 257 free(rec->spec_file); 258#endif 259 free(rec); 260 rec = NULL; 261 } 262 263out: 264 return rec; 265} 266 267int selabel_lookup(struct selabel_handle *rec, char **con, 268 const char *key, int type) 269{ 270 struct selabel_lookup_rec *lr; 271 272 lr = selabel_lookup_common(rec, 1, key, type); 273 if (!lr) 274 return -1; 275 276 *con = strdup(lr->ctx_trans); 277 return *con ? 0 : -1; 278} 279 280int selabel_lookup_raw(struct selabel_handle *rec, char **con, 281 const char *key, int type) 282{ 283 struct selabel_lookup_rec *lr; 284 285 lr = selabel_lookup_common(rec, 0, key, type); 286 if (!lr) 287 return -1; 288 289 *con = strdup(lr->ctx_raw); 290 return *con ? 0 : -1; 291} 292 293bool selabel_partial_match(struct selabel_handle *rec, const char *key) 294{ 295 if (!rec->func_partial_match) { 296 /* 297 * If the label backend does not support partial matching, 298 * then assume a match is possible. 299 */ 300 return true; 301 } 302 303 return rec->func_partial_match(rec, key); 304} 305 306bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec, 307 const char *key, 308 uint8_t **calculated_digest, 309 uint8_t **xattr_digest, 310 size_t *digest_len) 311{ 312 if (!rec->func_get_digests_all_partial_matches) 313 return false; 314 315 return rec->func_get_digests_all_partial_matches(rec, key, 316 calculated_digest, 317 xattr_digest, 318 digest_len); 319} 320 321bool selabel_hash_all_partial_matches(struct selabel_handle *rec, 322 const char *key, uint8_t *digest) { 323 if (!rec->func_hash_all_partial_matches) { 324 return false; 325 } 326 327 return rec->func_hash_all_partial_matches(rec, key, digest); 328} 329 330int selabel_lookup_best_match(struct selabel_handle *rec, char **con, 331 const char *key, const char **aliases, int type) 332{ 333 struct selabel_lookup_rec *lr; 334 335 if (!rec->func_lookup_best_match) { 336 errno = ENOTSUP; 337 return -1; 338 } 339 340 lr = selabel_lookup_bm_common(rec, 1, key, type, aliases); 341 if (!lr) 342 return -1; 343 344 *con = strdup(lr->ctx_trans); 345 return *con ? 0 : -1; 346} 347 348int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con, 349 const char *key, const char **aliases, int type) 350{ 351 struct selabel_lookup_rec *lr; 352 353 if (!rec->func_lookup_best_match) { 354 errno = ENOTSUP; 355 return -1; 356 } 357 358 lr = selabel_lookup_bm_common(rec, 0, key, type, aliases); 359 if (!lr) 360 return -1; 361 362 *con = strdup(lr->ctx_raw); 363 return *con ? 0 : -1; 364} 365 366enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, 367 struct selabel_handle *h2) 368{ 369 if (!h1->func_cmp || h1->func_cmp != h2->func_cmp) 370 return SELABEL_INCOMPARABLE; 371 372 return h1->func_cmp(h1, h2); 373} 374 375int selabel_digest(struct selabel_handle *rec, 376 unsigned char **digest, size_t *digest_len, 377 char ***specfiles, size_t *num_specfiles) 378{ 379 if (!rec->digest) { 380 errno = EINVAL; 381 return -1; 382 } 383 384 *digest = rec->digest->digest; 385 *digest_len = DIGEST_SPECFILE_SIZE; 386 *specfiles = rec->digest->specfile_list; 387 *num_specfiles = rec->digest->specfile_cnt; 388 return 0; 389} 390 391void selabel_close(struct selabel_handle *rec) 392{ 393 if (rec->digest) 394 selabel_digest_fini(rec->digest); 395 rec->func_close(rec); 396#ifdef OHOS_FC_INIT 397 free_spec_files(rec); 398#else 399 free(rec->spec_file); 400#endif 401 free(rec); 402} 403 404void selabel_stats(struct selabel_handle *rec) 405{ 406 rec->func_stats(rec); 407} 408