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