diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c index 80a7c5ab2..56e209494 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 @@ FUZZ_EXTERN int load_mmap(FILE *fp, const size_t len, struct selabel_handle *rec 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, "<>") == 0) { - free_lookup_result(result); - errno = ENOENT; - return NULL; - } + if (strcmp(lspec->lr.ctx_raw, "<>") == 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, "<>") == 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 562c3da60..597b756e4 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, struct lookup_result *buf); 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 b4445a1f1..811b2a1a6 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);