16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * Property Service contexts backend for labeling Android 36cd6a6acSopenharmony_ci * property keys 46cd6a6acSopenharmony_ci */ 56cd6a6acSopenharmony_ci 66cd6a6acSopenharmony_ci#include <stdarg.h> 76cd6a6acSopenharmony_ci#include <string.h> 86cd6a6acSopenharmony_ci#include <ctype.h> 96cd6a6acSopenharmony_ci#include <errno.h> 106cd6a6acSopenharmony_ci#include <limits.h> 116cd6a6acSopenharmony_ci#include <sys/types.h> 126cd6a6acSopenharmony_ci#include <sys/stat.h> 136cd6a6acSopenharmony_ci#include "callbacks.h" 146cd6a6acSopenharmony_ci#include "label_internal.h" 156cd6a6acSopenharmony_ci 166cd6a6acSopenharmony_ci/* A property security context specification. */ 176cd6a6acSopenharmony_citypedef struct spec { 186cd6a6acSopenharmony_ci struct selabel_lookup_rec lr; /* holds contexts for lookup result */ 196cd6a6acSopenharmony_ci char *property_key; /* property key string */ 206cd6a6acSopenharmony_ci} spec_t; 216cd6a6acSopenharmony_ci 226cd6a6acSopenharmony_ci/* Our stored configuration */ 236cd6a6acSopenharmony_cistruct saved_data { 246cd6a6acSopenharmony_ci /* 256cd6a6acSopenharmony_ci * The array of specifications is sorted for longest 266cd6a6acSopenharmony_ci * prefix match 276cd6a6acSopenharmony_ci */ 286cd6a6acSopenharmony_ci spec_t *spec_arr; 296cd6a6acSopenharmony_ci unsigned int nspec; /* total number of specifications */ 306cd6a6acSopenharmony_ci}; 316cd6a6acSopenharmony_ci 326cd6a6acSopenharmony_cistatic int cmp(const void *A, const void *B) 336cd6a6acSopenharmony_ci{ 346cd6a6acSopenharmony_ci const struct spec *sp1 = A, *sp2 = B; 356cd6a6acSopenharmony_ci 366cd6a6acSopenharmony_ci if (strncmp(sp1->property_key, "*", 1) == 0) 376cd6a6acSopenharmony_ci return 1; 386cd6a6acSopenharmony_ci if (strncmp(sp2->property_key, "*", 1) == 0) 396cd6a6acSopenharmony_ci return -1; 406cd6a6acSopenharmony_ci 416cd6a6acSopenharmony_ci size_t L1 = strlen(sp1->property_key); 426cd6a6acSopenharmony_ci size_t L2 = strlen(sp2->property_key); 436cd6a6acSopenharmony_ci 446cd6a6acSopenharmony_ci return (L1 < L2) - (L1 > L2); 456cd6a6acSopenharmony_ci} 466cd6a6acSopenharmony_ci 476cd6a6acSopenharmony_ci/* 486cd6a6acSopenharmony_ci * Warn about duplicate specifications. 496cd6a6acSopenharmony_ci */ 506cd6a6acSopenharmony_cistatic int nodups_specs(struct saved_data *data, const char *path) 516cd6a6acSopenharmony_ci{ 526cd6a6acSopenharmony_ci int rc = 0; 536cd6a6acSopenharmony_ci unsigned int ii, jj; 546cd6a6acSopenharmony_ci struct spec *curr_spec, *spec_arr = data->spec_arr; 556cd6a6acSopenharmony_ci 566cd6a6acSopenharmony_ci for (ii = 0; ii < data->nspec; ii++) { 576cd6a6acSopenharmony_ci curr_spec = &spec_arr[ii]; 586cd6a6acSopenharmony_ci for (jj = ii + 1; jj < data->nspec; jj++) { 596cd6a6acSopenharmony_ci if (!strcmp(spec_arr[jj].property_key, 606cd6a6acSopenharmony_ci curr_spec->property_key)) { 616cd6a6acSopenharmony_ci rc = -1; 626cd6a6acSopenharmony_ci errno = EINVAL; 636cd6a6acSopenharmony_ci if (strcmp(spec_arr[jj].lr.ctx_raw, 646cd6a6acSopenharmony_ci curr_spec->lr.ctx_raw)) { 656cd6a6acSopenharmony_ci selinux_log 666cd6a6acSopenharmony_ci (SELINUX_ERROR, 676cd6a6acSopenharmony_ci "%s: Multiple different specifications for %s (%s and %s).\n", 686cd6a6acSopenharmony_ci path, curr_spec->property_key, 696cd6a6acSopenharmony_ci spec_arr[jj].lr.ctx_raw, 706cd6a6acSopenharmony_ci curr_spec->lr.ctx_raw); 716cd6a6acSopenharmony_ci } else { 726cd6a6acSopenharmony_ci selinux_log 736cd6a6acSopenharmony_ci (SELINUX_ERROR, 746cd6a6acSopenharmony_ci "%s: Multiple same specifications for %s.\n", 756cd6a6acSopenharmony_ci path, curr_spec->property_key); 766cd6a6acSopenharmony_ci } 776cd6a6acSopenharmony_ci } 786cd6a6acSopenharmony_ci } 796cd6a6acSopenharmony_ci } 806cd6a6acSopenharmony_ci return rc; 816cd6a6acSopenharmony_ci} 826cd6a6acSopenharmony_ci 836cd6a6acSopenharmony_cistatic int process_line(struct selabel_handle *rec, 846cd6a6acSopenharmony_ci const char *path, char *line_buf, 856cd6a6acSopenharmony_ci int pass, unsigned lineno) 866cd6a6acSopenharmony_ci{ 876cd6a6acSopenharmony_ci int items; 886cd6a6acSopenharmony_ci char *prop = NULL, *context = NULL; 896cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 906cd6a6acSopenharmony_ci spec_t *spec_arr = data->spec_arr; 916cd6a6acSopenharmony_ci unsigned int nspec = data->nspec; 926cd6a6acSopenharmony_ci const char *errbuf = NULL; 936cd6a6acSopenharmony_ci 946cd6a6acSopenharmony_ci items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context); 956cd6a6acSopenharmony_ci if (items < 0) { 966cd6a6acSopenharmony_ci if (errbuf) { 976cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, 986cd6a6acSopenharmony_ci "%s: line %u error due to: %s\n", path, 996cd6a6acSopenharmony_ci lineno, errbuf); 1006cd6a6acSopenharmony_ci } else { 1016cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, 1026cd6a6acSopenharmony_ci "%s: line %u error due to: %m\n", path, 1036cd6a6acSopenharmony_ci lineno); 1046cd6a6acSopenharmony_ci } 1056cd6a6acSopenharmony_ci return -1; 1066cd6a6acSopenharmony_ci } 1076cd6a6acSopenharmony_ci 1086cd6a6acSopenharmony_ci if (items == 0) 1096cd6a6acSopenharmony_ci return items; 1106cd6a6acSopenharmony_ci 1116cd6a6acSopenharmony_ci if (items != 2) { 1126cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, 1136cd6a6acSopenharmony_ci "%s: line %u is missing fields\n", path, 1146cd6a6acSopenharmony_ci lineno); 1156cd6a6acSopenharmony_ci free(prop); 1166cd6a6acSopenharmony_ci errno = EINVAL; 1176cd6a6acSopenharmony_ci return -1; 1186cd6a6acSopenharmony_ci } 1196cd6a6acSopenharmony_ci 1206cd6a6acSopenharmony_ci if (pass == 0) { 1216cd6a6acSopenharmony_ci free(prop); 1226cd6a6acSopenharmony_ci free(context); 1236cd6a6acSopenharmony_ci } else if (pass == 1) { 1246cd6a6acSopenharmony_ci /* On the second pass, process and store the specification in spec. */ 1256cd6a6acSopenharmony_ci spec_arr[nspec].property_key = prop; 1266cd6a6acSopenharmony_ci spec_arr[nspec].lr.ctx_raw = context; 1276cd6a6acSopenharmony_ci 1286cd6a6acSopenharmony_ci if (rec->validating) { 1296cd6a6acSopenharmony_ci if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { 1306cd6a6acSopenharmony_ci selinux_log(SELINUX_ERROR, 1316cd6a6acSopenharmony_ci "%s: line %u has invalid context %s\n", 1326cd6a6acSopenharmony_ci path, lineno, spec_arr[nspec].lr.ctx_raw); 1336cd6a6acSopenharmony_ci errno = EINVAL; 1346cd6a6acSopenharmony_ci return -1; 1356cd6a6acSopenharmony_ci } 1366cd6a6acSopenharmony_ci } 1376cd6a6acSopenharmony_ci } 1386cd6a6acSopenharmony_ci 1396cd6a6acSopenharmony_ci data->nspec = ++nspec; 1406cd6a6acSopenharmony_ci return 0; 1416cd6a6acSopenharmony_ci} 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_cistatic int init(struct selabel_handle *rec, const struct selinux_opt *opts, 1446cd6a6acSopenharmony_ci unsigned n) 1456cd6a6acSopenharmony_ci{ 1466cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 1476cd6a6acSopenharmony_ci const char *path = NULL; 1486cd6a6acSopenharmony_ci FILE *fp; 1496cd6a6acSopenharmony_ci char line_buf[BUFSIZ]; 1506cd6a6acSopenharmony_ci unsigned int lineno, maxnspec, pass; 1516cd6a6acSopenharmony_ci int status = -1; 1526cd6a6acSopenharmony_ci struct stat sb; 1536cd6a6acSopenharmony_ci 1546cd6a6acSopenharmony_ci /* Process arguments */ 1556cd6a6acSopenharmony_ci while (n--) 1566cd6a6acSopenharmony_ci switch (opts[n].type) { 1576cd6a6acSopenharmony_ci case SELABEL_OPT_PATH: 1586cd6a6acSopenharmony_ci path = opts[n].value; 1596cd6a6acSopenharmony_ci break; 1606cd6a6acSopenharmony_ci } 1616cd6a6acSopenharmony_ci 1626cd6a6acSopenharmony_ci if (!path) 1636cd6a6acSopenharmony_ci return -1; 1646cd6a6acSopenharmony_ci 1656cd6a6acSopenharmony_ci /* Open the specification file. */ 1666cd6a6acSopenharmony_ci if ((fp = fopen(path, "re")) == NULL) 1676cd6a6acSopenharmony_ci return -1; 1686cd6a6acSopenharmony_ci 1696cd6a6acSopenharmony_ci if (fstat(fileno(fp), &sb) < 0) 1706cd6a6acSopenharmony_ci goto finish; 1716cd6a6acSopenharmony_ci errno = EINVAL; 1726cd6a6acSopenharmony_ci if (!S_ISREG(sb.st_mode)) 1736cd6a6acSopenharmony_ci goto finish; 1746cd6a6acSopenharmony_ci 1756cd6a6acSopenharmony_ci /* 1766cd6a6acSopenharmony_ci * Two passes of the specification file. First is to get the size. 1776cd6a6acSopenharmony_ci * After the first pass, the spec array is malloced to the appropriate 1786cd6a6acSopenharmony_ci * size. Second pass is to populate the spec array and check for 1796cd6a6acSopenharmony_ci * dups. 1806cd6a6acSopenharmony_ci */ 1816cd6a6acSopenharmony_ci maxnspec = UINT_MAX / sizeof(spec_t); 1826cd6a6acSopenharmony_ci for (pass = 0; pass < 2; pass++) { 1836cd6a6acSopenharmony_ci data->nspec = 0; 1846cd6a6acSopenharmony_ci lineno = 0; 1856cd6a6acSopenharmony_ci 1866cd6a6acSopenharmony_ci while (fgets(line_buf, sizeof(line_buf) - 1, fp) 1876cd6a6acSopenharmony_ci && data->nspec < maxnspec) { 1886cd6a6acSopenharmony_ci if (process_line(rec, path, line_buf, pass, ++lineno) 1896cd6a6acSopenharmony_ci != 0) 1906cd6a6acSopenharmony_ci goto finish; 1916cd6a6acSopenharmony_ci } 1926cd6a6acSopenharmony_ci 1936cd6a6acSopenharmony_ci if (pass == 1) { 1946cd6a6acSopenharmony_ci status = nodups_specs(data, path); 1956cd6a6acSopenharmony_ci 1966cd6a6acSopenharmony_ci if (status) 1976cd6a6acSopenharmony_ci goto finish; 1986cd6a6acSopenharmony_ci } 1996cd6a6acSopenharmony_ci 2006cd6a6acSopenharmony_ci if (pass == 0) { 2016cd6a6acSopenharmony_ci if (data->nspec == 0) { 2026cd6a6acSopenharmony_ci status = 0; 2036cd6a6acSopenharmony_ci goto finish; 2046cd6a6acSopenharmony_ci } 2056cd6a6acSopenharmony_ci 2066cd6a6acSopenharmony_ci if (NULL == (data->spec_arr = 2076cd6a6acSopenharmony_ci calloc(data->nspec, sizeof(spec_t)))) 2086cd6a6acSopenharmony_ci goto finish; 2096cd6a6acSopenharmony_ci 2106cd6a6acSopenharmony_ci maxnspec = data->nspec; 2116cd6a6acSopenharmony_ci rewind(fp); 2126cd6a6acSopenharmony_ci } 2136cd6a6acSopenharmony_ci } 2146cd6a6acSopenharmony_ci 2156cd6a6acSopenharmony_ci qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); 2166cd6a6acSopenharmony_ci 2176cd6a6acSopenharmony_ci status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); 2186cd6a6acSopenharmony_ci if (status) 2196cd6a6acSopenharmony_ci goto finish; 2206cd6a6acSopenharmony_ci 2216cd6a6acSopenharmony_ci digest_gen_hash(rec->digest); 2226cd6a6acSopenharmony_ci 2236cd6a6acSopenharmony_cifinish: 2246cd6a6acSopenharmony_ci fclose(fp); 2256cd6a6acSopenharmony_ci return status; 2266cd6a6acSopenharmony_ci} 2276cd6a6acSopenharmony_ci 2286cd6a6acSopenharmony_ci/* 2296cd6a6acSopenharmony_ci * Backend interface routines 2306cd6a6acSopenharmony_ci */ 2316cd6a6acSopenharmony_cistatic void closef(struct selabel_handle *rec) 2326cd6a6acSopenharmony_ci{ 2336cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 2346cd6a6acSopenharmony_ci struct spec *spec; 2356cd6a6acSopenharmony_ci unsigned int i; 2366cd6a6acSopenharmony_ci 2376cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) { 2386cd6a6acSopenharmony_ci spec = &data->spec_arr[i]; 2396cd6a6acSopenharmony_ci free(spec->property_key); 2406cd6a6acSopenharmony_ci free(spec->lr.ctx_raw); 2416cd6a6acSopenharmony_ci free(spec->lr.ctx_trans); 2426cd6a6acSopenharmony_ci } 2436cd6a6acSopenharmony_ci 2446cd6a6acSopenharmony_ci if (data->spec_arr) 2456cd6a6acSopenharmony_ci free(data->spec_arr); 2466cd6a6acSopenharmony_ci 2476cd6a6acSopenharmony_ci free(data); 2486cd6a6acSopenharmony_ci} 2496cd6a6acSopenharmony_ci 2506cd6a6acSopenharmony_cistatic struct selabel_lookup_rec *property_lookup(struct selabel_handle *rec, 2516cd6a6acSopenharmony_ci const char *key, 2526cd6a6acSopenharmony_ci int __attribute__((unused)) type) 2536cd6a6acSopenharmony_ci{ 2546cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 2556cd6a6acSopenharmony_ci spec_t *spec_arr = data->spec_arr; 2566cd6a6acSopenharmony_ci unsigned int i; 2576cd6a6acSopenharmony_ci struct selabel_lookup_rec *ret = NULL; 2586cd6a6acSopenharmony_ci 2596cd6a6acSopenharmony_ci if (!data->nspec) { 2606cd6a6acSopenharmony_ci errno = ENOENT; 2616cd6a6acSopenharmony_ci goto finish; 2626cd6a6acSopenharmony_ci } 2636cd6a6acSopenharmony_ci 2646cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) { 2656cd6a6acSopenharmony_ci if (strncmp(spec_arr[i].property_key, key, 2666cd6a6acSopenharmony_ci strlen(spec_arr[i].property_key)) == 0) { 2676cd6a6acSopenharmony_ci break; 2686cd6a6acSopenharmony_ci } 2696cd6a6acSopenharmony_ci if (strncmp(spec_arr[i].property_key, "*", 1) == 0) 2706cd6a6acSopenharmony_ci break; 2716cd6a6acSopenharmony_ci } 2726cd6a6acSopenharmony_ci 2736cd6a6acSopenharmony_ci if (i >= data->nspec) { 2746cd6a6acSopenharmony_ci /* No matching specification. */ 2756cd6a6acSopenharmony_ci errno = ENOENT; 2766cd6a6acSopenharmony_ci goto finish; 2776cd6a6acSopenharmony_ci } 2786cd6a6acSopenharmony_ci 2796cd6a6acSopenharmony_ci ret = &spec_arr[i].lr; 2806cd6a6acSopenharmony_ci 2816cd6a6acSopenharmony_cifinish: 2826cd6a6acSopenharmony_ci return ret; 2836cd6a6acSopenharmony_ci} 2846cd6a6acSopenharmony_ci 2856cd6a6acSopenharmony_cistatic struct selabel_lookup_rec *service_lookup(struct selabel_handle *rec, 2866cd6a6acSopenharmony_ci const char *key, int __attribute__((unused)) type) 2876cd6a6acSopenharmony_ci{ 2886cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 2896cd6a6acSopenharmony_ci spec_t *spec_arr = data->spec_arr; 2906cd6a6acSopenharmony_ci unsigned int i; 2916cd6a6acSopenharmony_ci struct selabel_lookup_rec *ret = NULL; 2926cd6a6acSopenharmony_ci 2936cd6a6acSopenharmony_ci if (!data->nspec) { 2946cd6a6acSopenharmony_ci errno = ENOENT; 2956cd6a6acSopenharmony_ci goto finish; 2966cd6a6acSopenharmony_ci } 2976cd6a6acSopenharmony_ci 2986cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) { 2996cd6a6acSopenharmony_ci if (strcmp(spec_arr[i].property_key, key) == 0) 3006cd6a6acSopenharmony_ci break; 3016cd6a6acSopenharmony_ci if (strcmp(spec_arr[i].property_key, "*") == 0) 3026cd6a6acSopenharmony_ci break; 3036cd6a6acSopenharmony_ci } 3046cd6a6acSopenharmony_ci 3056cd6a6acSopenharmony_ci if (i >= data->nspec) { 3066cd6a6acSopenharmony_ci /* No matching specification. */ 3076cd6a6acSopenharmony_ci errno = ENOENT; 3086cd6a6acSopenharmony_ci goto finish; 3096cd6a6acSopenharmony_ci } 3106cd6a6acSopenharmony_ci 3116cd6a6acSopenharmony_ci ret = &spec_arr[i].lr; 3126cd6a6acSopenharmony_ci 3136cd6a6acSopenharmony_cifinish: 3146cd6a6acSopenharmony_ci return ret; 3156cd6a6acSopenharmony_ci} 3166cd6a6acSopenharmony_ci 3176cd6a6acSopenharmony_cistatic void stats(struct selabel_handle __attribute__((unused)) *rec) 3186cd6a6acSopenharmony_ci{ 3196cd6a6acSopenharmony_ci selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n"); 3206cd6a6acSopenharmony_ci} 3216cd6a6acSopenharmony_ci 3226cd6a6acSopenharmony_ciint selabel_property_init(struct selabel_handle *rec, 3236cd6a6acSopenharmony_ci const struct selinux_opt *opts, 3246cd6a6acSopenharmony_ci unsigned nopts) 3256cd6a6acSopenharmony_ci{ 3266cd6a6acSopenharmony_ci struct saved_data *data; 3276cd6a6acSopenharmony_ci 3286cd6a6acSopenharmony_ci data = (struct saved_data *)calloc(1, sizeof(*data)); 3296cd6a6acSopenharmony_ci if (!data) 3306cd6a6acSopenharmony_ci return -1; 3316cd6a6acSopenharmony_ci 3326cd6a6acSopenharmony_ci rec->data = data; 3336cd6a6acSopenharmony_ci rec->func_close = &closef; 3346cd6a6acSopenharmony_ci rec->func_stats = &stats; 3356cd6a6acSopenharmony_ci rec->func_lookup = &property_lookup; 3366cd6a6acSopenharmony_ci 3376cd6a6acSopenharmony_ci return init(rec, opts, nopts); 3386cd6a6acSopenharmony_ci} 3396cd6a6acSopenharmony_ci 3406cd6a6acSopenharmony_ciint selabel_service_init(struct selabel_handle *rec, 3416cd6a6acSopenharmony_ci const struct selinux_opt *opts, unsigned nopts) 3426cd6a6acSopenharmony_ci{ 3436cd6a6acSopenharmony_ci struct saved_data *data; 3446cd6a6acSopenharmony_ci 3456cd6a6acSopenharmony_ci data = (struct saved_data *)calloc(1, sizeof(*data)); 3466cd6a6acSopenharmony_ci if (!data) 3476cd6a6acSopenharmony_ci return -1; 3486cd6a6acSopenharmony_ci 3496cd6a6acSopenharmony_ci rec->data = data; 3506cd6a6acSopenharmony_ci rec->func_close = &closef; 3516cd6a6acSopenharmony_ci rec->func_stats = &stats; 3526cd6a6acSopenharmony_ci rec->func_lookup = &service_lookup; 3536cd6a6acSopenharmony_ci 3546cd6a6acSopenharmony_ci return init(rec, opts, nopts); 3556cd6a6acSopenharmony_ci} 356