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