Re: [RFC PATCH v2] libselinux: restore previous regex spec ordering

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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>

> ---
>  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
>
>





[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux