On Tue, Dec 17, 2024 at 2:46 PM James Carter <jwcart2@xxxxxxxxx> wrote: > > On Thu, Dec 12, 2024 at 4:15 PM Christian Göttsche > <cgoettsche@xxxxxxxxxxxxx> wrote: > > > > From: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> > > > > Prior the recent selabel_file(5) rework regular expressions for a > > certain stem where matched in the order given by the input. > > The Reference and Fedora Policy as well as CIL and libsemanage pre-sort > > the file context definitions based on the prefix stem length, so this > > ordering was adopted. > > > > Do not alter the order by the input of regex specifications, and search > > on matches on regex specifications in in parent nodes, which might > > contain specifications with definitions defined later in the source > > file. > > This restores backward compatibility, especially for Android. > > > > Reported-by: Takaya Saeki <takayas@xxxxxxxxxxxx> > > Closes: https://lore.kernel.org/selinux/CAH9xa6eFO6BNeGko90bsq8CuDba9eO+qdDoF+7zfyAUHEDpH9g@xxxxxxxxxxxxxx/ > > Fixes: 92306da ("libselinux: rework selabel_file(5) database") > > Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> > > --- > > v2: > > - search parent nodes for later regex specs > > The pre-compiled fcontext format changed, due to the addition of the > > line number for regex specs. Thus files generated with 3.8-rc1 > > will fail to load, but it won't result in wrong lookup results like > > the v1 patch. > > Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> > > Acked-by: James Carter <jwcart2@xxxxxxxxx> > Merged. Thanks, Jim > > --- > > libselinux/src/label_file.c | 331 ++++++++++++++------------ > > libselinux/src/label_file.h | 47 +--- > > libselinux/utils/sefcontext_compile.c | 11 +- > > 3 files changed, 202 insertions(+), 187 deletions(-) > > > > diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c > > index 80a7c5ab..56e20949 100644 > > --- a/libselinux/src/label_file.c > > +++ b/libselinux/src/label_file.c > > @@ -87,14 +87,14 @@ void sort_spec_node(struct spec_node *node, struct spec_node *parent) > > > > node->parent = parent; > > > > - /* Sort for comparison support and binary search lookup */ > > + /* > > + * Sort for comparison support and binary search lookup, > > + * except for regex specs which are matched in reverse input order. > > + */ > > > > if (node->literal_specs_num > 1) > > qsort(node->literal_specs, node->literal_specs_num, sizeof(struct literal_spec), compare_literal_spec); > > > > - if (node->regex_specs_num > 1) > > - qsort(node->regex_specs, node->regex_specs_num, sizeof(struct regex_spec), compare_regex_spec); > > - > > if (node->children_num > 1) > > qsort(node->children, node->children_num, sizeof(struct spec_node), compare_spec_node); > > > > @@ -144,36 +144,38 @@ static int nodups_spec_node(const struct spec_node *node, const char *path) > > > > if (node->regex_specs_num > 1) { > > for (uint32_t i = 0; i < node->regex_specs_num - 1; i++) { > > - const struct regex_spec *node1 = &node->regex_specs[i]; > > - const struct regex_spec *node2 = &node->regex_specs[i+1]; > > + for (uint32_t j = i; j < node->regex_specs_num - 1; j++) { > > + const struct regex_spec *node1 = &node->regex_specs[i]; > > + const struct regex_spec *node2 = &node->regex_specs[j + 1]; > > > > - if (node1->prefix_len != node2->prefix_len) > > - continue; > > + if (node1->prefix_len != node2->prefix_len) > > + continue; > > > > - if (strcmp(node1->regex_str, node2->regex_str) != 0) > > - continue; > > + if (strcmp(node1->regex_str, node2->regex_str) != 0) > > + continue; > > > > - if (node1->file_kind != LABEL_FILE_KIND_ALL && node2->file_kind != LABEL_FILE_KIND_ALL && node1->file_kind != node2->file_kind) > > - continue; > > + if (node1->file_kind != LABEL_FILE_KIND_ALL && node2->file_kind != LABEL_FILE_KIND_ALL && node1->file_kind != node2->file_kind) > > + continue; > > > > - rc = -1; > > - errno = EINVAL; > > - if (strcmp(node1->lr.ctx_raw, node2->lr.ctx_raw) != 0) { > > - COMPAT_LOG > > - (SELINUX_ERROR, > > - "%s: Multiple different specifications for %s %s (%s and %s).\n", > > - path, > > - file_kind_to_string(node1->file_kind), > > - node1->regex_str, > > - node1->lr.ctx_raw, > > - node2->lr.ctx_raw); > > - } else { > > - COMPAT_LOG > > - (SELINUX_ERROR, > > - "%s: Multiple same specifications for %s %s.\n", > > - path, > > - file_kind_to_string(node1->file_kind), > > - node1->regex_str); > > + rc = -1; > > + errno = EINVAL; > > + if (strcmp(node1->lr.ctx_raw, node2->lr.ctx_raw) != 0) { > > + COMPAT_LOG > > + (SELINUX_ERROR, > > + "%s: Multiple different specifications for %s %s (%s and %s).\n", > > + path, > > + file_kind_to_string(node1->file_kind), > > + node1->regex_str, > > + node1->lr.ctx_raw, > > + node2->lr.ctx_raw); > > + } else { > > + COMPAT_LOG > > + (SELINUX_ERROR, > > + "%s: Multiple same specifications for %s %s.\n", > > + path, > > + file_kind_to_string(node1->file_kind), > > + node1->regex_str); > > + } > > } > > } > > } > > @@ -190,7 +192,8 @@ static int nodups_spec_node(const struct spec_node *node, const char *path) > > } > > > > FUZZ_EXTERN int process_text_file(FILE *fp, const char *prefix, > > - struct selabel_handle *rec, const char *path) > > + struct selabel_handle *rec, const char *path, > > + uint8_t inputno) > > { > > int rc; > > size_t line_len; > > @@ -199,7 +202,7 @@ FUZZ_EXTERN int process_text_file(FILE *fp, const char *prefix, > > char *line_buf = NULL; > > > > while ((nread = getline(&line_buf, &line_len, fp)) > 0) { > > - rc = process_line(rec, path, prefix, line_buf, nread, ++lineno); > > + rc = process_line(rec, path, prefix, line_buf, nread, inputno, ++lineno); > > if (rc) > > goto out; > > } > > @@ -568,9 +571,10 @@ static int load_mmap_literal_spec(struct mmap_area *mmap_area, bool validating, > > } > > > > static int load_mmap_regex_spec(struct mmap_area *mmap_area, bool validating, bool do_load_precompregex, > > + uint8_t inputno, > > struct regex_spec *rspec, const struct context_array *ctx_array) > > { > > - uint32_t data_u32, ctx_id; > > + uint32_t data_u32, ctx_id, lineno; > > uint16_t data_u16, regex_len; > > uint8_t data_u8; > > int rc; > > @@ -600,6 +604,20 @@ static int load_mmap_regex_spec(struct mmap_area *mmap_area, bool validating, bo > > rspec->lr.validated = true; > > > > > > + /* > > + * Read line number in source file. > > + */ > > + rc = next_entry(&data_u32, mmap_area, sizeof(uint32_t)); > > + if (rc < 0) > > + return -1; > > + lineno = be32toh(data_u32); > > + > > + if (lineno == 0 || lineno == UINT32_MAX) > > + return -1; > > + rspec->lineno = lineno; > > + rspec->inputno = inputno; > > + > > + > > /* > > * Read original regex > > */ > > @@ -649,14 +667,14 @@ static int load_mmap_regex_spec(struct mmap_area *mmap_area, bool validating, bo > > if (rc < 0) > > return -1; > > > > - __pthread_mutex_init(&rspec->regex_lock, NULL); > > > > + __pthread_mutex_init(&rspec->regex_lock, NULL); > > > > return 0; > > } > > > > static int load_mmap_spec_node(struct mmap_area *mmap_area, const char *path, bool validating, bool do_load_precompregex, > > - struct spec_node *node, bool is_root, const struct context_array *ctx_array) > > + struct spec_node *node, bool is_root, uint8_t inputno, const struct context_array *ctx_array) > > { > > uint32_t data_u32, lspec_num, rspec_num, children_num; > > uint16_t data_u16, stem_len; > > @@ -744,7 +762,7 @@ static int load_mmap_spec_node(struct mmap_area *mmap_area, const char *path, bo > > node->regex_specs_alloc = rspec_num; > > > > for (uint32_t i = 0; i < rspec_num; i++) { > > - rc = load_mmap_regex_spec(mmap_area, validating, do_load_precompregex, &node->regex_specs[i], ctx_array); > > + rc = load_mmap_regex_spec(mmap_area, validating, do_load_precompregex, inputno, &node->regex_specs[i], ctx_array); > > if (rc) > > return -1; > > } > > @@ -776,7 +794,7 @@ static int load_mmap_spec_node(struct mmap_area *mmap_area, const char *path, bo > > node->children_alloc = children_num; > > > > for (uint32_t i = 0; i < children_num; i++) { > > - rc = load_mmap_spec_node(mmap_area, path, validating, do_load_precompregex, &node->children[i], false, ctx_array); > > + rc = load_mmap_spec_node(mmap_area, path, validating, do_load_precompregex, &node->children[i], false, inputno, ctx_array); > > if (rc) > > return -1; > > > > @@ -796,7 +814,7 @@ static int load_mmap_spec_node(struct mmap_area *mmap_area, const char *path, bo > > } > > > > FUZZ_EXTERN int load_mmap(FILE *fp, const size_t len, struct selabel_handle *rec, > > - const char *path) > > + const char *path, uint8_t inputno) > > { > > struct saved_data *data = rec->data; > > struct spec_node *root = NULL; > > @@ -952,6 +970,7 @@ end_arch_check: > > rc = load_mmap_spec_node(mmap_area, path, rec->validating, > > reg_version_matches && reg_arch_matches, > > root, true, > > + inputno, > > &ctx_array); > > if (rc) > > goto err; > > @@ -1142,7 +1161,8 @@ static FILE *open_file(const char *path, const char *suffix, > > static int process_file(const char *path, const char *suffix, > > struct selabel_handle *rec, > > const char *prefix, > > - struct selabel_digest *digest) > > + struct selabel_digest *digest, > > + uint8_t inputno) > > { > > int rc; > > unsigned int i; > > @@ -1171,9 +1191,9 @@ static int process_file(const char *path, const char *suffix, > > COMPAT_LOG(SELINUX_INFO, "%s: Old compiled fcontext format, skipping\n", found_path); > > errno = EINVAL; > > } else if (rc == 1) { > > - rc = load_mmap(fp, sb.st_size, rec, found_path); > > + rc = load_mmap(fp, sb.st_size, rec, found_path, inputno); > > } else { > > - rc = process_text_file(fp, prefix, rec, found_path); > > + rc = process_text_file(fp, prefix, rec, found_path, inputno); > > } > > > > if (!rc) > > @@ -1434,7 +1454,7 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts, > > /* > > * The do detailed validation of the input and fill the spec array > > */ > > - status = process_file(path, NULL, rec, prefix, rec->digest); > > + status = process_file(path, NULL, rec, prefix, rec->digest, 0); > > if (status) > > goto finish; > > > > @@ -1448,12 +1468,12 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts, > > > > if (!baseonly) { > > status = process_file(path, "homedirs", rec, prefix, > > - rec->digest); > > + rec->digest, 1); > > if (status && errno != ENOENT) > > goto finish; > > > > status = process_file(path, "local", rec, prefix, > > - rec->digest); > > + rec->digest, 2); > > if (status && errno != ENOENT) > > goto finish; > > } > > @@ -1579,77 +1599,84 @@ static struct lookup_result *lookup_check_node(struct spec_node *node, const cha > > { > > struct lookup_result *result = NULL; > > struct lookup_result **next = &result; > > + struct lookup_result *child_regex_match = NULL; > > + uint8_t child_regex_match_inputno = 0; /* initialize to please GCC */ > > + uint32_t child_regex_match_lineno = 1; /* initialize to please GCC */ > > size_t key_len = strlen(key); > > > > assert(!(find_all && buf != NULL)); > > > > for (struct spec_node *n = node; n; n = n->parent) { > > > > - uint32_t literal_idx = search_literal_spec(n->literal_specs, n->literal_specs_num, key, key_len, partial); > > - if (literal_idx != (uint32_t)-1) { > > - do { > > - struct literal_spec *lspec = &n->literal_specs[literal_idx]; > > + if (n == node) { > > + uint32_t literal_idx = search_literal_spec(n->literal_specs, n->literal_specs_num, key, key_len, partial); > > + if (literal_idx != (uint32_t)-1) { > > + do { > > + struct literal_spec *lspec = &n->literal_specs[literal_idx]; > > > > - if (file_kind == LABEL_FILE_KIND_ALL || lspec->file_kind == LABEL_FILE_KIND_ALL || lspec->file_kind == file_kind) { > > - struct lookup_result *r; > > + if (file_kind == LABEL_FILE_KIND_ALL || lspec->file_kind == LABEL_FILE_KIND_ALL || lspec->file_kind == file_kind) { > > + struct lookup_result *r; > > > > #ifdef __ATOMIC_RELAXED > > - __atomic_store_n(&lspec->any_matches, true, __ATOMIC_RELAXED); > > + __atomic_store_n(&lspec->any_matches, true, __ATOMIC_RELAXED); > > #else > > #error "Please use a compiler that supports __atomic builtins" > > #endif > > > > - if (strcmp(lspec->lr.ctx_raw, "<<none>>") == 0) { > > - free_lookup_result(result); > > - errno = ENOENT; > > - return NULL; > > - } > > + if (strcmp(lspec->lr.ctx_raw, "<<none>>") == 0) { > > + errno = ENOENT; > > + goto fail; > > + } > > > > - if (likely(buf)) { > > - r = buf; > > - } else { > > - r = malloc(sizeof(*r)); > > - if (!r) { > > - free_lookup_result(result); > > - return NULL; > > + if (likely(buf)) { > > + r = buf; > > + } else { > > + r = malloc(sizeof(*r)); > > + if (!r) > > + goto fail; > > } > > - } > > > > - *r = (struct lookup_result) { > > - .regex_str = lspec->regex_str, > > - .prefix_len = lspec->prefix_len, > > - .file_kind = lspec->file_kind, > > - .lr = &lspec->lr, > > - .has_meta_chars = false, > > - .next = NULL, > > - }; > > + *r = (struct lookup_result) { > > + .regex_str = lspec->regex_str, > > + .prefix_len = lspec->prefix_len, > > + .file_kind = lspec->file_kind, > > + .lr = &lspec->lr, > > + .has_meta_chars = false, > > + .next = NULL, > > + }; > > > > - if (likely(!find_all)) > > - return r; > > + if (likely(!find_all)) > > + return r; > > > > - *next = r; > > - next = &r->next; > > - } > > + *next = r; > > + next = &r->next; > > + } > > > > - literal_idx++; > > - } while (literal_idx < n->literal_specs_num && > > - (partial ? (strncmp(n->literal_specs[literal_idx].literal_match, key, key_len) == 0) > > - : (strcmp(n->literal_specs[literal_idx].literal_match, key) == 0))); > > + literal_idx++; > > + } while (literal_idx < n->literal_specs_num && > > + (partial ? (strncmp(n->literal_specs[literal_idx].literal_match, key, key_len) == 0) > > + : (strcmp(n->literal_specs[literal_idx].literal_match, key) == 0))); > > + } > > } > > > > - for (uint32_t i = 0; i < n->regex_specs_num; i++) { > > - struct regex_spec *rspec = &n->regex_specs[i]; > > + for (uint32_t i = n->regex_specs_num; i > 0; i--) { > > + /* search in reverse order */ > > + struct regex_spec *rspec = &n->regex_specs[i - 1]; > > const char *errbuf = NULL; > > int rc; > > > > + if (child_regex_match && > > + (rspec->inputno < child_regex_match_inputno || > > + (rspec->inputno == child_regex_match_inputno && rspec->lineno < child_regex_match_lineno))) > > + break; > > + > > if (file_kind != LABEL_FILE_KIND_ALL && rspec->file_kind != LABEL_FILE_KIND_ALL && file_kind != rspec->file_kind) > > continue; > > > > if (compile_regex(rspec, &errbuf) < 0) { > > COMPAT_LOG(SELINUX_ERROR, "Failed to compile regular expression '%s': %s\n", > > rspec->regex_str, errbuf); > > - free_lookup_result(result); > > - return NULL; > > + goto fail; > > } > > > > rc = regex_match(rspec->regex, key, partial); > > @@ -1665,19 +1692,18 @@ static struct lookup_result *lookup_check_node(struct spec_node *node, const cha > > } > > > > if (strcmp(rspec->lr.ctx_raw, "<<none>>") == 0) { > > - free_lookup_result(result); > > errno = ENOENT; > > - return NULL; > > + goto fail; > > } > > > > - if (likely(buf)) { > > + if (child_regex_match) { > > + r = child_regex_match; > > + } else if (buf) { > > r = buf; > > } else { > > r = malloc(sizeof(*r)); > > - if (!r) { > > - free_lookup_result(result); > > - return NULL; > > - } > > + if (!r) > > + goto fail; > > } > > > > *r = (struct lookup_result) { > > @@ -1689,8 +1715,12 @@ static struct lookup_result *lookup_check_node(struct spec_node *node, const cha > > .next = NULL, > > }; > > > > - if (likely(!find_all)) > > - return r; > > + if (likely(!find_all)) { > > + child_regex_match = r; > > + child_regex_match_inputno = rspec->inputno; > > + child_regex_match_lineno = rspec->lineno; > > + goto parent_node; > > + } > > > > *next = r; > > next = &r->next; > > @@ -1702,15 +1732,28 @@ static struct lookup_result *lookup_check_node(struct spec_node *node, const cha > > continue; > > > > /* else it's an error */ > > - free_lookup_result(result); > > errno = ENOENT; > > - return NULL; > > + goto fail; > > } > > + > > + parent_node: > > + continue; > > } > > > > + if (child_regex_match) > > + return child_regex_match; > > + > > if (!result) > > errno = ENOENT; > > return result; > > + > > + fail: > > + if (!find_all && child_regex_match && child_regex_match != buf) > > + free(child_regex_match); > > + > > + free_lookup_result(result); > > + > > + return NULL; > > } > > > > static struct spec_node* search_child_node(struct spec_node *array, uint32_t size, const char *key, size_t key_len) > > @@ -2221,81 +2264,69 @@ static enum selabel_cmp_result spec_node_cmp(const struct spec_node *node1, cons > > while (iter1 < node1->regex_specs_num && iter2 < node2->regex_specs_num) { > > const struct regex_spec *rspec1 = &node1->regex_specs[iter1]; > > const struct regex_spec *rspec2 = &node2->regex_specs[iter2]; > > - int cmp; > > - > > - if (rspec1->prefix_len > rspec2->prefix_len) { > > - if (result == SELABEL_EQUAL || result == SELABEL_SUPERSET) { > > - result = SELABEL_SUPERSET; > > - iter1++; > > - continue; > > - } > > + bool found_successor; > > > > - return rspec_incomp(node1->stem, rspec1, rspec2, "regex_prefix_length", iter1, iter2); > > + if (rspec1->file_kind == rspec2->file_kind && strcmp(rspec1->regex_str, rspec2->regex_str) == 0) { > > + iter1++; > > + iter2++; > > + continue; > > } > > > > - if (rspec1->prefix_len < rspec2->prefix_len) { > > - if (result == SELABEL_EQUAL || result == SELABEL_SUBSET) { > > - result = SELABEL_SUBSET; > > - iter2++; > > - continue; > > - } > > + if (result == SELABEL_SUPERSET) { > > + iter1++; > > + continue; > > + } > > > > - return rspec_incomp(node1->stem, rspec1, rspec2, "regex_prefix_length", iter1, iter2); > > + if (result == SELABEL_SUBSET) { > > + iter2++; > > + continue; > > } > > > > - /* If prefix length is equal compare regex string */ > > + assert(result == SELABEL_EQUAL); > > > > - cmp = strcmp(rspec1->regex_str, rspec2->regex_str); > > - if (cmp < 0) { > > - if (result == SELABEL_EQUAL || result == SELABEL_SUPERSET) { > > - result = SELABEL_SUPERSET; > > - iter1++; > > - continue; > > - } > > + found_successor = false; > > > > - return rspec_incomp(node1->stem, rspec1, rspec2, "regex_str", iter1, iter2); > > - } > > + for (uint32_t i = iter2; i < node2->regex_specs_num; i++) { > > + const struct regex_spec *successor = &node2->regex_specs[i]; > > > > - if (cmp > 0) { > > - if (result == SELABEL_EQUAL || result == SELABEL_SUBSET) { > > + if (rspec1->file_kind == successor->file_kind && strcmp(rspec1->regex_str, successor->regex_str) == 0) { > > result = SELABEL_SUBSET; > > - iter2++; > > - continue; > > + iter1++; > > + iter2 = i + 1; > > + found_successor = true; > > + break; > > } > > - > > - return rspec_incomp(node1->stem, rspec1, rspec2, "regex_str", iter1, iter2); > > } > > > > - /* If literal match is equal compare file kind */ > > + if (found_successor) > > + continue; > > > > - if (rspec1->file_kind > rspec2->file_kind) { > > - if (result == SELABEL_EQUAL || result == SELABEL_SUPERSET) { > > - result = SELABEL_SUPERSET; > > - iter1++; > > - continue; > > - } > > + for (uint32_t i = iter1; i < node1->regex_specs_num; i++) { > > + const struct regex_spec *successor = &node1->regex_specs[i]; > > > > - return rspec_incomp(node1->stem, rspec1, rspec2, "file_kind", iter1, iter2); > > - } > > - > > - if (rspec1->file_kind < rspec2->file_kind) { > > - if (result == SELABEL_EQUAL || result == SELABEL_SUBSET) { > > - result = SELABEL_SUBSET; > > + if (successor->file_kind == rspec2->file_kind && strcmp(successor->regex_str, rspec2->regex_str) == 0) { > > + result = SELABEL_SUPERSET; > > + iter1 = i + 1; > > iter2++; > > - continue; > > + found_successor = true; > > + break; > > } > > - > > - return rspec_incomp(node1->stem, rspec1, rspec2, "file_kind", iter1, iter2); > > } > > > > - iter1++; > > - iter2++; > > + if (found_successor) > > + continue; > > + > > + return rspec_incomp(node1->stem, rspec1, rspec2, "regex", iter1, iter2); > > } > > if (iter1 != node1->regex_specs_num) { > > if (result == SELABEL_EQUAL || result == SELABEL_SUPERSET) { > > result = SELABEL_SUPERSET; > > } else { > > - selinux_log(SELINUX_INFO, "selabel_cmp: mismatch regex_str left remnant in stem %s\n", fmt_stem(node1->stem)); > > + const struct regex_spec *rspec1 = &node1->regex_specs[iter1]; > > + > > + selinux_log(SELINUX_INFO, "selabel_cmp: mismatch regex left remnant in stem %s entry %u: (%s, %s, %s)\n", > > + fmt_stem(node1->stem), > > + iter1, rspec1->regex_str, file_kind_to_string(rspec1->file_kind), rspec1->lr.ctx_raw); > > return SELABEL_INCOMPARABLE; > > } > > } > > @@ -2303,7 +2334,11 @@ static enum selabel_cmp_result spec_node_cmp(const struct spec_node *node1, cons > > if (result == SELABEL_EQUAL || result == SELABEL_SUBSET) { > > result = SELABEL_SUBSET; > > } else { > > - selinux_log(SELINUX_INFO, "selabel_cmp: mismatch regex_str right remnant in stem %s\n", fmt_stem(node1->stem)); > > + const struct regex_spec *rspec2 = &node2->regex_specs[iter2]; > > + > > + selinux_log(SELINUX_INFO, "selabel_cmp: mismatch regex right remnant in stem %s entry %u: (%s, %s, %s)\n", > > + fmt_stem(node1->stem), > > + iter2, rspec2->regex_str, file_kind_to_string(rspec2->file_kind), rspec2->lr.ctx_raw); > > return SELABEL_INCOMPARABLE; > > } > > } > > diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h > > index c7fe3a48..2506f9b5 100644 > > --- a/libselinux/src/label_file.h > > +++ b/libselinux/src/label_file.h > > @@ -61,7 +61,7 @@ struct lookup_result { > > }; > > #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION > > extern int load_mmap(FILE *fp, const size_t len, struct selabel_handle *rec, const char *path); > > -extern int process_text_file(FILE *fp, const char *prefix, struct selabel_handle *rec, const char *path); > > +extern int process_text_file(FILE *fp, const char *prefix, struct selabel_handle *rec, const char *path, uint8_t inputno); > > extern void free_lookup_result(struct lookup_result *result); > > extern struct lookup_result *lookup_all(struct selabel_handle *rec, const char *key, int type, bool partial, bool find_all); > > extern enum selabel_cmp_result cmp(const struct selabel_handle *h1, const struct selabel_handle *h2); > > @@ -81,7 +81,9 @@ struct regex_spec { > > char *regex_str; /* original regular expression string for diagnostics */ > > struct regex_data *regex; /* backend dependent regular expression data */ > > pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */ > > + uint32_t lineno; /* Line number in source file */ > > uint16_t prefix_len; /* length of fixed path prefix */ > > + uint8_t inputno; /* Input number of source file */ > > uint8_t file_kind; /* file type */ > > bool regex_compiled; /* whether the regex is compiled */ > > bool any_matches; /* whether any pathname match */ > > @@ -123,7 +125,7 @@ struct spec_node { > > uint32_t literal_specs_num, literal_specs_alloc; > > > > /* > > - * Array of regular expression specifications (ordered from most to least specific) > > + * Array of regular expression specifications (order preserved from input) > > */ > > struct regex_spec *regex_specs; > > uint32_t regex_specs_num, regex_specs_alloc; > > @@ -369,38 +371,6 @@ static inline int compare_literal_spec(const void *p1, const void *p2) > > return (l1->file_kind < l2->file_kind) - (l1->file_kind > l2->file_kind); > > } > > > > -static inline int compare_regex_spec(const void *p1, const void *p2) > > -{ > > - const struct regex_spec *r1 = p1; > > - const struct regex_spec *r2 = p2; > > - size_t regex_len1, regex_len2; > > - int ret; > > - > > - /* Order from high prefix length to low */ > > - ret = (r1->prefix_len < r2->prefix_len) - (r1->prefix_len > r2->prefix_len); > > - if (ret) > > - return ret; > > - > > - /* Order from long total regex length to short */ > > - regex_len1 = strlen(r1->regex_str); > > - regex_len2 = strlen(r2->regex_str); > > - ret = (regex_len1 < regex_len2) - (regex_len1 > regex_len2); > > - if (ret) > > - return ret; > > - > > - /* > > - * Order for no-duplicates check. > > - * Use reverse alphabetically order to retain the Fedora ordering of > > - * `/usr/(.* /)?lib(/.*)?` before `/usr/(.* /)?bin(/.*)?`. > > - */ > > - ret = strcmp(r1->regex_str, r2->regex_str); > > - if (ret) > > - return -ret; > > - > > - /* Order wildcard mode (0) last */ > > - return (r1->file_kind < r2->file_kind) - (r1->file_kind > r2->file_kind); > > -} > > - > > static inline int compare_spec_node(const void *p1, const void *p2) > > { > > const struct spec_node *n1 = p1; > > @@ -531,7 +501,7 @@ static inline int compile_regex(struct regex_spec *spec, const char **errbuf) > > > > static int insert_spec(const struct selabel_handle *rec, struct saved_data *data, > > const char *prefix, char *regex, uint8_t file_kind, char *context, > > - const char *path, unsigned int lineno) > > + const char *path, uint8_t inputno, uint32_t lineno) > > { > > size_t prefix_len; > > bool has_meta; > > @@ -642,6 +612,8 @@ static int insert_spec(const struct selabel_handle *rec, struct saved_data *data > > .regex_lock = PTHREAD_MUTEX_INITIALIZER, > > .file_kind = file_kind, > > .any_matches = false, > > + .inputno = inputno, > > + .lineno = lineno, > > .lr.ctx_raw = context, > > .lr.ctx_trans = NULL, > > .lr.lineno = lineno, > > @@ -816,7 +788,8 @@ static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes) > > * utils/sefcontext_compile.c */ > > static inline int process_line(struct selabel_handle *rec, > > const char *path, const char *prefix, > > - char *line_buf, size_t nread, unsigned lineno) > > + char *line_buf, size_t nread, > > + uint8_t inputno, uint32_t lineno) > > { > > int items; > > char *regex = NULL, *type = NULL, *context = NULL; > > @@ -886,7 +859,7 @@ static inline int process_line(struct selabel_handle *rec, > > free(type); > > } > > > > - return insert_spec(rec, data, prefix, regex, file_kind, context, path, lineno); > > + return insert_spec(rec, data, prefix, regex, file_kind, context, path, inputno, lineno); > > } > > > > #endif /* _SELABEL_FILE_H_ */ > > diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c > > index b4445a1f..811b2a1a 100644 > > --- a/libselinux/utils/sefcontext_compile.c > > +++ b/libselinux/utils/sefcontext_compile.c > > @@ -31,7 +31,7 @@ static int validate_context(char **ctxp) > > > > static int process_file(struct selabel_handle *rec, const char *filename) > > { > > - unsigned int line_num; > > + uint32_t line_num; > > int rc; > > char *line_buf = NULL; > > size_t line_len = 0; > > @@ -48,7 +48,7 @@ static int process_file(struct selabel_handle *rec, const char *filename) > > line_num = 0; > > rc = 0; > > while ((nread = getline(&line_buf, &line_len, context_file)) > 0) { > > - rc = process_line(rec, filename, prefix, line_buf, nread, ++line_num); > > + rc = process_line(rec, filename, prefix, line_buf, nread, 0, ++line_num); > > if (rc || ctx_err) { > > /* With -p option need to check and fail if ctx err as > > * process_line() context validation on Linux does not > > @@ -160,6 +160,7 @@ static int create_sidtab(const struct saved_data *data, struct sidtab *stab) > > * Regular Expression Specification Format (RSpec) > > * > > * u32 - context table index for raw context (1-based) > > + * u32 - line number in source file > > * u16 - length of upcoming regex_str INCLUDING nul > > * [char] - char array of the original regex string including the stem INCLUDING nul > > * u16 - length of the fixed path prefix > > @@ -307,6 +308,12 @@ static int write_regex_spec(FILE *bin_file, bool do_write_precompregex, const st > > if (len != 1) > > return -1; > > > > + /* write line number */ > > + data_u32 = htobe32(rspec->lineno); > > + len = fwrite(&data_u32, sizeof(uint32_t), 1, bin_file); > > + if (len != 1) > > + return -1; > > + > > /* write regex string */ > > regex = rspec->regex_str; > > regex_len = strlen(regex); > > -- > > 2.45.2 > > > >