/* * Warn about duplicate specifications. */ static int nodups_specs(struct saved_data *data, const char *path) { int rc = 0; unsigned int ii, jj; struct spec *curr_spec, *spec_arr = data->spec_arr; for (ii = 0; ii < data->nspec; ii++) { curr_spec = &spec_arr[ii]; for (jj = ii + 1; jj < data->nspec; jj++) { if (!strcmp(spec_arr[jj].property_key, curr_spec->property_key)) { rc = -1; errno = EINVAL; if (strcmp(spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) { selinux_log (SELINUX_ERROR, "%s: Multiple different specifications for %s (%s and %s).\n", path, curr_spec->property_key, spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw); } else { selinux_log (SELINUX_ERROR, "%s: Multiple same specifications for %s.\n", path, curr_spec->property_key); } } } } return rc; }
static int process_line(struct selabel_handle *rec, const char *path, char *line_buf, int pass, unsigned lineno) { int items, len; char buf1[BUFSIZ], buf2[BUFSIZ]; char *buf_p, *prop = buf1, *context = buf2; struct saved_data *data = (struct saved_data *)rec->data; spec_t *spec_arr = data->spec_arr; unsigned int nspec = data->nspec; len = strlen(line_buf); if (line_buf[len - 1] == '\n') line_buf[len - 1] = 0; buf_p = line_buf; while (isspace(*buf_p)) buf_p++; /* Skip comment lines and empty lines. */ if (*buf_p == '#' || *buf_p == 0) return 0; items = sscanf(line_buf, "%255s %255s", prop, context); if (items != 2) { selinux_log(SELINUX_WARNING, "%s: line %d is missing fields, skipping\n", path, lineno); return 0; } if (pass == 1) { /* On the second pass, process and store the specification in spec. */ spec_arr[nspec].property_key = strdup(prop); if (!spec_arr[nspec].property_key) { selinux_log(SELINUX_WARNING, "%s: out of memory at line %d on prop %s\n", path, lineno, prop); return -1; } spec_arr[nspec].lr.ctx_raw = strdup(context); if (!spec_arr[nspec].lr.ctx_raw) { selinux_log(SELINUX_WARNING, "%s: out of memory at line %d on context %s\n", path, lineno, context); return -1; } if (rec->validating) { if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { selinux_log(SELINUX_WARNING, "%s: line %d has invalid context %s\n", path, lineno, spec_arr[nspec].lr.ctx_raw); } } } data->nspec = ++nspec; return 0; }
static int add_exclude(const char *directory, bool who) { struct edir *tmp_list, *current; size_t len = 0; int i; /* Check if already present. */ for (i = 0; i < exclude_count; i++) { if (strcmp(directory, exclude_lst[i].directory) == 0) return 0; } if (directory == NULL || directory[0] != '/') { selinux_log(SELINUX_ERROR, "Full path required for exclude: %s.\n", directory); errno = EINVAL; return -1; } tmp_list = realloc(exclude_lst, sizeof(struct edir) * (exclude_count + 1)); if (!tmp_list) goto oom; exclude_lst = tmp_list; len = strlen(directory); while (len > 1 && directory[len - 1] == '/') len--; current = (exclude_lst + exclude_count); current->directory = strndup(directory, len); if (!current->directory) goto oom; current->size = len; current->caller_excluded = who; exclude_count++; return 0; oom: selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); return -1; }
static enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, const char *reason, int i, int j) { selinux_log(SELINUX_INFO, "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n", reason, i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw, j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw); return SELABEL_INCOMPARABLE; }
static void stats(struct selabel_handle *rec) { struct saved_data *data = (struct saved_data *)rec->data; unsigned int i, total = 0; for (i = 0; i < data->nspec; i++) total += data->spec_arr[i].matches; selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", data->nspec, total); }
/* * selabel_stats() handler */ static void db_stats(struct selabel_handle *rec) { catalog_t *catalog = (catalog_t *)rec->data; unsigned int i, total = 0; for (i = 0; i < catalog->nspec; i++) total += catalog->specs[i].matches; selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", catalog->nspec, total); }
static void stats(struct selabel_handle *rec) { struct saved_data *data = (struct saved_data *)rec->data; unsigned int i, nspec = data->nspec; spec_t *spec_arr = data->spec_arr; for (i = 0; i < nspec; i++) { if (spec_arr[i].matches == 0) { if (spec_arr[i].type_str) { selinux_log(SELINUX_WARNING, "Warning! No matches for (%s, %s, %s)\n", spec_arr[i].regex_str, spec_arr[i].type_str, spec_arr[i].lr.ctx_raw); } else { selinux_log(SELINUX_WARNING, "Warning! No matches for (%s, %s)\n", spec_arr[i].regex_str, spec_arr[i].lr.ctx_raw); } } } }
static int process_line(const char *path, char *line_buf, int pass, unsigned lineno, struct selabel_handle *rec) { struct saved_data *data = (struct saved_data *)rec->data; int items; char *buf_p; char *key, *context; buf_p = line_buf; while (isspace(*buf_p)) buf_p++; /* Skip comment lines and empty lines. */ if (*buf_p == '#' || *buf_p == 0) return 0; items = sscanf(line_buf, "%ms %ms ", &key, &context); if (items < 2) { selinux_log(SELINUX_WARNING, "%s: line %u is missing fields, skipping\n", path, lineno); if (items == 1) free(key); return 0; } if (pass == 1) { data->spec_arr[data->nspec].key = key; data->spec_arr[data->nspec].lr.ctx_raw = context; } data->nspec++; if (pass == 0) { free(key); free(context); } return 0; }
int selinux_set_mapping(struct security_class_mapping *map) { size_t size = sizeof(struct selinux_mapping); security_class_t i, j; unsigned k; bool print_unknown_handle = false; bool reject = (security_reject_unknown() == 1); bool deny = (security_deny_unknown() == 1); free(current_mapping); current_mapping = NULL; current_mapping_size = 0; if (avc_reset() < 0) goto err; /* Find number of classes in the input mapping */ if (!map) { errno = EINVAL; goto err; } i = 0; while (map[i].name) i++; /* Allocate space for the class records, plus one for class zero */ current_mapping = (struct selinux_mapping *)calloc(++i, size); if (!current_mapping) goto err; /* Store the raw class and permission values */ j = 0; while (map[j].name) { struct security_class_mapping *p_in = map + (j++); struct selinux_mapping *p_out = current_mapping + j; p_out->value = string_to_security_class(p_in->name); if (!p_out->value) { selinux_log(SELINUX_INFO, "SELinux: Class %s not defined in policy.\n", p_in->name); if (reject) goto err2; p_out->num_perms = 0; print_unknown_handle = true; continue; } k = 0; while (p_in->perms[k]) { /* An empty permission string skips ahead */ if (!*p_in->perms[k]) { k++; continue; } p_out->perms[k] = string_to_av_perm(p_out->value, p_in->perms[k]); if (!p_out->perms[k]) { selinux_log(SELINUX_INFO, "SELinux: Permission %s in class %s not defined in policy.\n", p_in->perms[k], p_in->name); if (reject) goto err2; print_unknown_handle = true; } k++; } p_out->num_perms = k; } if (print_unknown_handle) selinux_log(SELINUX_INFO, "SELinux: the above unknown classes and permissions will be %s\n", deny ? "denied" : "allowed"); /* Set the mapping size here so the above lookups are "raw" */ current_mapping_size = i; return 0; err2: free(current_mapping); current_mapping = NULL; current_mapping_size = 0; err: return -1; }
static int process_line(const char *path, char *line_buf, int pass, unsigned lineno, struct selabel_handle *rec) { struct saved_data *data = (struct saved_data *)rec->data; int items; char *buf_p; char *type, *key, *context; buf_p = line_buf; while (isspace(*buf_p)) buf_p++; /* Skip comment lines and empty lines. */ if (*buf_p == '#' || *buf_p == 0) return 0; items = sscanf(line_buf, "%ms %ms %ms ", &type, &key, &context); if (items < 3) { selinux_log(SELINUX_WARNING, "%s: line %u is missing fields, skipping\n", path, lineno); if (items > 0) free(type); if (items > 1) free(key); return 0; } if (pass == 1) { /* Convert the type string to a mode format */ if (!strcmp(type, "property")) data->spec_arr[data->nspec].type = SELABEL_X_PROP; else if (!strcmp(type, "extension")) data->spec_arr[data->nspec].type = SELABEL_X_EXT; else if (!strcmp(type, "client")) data->spec_arr[data->nspec].type = SELABEL_X_CLIENT; else if (!strcmp(type, "event")) data->spec_arr[data->nspec].type = SELABEL_X_EVENT; else if (!strcmp(type, "selection")) data->spec_arr[data->nspec].type = SELABEL_X_SELN; else if (!strcmp(type, "poly_property")) data->spec_arr[data->nspec].type = SELABEL_X_POLYPROP; else if (!strcmp(type, "poly_selection")) data->spec_arr[data->nspec].type = SELABEL_X_POLYSELN; else { selinux_log(SELINUX_WARNING, "%s: line %u has invalid object type %s\n", path, lineno, type); return 0; } data->spec_arr[data->nspec].key = key; data->spec_arr[data->nspec].lr.ctx_raw = context; free(type); } data->nspec++; if (pass == 0) { free(type); free(key); free(context); } return 0; }
/* * Helper function to parse a line read from the specfile */ static int process_line(const char *path, char *line_buf, unsigned int line_num, catalog_t *catalog) { spec_t *spec = &catalog->specs[catalog->nspec]; char *type, *key, *context, *temp; int items; /* Cut off comments */ temp = strchr(line_buf, '#'); if (temp) *temp = '\0'; /* * Every entry must have the following format * <object class> <object name> <security context> */ type = key = context = temp = NULL; items = sscanf(line_buf, "%as %as %as %as", &type, &key, &context, &temp); if (items != 3) { if (items > 0) selinux_log(SELINUX_WARNING, "%s: line %d has invalid format, skipped", path, line_num); goto skip; } /* * Set up individual spec entry */ memset(spec, 0, sizeof(spec_t)); if (!strcmp(type, "db_database")) spec->type = SELABEL_DB_DATABASE; else if (!strcmp(type, "db_schema")) spec->type = SELABEL_DB_SCHEMA; else if (!strcmp(type, "db_table")) spec->type = SELABEL_DB_TABLE; else if (!strcmp(type, "db_column")) spec->type = SELABEL_DB_COLUMN; else if (!strcmp(type, "db_sequence")) spec->type = SELABEL_DB_SEQUENCE; else if (!strcmp(type, "db_view")) spec->type = SELABEL_DB_VIEW; else if (!strcmp(type, "db_procedure")) spec->type = SELABEL_DB_PROCEDURE; else if (!strcmp(type, "db_blob")) spec->type = SELABEL_DB_BLOB; else if (!strcmp(type, "db_tuple")) spec->type = SELABEL_DB_TUPLE; else if (!strcmp(type, "db_language")) spec->type = SELABEL_DB_LANGUAGE; else { selinux_log(SELINUX_WARNING, "%s: line %d has invalid object type %s\n", path, line_num, type); goto skip; } free(type); spec->key = key; spec->lr.ctx_raw = context; catalog->nspec++; return 0; skip: free(type); free(key); free(context); free(temp); return 0; }
int selinux_android_seapp_context_reload(void) { FILE *fp = NULL; char line_buf[BUFSIZ]; char *token; unsigned lineno; struct seapp_context *cur; char *p, *name = NULL, *value = NULL, *saveptr; size_t len; int n, ret; set_policy_index(); fp = fopen(seapp_contexts_file[policy_index], "r"); if (!fp) { selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__); return -1; } free_seapp_contexts(); nspec = 0; while (fgets(line_buf, sizeof line_buf - 1, fp)) { p = line_buf; while (isspace(*p)) p++; if (*p == '#' || *p == 0) continue; nspec++; } seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *)); if (!seapp_contexts) goto oom; rewind(fp); nspec = 0; lineno = 1; while (fgets(line_buf, sizeof line_buf - 1, fp)) { len = strlen(line_buf); if (line_buf[len - 1] == '\n') line_buf[len - 1] = 0; p = line_buf; while (isspace(*p)) p++; if (*p == '#' || *p == 0) continue; cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context)); if (!cur) goto oom; token = strtok_r(p, " \t", &saveptr); if (!token) { free_seapp_context(cur); goto err; } while (1) { name = token; value = strchr(name, '='); if (!value) { free_seapp_context(cur); goto err; } *value++ = 0; if (!strcasecmp(name, "isSystemServer")) { if (!strcasecmp(value, "true")) cur->isSystemServer = true; else if (!strcasecmp(value, "false")) cur->isSystemServer = false; else { free_seapp_context(cur); goto err; } } else if (!strcasecmp(name, "isOwner")) { cur->isOwnerSet = true; if (!strcasecmp(value, "true")) cur->isOwner = true; else if (!strcasecmp(value, "false")) cur->isOwner = false; else { free_seapp_context(cur); goto err; } } else if (!strcasecmp(name, "user")) { if (cur->user.str) { free_seapp_context(cur); goto err; } cur->user.str = strdup(value); if (!cur->user.str) { free_seapp_context(cur); goto oom; } cur->user.len = strlen(cur->user.str); if (cur->user.str[cur->user.len-1] == '*') cur->user.is_prefix = 1; } else if (!strcasecmp(name, "seinfo")) { if (cur->seinfo) { free_seapp_context(cur); goto err; } cur->seinfo = strdup(value); if (!cur->seinfo) { free_seapp_context(cur); goto oom; } } else if (!strcasecmp(name, "name")) { if (cur->name.str) { free_seapp_context(cur); goto err; } cur->name.str = strdup(value); if (!cur->name.str) { free_seapp_context(cur); goto oom; } cur->name.len = strlen(cur->name.str); if (cur->name.str[cur->name.len-1] == '*') cur->name.is_prefix = 1; } else if (!strcasecmp(name, "domain")) { if (cur->domain) { free_seapp_context(cur); goto err; } cur->domain = strdup(value); if (!cur->domain) { free_seapp_context(cur); goto oom; } } else if (!strcasecmp(name, "type")) { if (cur->type) { free_seapp_context(cur); goto err; } cur->type = strdup(value); if (!cur->type) { free_seapp_context(cur); goto oom; } } else if (!strcasecmp(name, "levelFromUid")) { if (cur->levelFrom) { free_seapp_context(cur); goto err; } if (!strcasecmp(value, "true")) cur->levelFrom = LEVELFROM_APP; else if (!strcasecmp(value, "false")) cur->levelFrom = LEVELFROM_NONE; else { free_seapp_context(cur); goto err; } } else if (!strcasecmp(name, "levelFrom")) { if (cur->levelFrom) { free_seapp_context(cur); goto err; } if (!strcasecmp(value, "none")) cur->levelFrom = LEVELFROM_NONE; else if (!strcasecmp(value, "app")) cur->levelFrom = LEVELFROM_APP; else if (!strcasecmp(value, "user")) cur->levelFrom = LEVELFROM_USER; else if (!strcasecmp(value, "all")) cur->levelFrom = LEVELFROM_ALL; else { free_seapp_context(cur); goto err; } } else if (!strcasecmp(name, "level")) { if (cur->level) { free_seapp_context(cur); goto err; } cur->level = strdup(value); if (!cur->level) { free_seapp_context(cur); goto oom; } } else if (!strcasecmp(name, "path")) { if (cur->path.str) { free_seapp_context(cur); goto err; } cur->path.str = strdup(value); if (!cur->path.str) { free_seapp_context(cur); goto oom; } cur->path.len = strlen(cur->path.str); if (cur->path.str[cur->path.len-1] == '*') cur->path.is_prefix = 1; } else { free_seapp_context(cur); goto err; } token = strtok_r(NULL, " \t", &saveptr); if (!token) break; } if (cur->name.str && (!cur->seinfo || !strcmp(cur->seinfo, "default"))) { selinux_log(SELINUX_ERROR, "%s: No specific seinfo value specified with name=\"%s\", on line %u: insecure configuration!\n", seapp_contexts_file[policy_index], cur->name.str, lineno); free_seapp_context(cur); goto err; } seapp_contexts[nspec] = cur; nspec++; lineno++; } qsort(seapp_contexts, nspec, sizeof(struct seapp_context *), seapp_context_cmp); if (seapp_contexts_dup) goto err; #if DEBUG { int i; for (i = 0; i < nspec; i++) { cur = seapp_contexts[i]; selinux_log(SELINUX_INFO, "%s: isSystemServer=%s isOwner=%s user=%s seinfo=%s name=%s path=%s -> domain=%s type=%s level=%s levelFrom=%s", __FUNCTION__, cur->isSystemServer ? "true" : "false", cur->isOwnerSet ? (cur->isOwner ? "true" : "false") : "null", cur->user.str, cur->seinfo, cur->name.str, cur->path.str, cur->domain, cur->type, cur->level, levelFromName[cur->levelFrom]); } } #endif ret = 0; out: fclose(fp); return ret; err: selinux_log(SELINUX_ERROR, "%s: Invalid entry on line %u\n", seapp_contexts_file[policy_index], lineno); free_seapp_contexts(); ret = -1; goto out; oom: selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); free_seapp_contexts(); ret = -1; goto out; }
static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *sb, bool isbinary, struct selabel_digest *digest) { struct saved_data *data = (struct saved_data *)rec->data; char mmap_path[PATH_MAX + 1]; int mmapfd; int rc; struct stat mmap_stat; char *addr, *str_buf; size_t len; int *stem_map; struct mmap_area *mmap_area; uint32_t i, magic, version; uint32_t entry_len, stem_map_len, regex_array_len; if (isbinary) { len = strlen(path); if (len >= sizeof(mmap_path)) return -1; strcpy(mmap_path, path); } else { rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path); if (rc >= (int)sizeof(mmap_path)) return -1; } mmapfd = open(mmap_path, O_RDONLY | O_CLOEXEC); if (mmapfd < 0) return -1; rc = fstat(mmapfd, &mmap_stat); if (rc < 0) { close(mmapfd); return -1; } /* if mmap is old, ignore it */ if (mmap_stat.st_mtime < sb->st_mtime) { close(mmapfd); return -1; } /* ok, read it in... */ len = mmap_stat.st_size; len += (sysconf(_SC_PAGE_SIZE) - 1); len &= ~(sysconf(_SC_PAGE_SIZE) - 1); mmap_area = malloc(sizeof(*mmap_area)); if (!mmap_area) { close(mmapfd); return -1; } addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, mmapfd, 0); close(mmapfd); if (addr == MAP_FAILED) { free(mmap_area); perror("mmap"); return -1; } /* save where we mmap'd the file to cleanup on close() */ mmap_area->addr = mmap_area->next_addr = addr; mmap_area->len = mmap_area->next_len = len; mmap_area->next = data->mmap_areas; data->mmap_areas = mmap_area; /* check if this looks like an fcontext file */ rc = next_entry(&magic, mmap_area, sizeof(uint32_t)); if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) return -1; /* check if this version is higher than we understand */ rc = next_entry(&version, mmap_area, sizeof(uint32_t)); if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) return -1; if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { len = strlen(pcre_version()); rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0) return -1; /* Check version lengths */ if (len != entry_len) return -1; /* Check if pcre version mismatch */ str_buf = malloc(entry_len + 1); if (!str_buf) return -1; rc = next_entry(str_buf, mmap_area, entry_len); if (rc < 0) { free(str_buf); return -1; } str_buf[entry_len] = '\0'; if ((strcmp(str_buf, pcre_version()) != 0)) { free(str_buf); return -1; } free(str_buf); } /* allocate the stems_data array */ rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !stem_map_len) return -1; /* * map indexed by the stem # in the mmap file and contains the stem * number in the data stem_arr */ stem_map = calloc(stem_map_len, sizeof(*stem_map)); if (!stem_map) return -1; for (i = 0; i < stem_map_len; i++) { char *buf; uint32_t stem_len; int newid; /* the length does not inlude the nul */ rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !stem_len) { rc = -1; goto err; } /* Check for stem_len wrap around. */ if (stem_len < UINT32_MAX) { buf = (char *)mmap_area->next_addr; /* Check if over-run before null check. */ rc = next_entry(NULL, mmap_area, (stem_len + 1)); if (rc < 0) goto err; if (buf[stem_len] != '\0') { rc = -1; goto err; } } else { rc = -1; goto err; } /* store the mapping between old and new */ newid = find_stem(data, buf, stem_len); if (newid < 0) { newid = store_stem(data, buf, stem_len); if (newid < 0) { rc = newid; goto err; } data->stem_arr[newid].from_mmap = 1; } stem_map[i] = newid; } /* allocate the regex array */ rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !regex_array_len) { rc = -1; goto err; } for (i = 0; i < regex_array_len; i++) { struct spec *spec; int32_t stem_id, meta_chars; uint32_t mode = 0, prefix_len = 0; rc = grow_specs(data); if (rc < 0) goto err; spec = &data->spec_arr[data->nspec]; spec->from_mmap = 1; spec->regcomp = 1; /* Process context */ rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; goto err; } str_buf = malloc(entry_len); if (!str_buf) { rc = -1; goto err; } rc = next_entry(str_buf, mmap_area, entry_len); if (rc < 0) goto err; if (str_buf[entry_len - 1] != '\0') { free(str_buf); rc = -1; goto err; } spec->lr.ctx_raw = str_buf; if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) { if (selabel_validate(rec, &spec->lr) < 0) { selinux_log(SELINUX_ERROR, "%s: context %s is invalid\n", mmap_path, spec->lr.ctx_raw); goto err; } } /* Process regex string */ rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; goto err; } spec->regex_str = (char *)mmap_area->next_addr; rc = next_entry(NULL, mmap_area, entry_len); if (rc < 0) goto err; if (spec->regex_str[entry_len - 1] != '\0') { rc = -1; goto err; } /* Process mode */ if (version >= SELINUX_COMPILED_FCONTEXT_MODE) rc = next_entry(&mode, mmap_area, sizeof(uint32_t)); else rc = next_entry(&mode, mmap_area, sizeof(mode_t)); if (rc < 0) goto err; spec->mode = mode; /* map the stem id from the mmap file to the data->stem_arr */ rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); if (rc < 0) goto err; if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) spec->stem_id = -1; else spec->stem_id = stem_map[stem_id]; /* retrieve the hasMetaChars bit */ rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); if (rc < 0) goto err; spec->hasMetaChars = meta_chars; /* and prefix length for use by selabel_lookup_best_match */ if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) { rc = next_entry(&prefix_len, mmap_area, sizeof(uint32_t)); if (rc < 0) goto err; spec->prefix_len = prefix_len; } /* Process regex and study_data entries */ rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; goto err; } spec->regex = (pcre *)mmap_area->next_addr; rc = next_entry(NULL, mmap_area, entry_len); if (rc < 0) goto err; /* Check that regex lengths match. pcre_fullinfo() * also validates its magic number. */ rc = pcre_fullinfo(spec->regex, NULL, PCRE_INFO_SIZE, &len); if (rc < 0 || len != entry_len) { rc = -1; goto err; } rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; goto err; } spec->lsd.study_data = (void *)mmap_area->next_addr; spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA; rc = next_entry(NULL, mmap_area, entry_len); if (rc < 0) goto err; /* Check that study data lengths match. */ rc = pcre_fullinfo(spec->regex, &spec->lsd, PCRE_INFO_STUDYSIZE, &len); if (rc < 0 || len != entry_len) { rc = -1; goto err; } data->nspec++; } rc = digest_add_specfile(digest, NULL, addr, mmap_stat.st_size, mmap_path); if (rc) goto err; err: free(stem_map); return rc; }
int selinux_android_seapp_context_reload(void) { FILE *fp = NULL; char line_buf[BUFSIZ]; char *token; unsigned lineno; struct seapp_context *cur; char *p, *name = NULL, *value = NULL, *saveptr; size_t len; int i = 0, n, ret; while ((fp==NULL) && seapp_contexts_file[i]) fp = fopen(seapp_contexts_file[i++], "r"); if (!fp) { selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__); return -1; } if (seapp_contexts) { for (n = 0; n < nspec; n++) { cur = seapp_contexts[n]; free(cur->user.str); free(cur->seinfo); free(cur->name.str); free(cur->path.str); free(cur->domain); free(cur->type); free(cur->level); free(cur->sebool); } free(seapp_contexts); } nspec = 0; while (fgets(line_buf, sizeof line_buf - 1, fp)) { p = line_buf; while (isspace(*p)) p++; if (*p == '#' || *p == 0) continue; nspec++; } seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *)); if (!seapp_contexts) goto oom; rewind(fp); nspec = 0; lineno = 1; while (fgets(line_buf, sizeof line_buf - 1, fp)) { len = strlen(line_buf); if (line_buf[len - 1] == '\n') line_buf[len - 1] = 0; p = line_buf; while (isspace(*p)) p++; if (*p == '#' || *p == 0) continue; cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context)); if (!cur) goto oom; token = strtok_r(p, " \t", &saveptr); if (!token) goto err; while (1) { name = token; value = strchr(name, '='); if (!value) goto err; *value++ = 0; if (!strcasecmp(name, "isSystemServer")) { if (!strcasecmp(value, "true")) cur->isSystemServer = 1; else if (!strcasecmp(value, "false")) cur->isSystemServer = 0; else { goto err; } } else if (!strcasecmp(name, "user")) { cur->user.str = strdup(value); if (!cur->user.str) goto oom; cur->user.len = strlen(cur->user.str); if (cur->user.str[cur->user.len-1] == '*') cur->user.is_prefix = 1; } else if (!strcasecmp(name, "seinfo")) { cur->seinfo = strdup(value); if (!cur->seinfo) goto oom; } else if (!strcasecmp(name, "name")) { cur->name.str = strdup(value); if (!cur->name.str) goto oom; cur->name.len = strlen(cur->name.str); if (cur->name.str[cur->name.len-1] == '*') cur->name.is_prefix = 1; } else if (!strcasecmp(name, "domain")) { cur->domain = strdup(value); if (!cur->domain) goto oom; } else if (!strcasecmp(name, "type")) { cur->type = strdup(value); if (!cur->type) goto oom; } else if (!strcasecmp(name, "levelFromUid")) { if (!strcasecmp(value, "true")) cur->levelFrom = LEVELFROM_APP; else if (!strcasecmp(value, "false")) cur->levelFrom = LEVELFROM_NONE; else { goto err; } } else if (!strcasecmp(name, "levelFrom")) { if (!strcasecmp(value, "none")) cur->levelFrom = LEVELFROM_NONE; else if (!strcasecmp(value, "app")) cur->levelFrom = LEVELFROM_APP; else if (!strcasecmp(value, "user")) cur->levelFrom = LEVELFROM_USER; else if (!strcasecmp(value, "all")) cur->levelFrom = LEVELFROM_ALL; else { goto err; } } else if (!strcasecmp(name, "level")) { cur->level = strdup(value); if (!cur->level) goto oom; } else if (!strcasecmp(name, "path")) { cur->path.str = strdup(value); if (!cur->path.str) goto oom; cur->path.len = strlen(cur->path.str); if (cur->path.str[cur->path.len-1] == '*') cur->path.is_prefix = 1; } else if (!strcasecmp(name, "sebool")) { cur->sebool = strdup(value); if (!cur->sebool) goto oom; } else goto err; token = strtok_r(NULL, " \t", &saveptr); if (!token) break; } seapp_contexts[nspec] = cur; nspec++; lineno++; } qsort(seapp_contexts, nspec, sizeof(struct seapp_context *), seapp_context_cmp); #if DEBUG { int i; for (i = 0; i < nspec; i++) { cur = seapp_contexts[i]; selinux_log(SELINUX_INFO, "%s: isSystemServer=%s user=%s seinfo=%s name=%s path=%s sebool=%s -> domain=%s type=%s level=%s levelFrom=%s", __FUNCTION__, cur->isSystemServer ? "true" : "false", cur->user.str, cur->seinfo, cur->name.str, cur->path.str, cur->sebool, cur->domain, cur->type, cur->level, levelFromName[cur->levelFrom]); } } #endif ret = 0; out: fclose(fp); return ret; err: selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n", __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value); ret = -1; goto out; oom: selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); ret = -1; goto out; }
static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec, const char *path) { struct saved_data *data = (struct saved_data *)rec->data; int rc; char *addr, *str_buf; int *stem_map; struct mmap_area *mmap_area; uint32_t i, magic, version; uint32_t entry_len, stem_map_len, regex_array_len; const char *reg_version; const char *reg_arch; char reg_arch_matches = 0; mmap_area = malloc(sizeof(*mmap_area)); if (!mmap_area) { return -1; } addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0); if (addr == MAP_FAILED) { free(mmap_area); perror("mmap"); return -1; } /* save where we mmap'd the file to cleanup on close() */ mmap_area->addr = mmap_area->next_addr = addr; mmap_area->len = mmap_area->next_len = len; mmap_area->next = data->mmap_areas; data->mmap_areas = mmap_area; /* check if this looks like an fcontext file */ rc = next_entry(&magic, mmap_area, sizeof(uint32_t)); if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) return -1; /* check if this version is higher than we understand */ rc = next_entry(&version, mmap_area, sizeof(uint32_t)); if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) return -1; reg_version = regex_version(); if (!reg_version) return -1; reg_arch = regex_arch_string(); if (!reg_arch) return -1; if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { len = strlen(reg_version); rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0) return -1; /* Check version lengths */ if (len != entry_len) return -1; /* Check if regex version mismatch */ str_buf = malloc(entry_len + 1); if (!str_buf) return -1; rc = next_entry(str_buf, mmap_area, entry_len); if (rc < 0) { free(str_buf); return -1; } str_buf[entry_len] = '\0'; if ((strcmp(str_buf, reg_version) != 0)) { free(str_buf); return -1; } free(str_buf); if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) { len = strlen(reg_arch); rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0) return -1; /* Check arch string lengths */ if (len != entry_len) { /* * Skip the entry and conclude that we have * a mismatch, which is not fatal. */ next_entry(NULL, mmap_area, entry_len); goto end_arch_check; } /* Check if arch string mismatch */ str_buf = malloc(entry_len + 1); if (!str_buf) return -1; rc = next_entry(str_buf, mmap_area, entry_len); if (rc < 0) { free(str_buf); return -1; } str_buf[entry_len] = '\0'; reg_arch_matches = strcmp(str_buf, reg_arch) == 0; free(str_buf); } } end_arch_check: /* allocate the stems_data array */ rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t)); if (rc < 0) return -1; /* * map indexed by the stem # in the mmap file and contains the stem * number in the data stem_arr */ stem_map = calloc(stem_map_len, sizeof(*stem_map)); if (!stem_map) return -1; for (i = 0; i < stem_map_len; i++) { char *buf; uint32_t stem_len; int newid; /* the length does not inlude the nul */ rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !stem_len) { rc = -1; goto out; } /* Check for stem_len wrap around. */ if (stem_len < UINT32_MAX) { buf = (char *)mmap_area->next_addr; /* Check if over-run before null check. */ rc = next_entry(NULL, mmap_area, (stem_len + 1)); if (rc < 0) goto out; if (buf[stem_len] != '\0') { rc = -1; goto out; } } else { rc = -1; goto out; } /* store the mapping between old and new */ newid = find_stem(data, buf, stem_len); if (newid < 0) { newid = store_stem(data, buf, stem_len); if (newid < 0) { rc = newid; goto out; } data->stem_arr[newid].from_mmap = 1; } stem_map[i] = newid; } /* allocate the regex array */ rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !regex_array_len) { rc = -1; goto out; } for (i = 0; i < regex_array_len; i++) { struct spec *spec; int32_t stem_id, meta_chars; uint32_t mode = 0, prefix_len = 0; rc = grow_specs(data); if (rc < 0) goto out; spec = &data->spec_arr[data->nspec]; spec->from_mmap = 1; /* Process context */ rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; goto out; } str_buf = malloc(entry_len); if (!str_buf) { rc = -1; goto out; } rc = next_entry(str_buf, mmap_area, entry_len); if (rc < 0) { free(str_buf); goto out; } if (str_buf[entry_len - 1] != '\0') { free(str_buf); rc = -1; goto out; } spec->lr.ctx_raw = str_buf; if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) { if (selabel_validate(rec, &spec->lr) < 0) { selinux_log(SELINUX_ERROR, "%s: context %s is invalid\n", path, spec->lr.ctx_raw); goto out; } } /* Process regex string */ rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); if (rc < 0 || !entry_len) { rc = -1; goto out; } spec->regex_str = (char *)mmap_area->next_addr; rc = next_entry(NULL, mmap_area, entry_len); if (rc < 0) goto out; if (spec->regex_str[entry_len - 1] != '\0') { rc = -1; goto out; } /* Process mode */ if (version >= SELINUX_COMPILED_FCONTEXT_MODE) rc = next_entry(&mode, mmap_area, sizeof(uint32_t)); else rc = next_entry(&mode, mmap_area, sizeof(mode_t)); if (rc < 0) goto out; spec->mode = mode; /* map the stem id from the mmap file to the data->stem_arr */ rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); if (rc < 0) goto out; if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) spec->stem_id = -1; else spec->stem_id = stem_map[stem_id]; /* retrieve the hasMetaChars bit */ rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); if (rc < 0) goto out; spec->hasMetaChars = meta_chars; /* and prefix length for use by selabel_lookup_best_match */ if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) { rc = next_entry(&prefix_len, mmap_area, sizeof(uint32_t)); if (rc < 0) goto out; spec->prefix_len = prefix_len; } rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches, &spec->regex_compiled); if (rc < 0) goto out; __pthread_mutex_init(&spec->regex_lock, NULL); data->nspec++; } rc = 0; out: free(stem_map); return rc; }
/* Called by selinux_restorecon_xattr(3) to build a linked list of entries. */ static int add_xattr_entry(const char *directory, bool delete_nonmatch, bool delete_all) { char *sha1_buf = NULL; unsigned char *xattr_value = NULL; ssize_t xattr_size; size_t i; int rc, digest_result; struct dir_xattr *new_entry; if (!directory) { errno = EINVAL; return -1; } xattr_value = malloc(fc_digest_len); if (!xattr_value) goto oom; xattr_size = getxattr(directory, RESTORECON_LAST, xattr_value, fc_digest_len); if (xattr_size < 0) { free(xattr_value); return 1; } /* Convert entry to a hex encoded string. */ sha1_buf = malloc(xattr_size * 2 + 1); if (!sha1_buf) { free(xattr_value); goto oom; } for (i = 0; i < (size_t)xattr_size; i++) sprintf((&sha1_buf[i * 2]), "%02x", xattr_value[i]); rc = memcmp(fc_digest, xattr_value, fc_digest_len); digest_result = rc ? NOMATCH : MATCH; if ((delete_nonmatch && rc != 0) || delete_all) { digest_result = rc ? DELETED_NOMATCH : DELETED_MATCH; rc = removexattr(directory, RESTORECON_LAST); if (rc) { selinux_log(SELINUX_ERROR, "Error: %s removing xattr \"%s\" from: %s\n", strerror(errno), RESTORECON_LAST, directory); digest_result = ERROR; } } free(xattr_value); /* Now add entries to link list. */ new_entry = malloc(sizeof(struct dir_xattr)); if (!new_entry) goto oom; new_entry->next = NULL; new_entry->directory = strdup(directory); if (!new_entry->directory) goto oom; new_entry->digest = strdup(sha1_buf); if (!new_entry->digest) goto oom; new_entry->result = digest_result; if (!dir_xattr_list) { dir_xattr_list = new_entry; dir_xattr_last = new_entry; } else { dir_xattr_last->next = new_entry; dir_xattr_last = new_entry; } free(sha1_buf); return 0; oom: selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); return -1; }
/* * This is called once when selinux_restorecon() is first called. * Searches /proc/mounts for all file systems that do not support extended * attributes and adds them to the exclude directory table. File systems * that support security labels have the seclabel option, return * approximate total file count. */ static int exclude_non_seclabel_mounts(void) { struct utsname uts; FILE *fp; size_t len; ssize_t num; int index = 0, found = 0, nfile = 0; char *mount_info[4]; char *buf = NULL, *item; /* Check to see if the kernel supports seclabel */ if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0) return 0; fp = fopen("/proc/mounts", "r"); if (!fp) return 0; while ((num = getline(&buf, &len, fp)) != -1) { found = 0; index = 0; item = strtok(buf, " "); while (item != NULL) { mount_info[index] = item; if (index == 3) break; index++; item = strtok(NULL, " "); } if (index < 3) { selinux_log(SELINUX_ERROR, "/proc/mounts record \"%s\" has incorrect format.\n", buf); continue; } /* Remove pre-existing entry */ remove_exclude(mount_info[1]); item = strtok(mount_info[3], ","); while (item != NULL) { if (strcmp(item, "seclabel") == 0) { found = 1; nfile += file_system_count(mount_info[1]); break; } item = strtok(NULL, ","); } /* Exclude mount points without the seclabel option */ if (!found) { if (add_exclude(mount_info[1], !CALLER_EXCLUDED) && errno == ENOMEM) assert(0); } } free(buf); fclose(fp); /* return estimated #Files + 5% for directories and hard links */ return nfile * 1.05; }
static int process_line(struct selabel_handle *rec, const char *path, const char *prefix, char *line_buf, int pass, unsigned lineno) { int items, len; char buf1[BUFSIZ], buf2[BUFSIZ], buf3[BUFSIZ]; char *buf_p, *regex = buf1, *type = buf2, *context = buf3; struct saved_data *data = (struct saved_data *)rec->data; spec_t *spec_arr = data->spec_arr; unsigned int nspec = data->nspec; len = strlen(line_buf); if (line_buf[len - 1] == '\n') line_buf[len - 1] = 0; buf_p = line_buf; while (isspace(*buf_p)) buf_p++; /* Skip comment lines and empty lines. */ if (*buf_p == '#' || *buf_p == 0) return 0; items = sscanf(line_buf, "%255s %255s %255s", regex, type, context); if (items < 2) { selinux_log(SELINUX_WARNING, "%s: line %d is missing fields, skipping\n", path, lineno); return 0; } else if (items == 2) { /* The type field is optional. */ context = type; type = NULL; } len = get_stem_from_spec(regex); if (len && prefix && strncmp(prefix, regex, len)) { /* Stem of regex does not match requested prefix, discard. */ return 0; } if (pass == 1) { /* On the second pass, process and store the specification in spec. */ const char *errbuf = NULL; spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); spec_arr[nspec].regex_str = strdup(regex); if (!spec_arr[nspec].regex_str) { selinux_log(SELINUX_WARNING, "%s: out of memory at line %d on regex %s\n", path, lineno, regex); return -1; } if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) { selinux_log(SELINUX_WARNING, "%s: line %d has invalid regex %s: %s\n", path, lineno, regex, (errbuf ? errbuf : "out of memory")); } /* Convert the type string to a mode format */ spec_arr[nspec].mode = 0; if (!type) goto skip_type; spec_arr[nspec].type_str = strdup(type); len = strlen(type); if (type[0] != '-' || len != 2) { selinux_log(SELINUX_WARNING, "%s: line %d has invalid file type %s\n", path, lineno, type); return 0; } switch (type[1]) { case 'b': spec_arr[nspec].mode = S_IFBLK; break; case 'c': spec_arr[nspec].mode = S_IFCHR; break; case 'd': spec_arr[nspec].mode = S_IFDIR; break; case 'p': spec_arr[nspec].mode = S_IFIFO; break; case 'l': spec_arr[nspec].mode = S_IFLNK; break; case 's': spec_arr[nspec].mode = S_IFSOCK; break; case '-': spec_arr[nspec].mode = S_IFREG; break; default: selinux_log(SELINUX_WARNING, "%s: line %d has invalid file type %s\n", path, lineno, type); return 0; } skip_type: spec_arr[nspec].lr.ctx_raw = strdup(context); if (strcmp(context, "<<none>>") && rec->validating) { if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { selinux_log(SELINUX_WARNING, "%s: line %d has invalid context %s\n", path, lineno, spec_arr[nspec].lr.ctx_raw); } } /* Determine if specification has * any meta characters in the RE */ spec_hasMetaChars(&spec_arr[nspec]); } data->nspec = ++nspec; return 0; }
static int seapp_context_lookup(enum seapp_kind kind, uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname, const char *path, context_t ctx) { const char *username = NULL; struct seapp_context *cur = NULL; int i; size_t n; uid_t userid; uid_t appid; __selinux_once(once, seapp_context_init); userid = uid / AID_USER; appid = uid % AID_USER; if (appid < AID_APP) { for (n = 0; n < android_id_count; n++) { if (android_ids[n].aid == appid) { username = android_ids[n].name; break; } } if (!username) goto err; } else if (appid < AID_ISOLATED_START) { username = "******"; appid -= AID_APP; } else { username = "******"; appid -= AID_ISOLATED_START; } if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID) goto err; for (i = 0; i < nspec; i++) { cur = seapp_contexts[i]; if (cur->isSystemServer != isSystemServer) continue; if (cur->user.str) { if (cur->user.is_prefix) { if (strncasecmp(username, cur->user.str, cur->user.len-1)) continue; } else { if (strcasecmp(username, cur->user.str)) continue; } } if (cur->seinfo) { if (!seinfo || strcasecmp(seinfo, cur->seinfo)) continue; } if (cur->name.str) { if(!pkgname) continue; if (cur->name.is_prefix) { if (strncasecmp(pkgname, cur->name.str, cur->name.len-1)) continue; } else { if (strcasecmp(pkgname, cur->name.str)) continue; } } if (cur->path.str) { if (!path) continue; if (cur->path.is_prefix) { if (strncmp(path, cur->path.str, cur->path.len-1)) continue; } else { if (strcmp(path, cur->path.str)) continue; } } if (kind == SEAPP_TYPE && !cur->type) continue; else if (kind == SEAPP_DOMAIN && !cur->domain) continue; if (cur->sebool) { int value = security_get_boolean_active(cur->sebool); if (value == 0) continue; else if (value == -1) { selinux_log(SELINUX_ERROR, \ "Could not find boolean: %s ", cur->sebool); goto err; } } if (kind == SEAPP_TYPE) { if (context_type_set(ctx, cur->type)) goto oom; } else if (kind == SEAPP_DOMAIN) { if (context_type_set(ctx, cur->domain)) goto oom; } if (cur->levelFrom != LEVELFROM_NONE) { char level[255]; switch (cur->levelFrom) { case LEVELFROM_APP: snprintf(level, sizeof level, "s0:c%u,c%u", appid & 0xff, 256 + (appid>>8 & 0xff)); break; case LEVELFROM_USER: snprintf(level, sizeof level, "s0:c%u,c%u", 512 + (userid & 0xff), 768 + (userid>>8 & 0xff)); break; case LEVELFROM_ALL: snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u", appid & 0xff, 256 + (appid>>8 & 0xff), 512 + (userid & 0xff), 768 + (userid>>8 & 0xff)); break; default: goto err; } if (context_range_set(ctx, level)) goto oom; } else if (cur->level) {
static int seapp_context_cmp(const void *A, const void *B) { const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A; const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B; const struct seapp_context *s1 = *sp1, *s2 = *sp2; bool dup; /* Give precedence to isSystemServer=true. */ if (s1->isSystemServer != s2->isSystemServer) return (s1->isSystemServer ? -1 : 1); /* Give precedence to a specified isOwner= over an unspecified isOwner=. */ if (s1->isOwnerSet != s2->isOwnerSet) return (s1->isOwnerSet ? -1 : 1); /* Give precedence to a specified user= over an unspecified user=. */ if (s1->user.str && !s2->user.str) return -1; if (!s1->user.str && s2->user.str) return 1; if (s1->user.str) { /* Give precedence to a fixed user= string over a prefix. */ if (s1->user.is_prefix != s2->user.is_prefix) return (s2->user.is_prefix ? -1 : 1); /* Give precedence to a longer prefix over a shorter prefix. */ if (s1->user.is_prefix && s1->user.len != s2->user.len) return (s1->user.len > s2->user.len) ? -1 : 1; } /* Give precedence to a specified seinfo= over an unspecified seinfo=. */ if (s1->seinfo && !s2->seinfo) return -1; if (!s1->seinfo && s2->seinfo) return 1; /* Give precedence to a specified name= over an unspecified name=. */ if (s1->name.str && !s2->name.str) return -1; if (!s1->name.str && s2->name.str) return 1; if (s1->name.str) { /* Give precedence to a fixed name= string over a prefix. */ if (s1->name.is_prefix != s2->name.is_prefix) return (s2->name.is_prefix ? -1 : 1); /* Give precedence to a longer prefix over a shorter prefix. */ if (s1->name.is_prefix && s1->name.len != s2->name.len) return (s1->name.len > s2->name.len) ? -1 : 1; } /* Give precedence to a specified path= over an unspecified path=. */ if (s1->path.str && !s2->path.str) return -1; if (!s1->path.str && s2->path.str) return 1; if (s1->path.str) { /* Give precedence to a fixed path= string over a prefix. */ if (s1->path.is_prefix != s2->path.is_prefix) return (s2->path.is_prefix ? -1 : 1); /* Give precedence to a longer prefix over a shorter prefix. */ if (s1->path.is_prefix && s1->path.len != s2->path.len) return (s1->path.len > s2->path.len) ? -1 : 1; } /* * Check for a duplicated entry on the input selectors. * We already compared isSystemServer, isOwnerSet, and isOwner above. * We also have already checked that both entries specify the same * string fields, so if s1 has a non-NULL string, then so does s2. */ dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) && (!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) && (!s1->name.str || !strcmp(s1->name.str, s2->name.str)) && (!s1->path.str || !strcmp(s1->path.str, s2->path.str)); if (dup) { seapp_contexts_dup = true; selinux_log(SELINUX_ERROR, "seapp_contexts: Duplicated entry\n"); if (s1->user.str) selinux_log(SELINUX_ERROR, " user=%s\n", s1->user.str); if (s1->seinfo) selinux_log(SELINUX_ERROR, " seinfo=%s\n", s1->seinfo); if (s1->name.str) selinux_log(SELINUX_ERROR, " name=%s\n", s1->name.str); if (s1->path.str) selinux_log(SELINUX_ERROR, " path=%s\n", s1->path.str); } /* Anything else has equal precedence. */ return 0; }