aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libselinux/src/label_file.c43
-rw-r--r--libselinux/src/label_file.h4
-rw-r--r--libselinux/src/regex.c50
-rw-r--r--libselinux/src/regex.h15
-rw-r--r--libselinux/utils/sefcontext_compile.c13
5 files changed, 119 insertions, 6 deletions
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 5ba6a222..adf3dccf 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -125,6 +125,8 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
uint32_t i, magic, version;
uint32_t entry_len, stem_map_len, regex_array_len;
const char *reg_version;
+ const char *reg_arch;
+ char reg_arch_matches = 0;
mmap_area = malloc(sizeof(*mmap_area));
if (!mmap_area) {
@@ -158,6 +160,10 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
if (!reg_version)
return -1;
+ reg_arch = regex_arch_string();
+ if (!reg_arch)
+ return -1;
+
if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
len = strlen(reg_version);
@@ -187,7 +193,42 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
return -1;
}
free(str_buf);
+
+ if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
+ len = strlen(reg_arch);
+
+ rc = next_entry(&entry_len, mmap_area,
+ sizeof(uint32_t));
+ if (rc < 0)
+ return -1;
+
+ /* Check arch string lengths */
+ if (len != entry_len) {
+ /*
+ * Skip the entry and conclude that we have
+ * a mismatch, which is not fatal.
+ */
+ next_entry(NULL, mmap_area, entry_len);
+ goto end_arch_check;
+ }
+
+ /* Check if arch string mismatch */
+ str_buf = malloc(entry_len + 1);
+ if (!str_buf)
+ return -1;
+
+ rc = next_entry(str_buf, mmap_area, entry_len);
+ if (rc < 0) {
+ free(str_buf);
+ return -1;
+ }
+
+ str_buf[entry_len] = '\0';
+ reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
+ free(str_buf);
+ }
}
+end_arch_check:
/* allocate the stems_data array */
rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
@@ -348,7 +389,7 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
spec->prefix_len = prefix_len;
}
- rc = regex_load_mmap(mmap_area, &spec->regex);
+ rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches);
if (rc < 0)
goto out;
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
index 88f42944..00c0a5c1 100644
--- a/libselinux/src/label_file.h
+++ b/libselinux/src/label_file.h
@@ -24,8 +24,10 @@
#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2
#define SELINUX_COMPILED_FCONTEXT_MODE 3
#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4
+#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH 5
-#define SELINUX_COMPILED_FCONTEXT_MAX_VERS SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
+#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
+ SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
/* A file security context specification. */
struct spec {
diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
index 750088ed..a3b427b4 100644
--- a/libselinux/src/regex.c
+++ b/libselinux/src/regex.c
@@ -7,6 +7,44 @@
#include "label_file.h"
#ifdef USE_PCRE2
+#define REGEX_ARCH_SIZE_T PCRE2_SIZE
+#else
+#define REGEX_ARCH_SIZE_T size_t
+#endif
+
+#ifndef __BYTE_ORDER__
+#error __BYTE_ORDER__ not defined. Unable to determine endianness.
+#endif
+
+#ifdef USE_PCRE2
+char const *regex_arch_string(void)
+{
+ static char arch_string_buffer[32];
+ static char const *arch_string = "";
+ char const *endianness = NULL;
+ int rc;
+
+ if (arch_string[0] == '\0') {
+ if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ endianness = "el";
+ else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+ endianness = "eb";
+
+ if (!endianness)
+ return NULL;
+
+ rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer),
+ "%zu-%zu-%s", sizeof(void *),
+ sizeof(REGEX_ARCH_SIZE_T),
+ endianness);
+ if (rc < 0)
+ abort();
+
+ arch_string = &arch_string_buffer[0];
+ }
+ return arch_string;
+}
+
struct regex_data {
pcre2_code *regex; /* compiled regular expression */
/*
@@ -56,7 +94,8 @@ char const *regex_version(void)
return version_buf;
}
-int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
+int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
+ int do_load_precompregex)
{
int rc;
uint32_t entry_len;
@@ -65,7 +104,7 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
if (rc < 0)
return -1;
- if (entry_len) {
+ if (entry_len && do_load_precompregex) {
/*
* this should yield exactly one because we store one pattern at
* a time
@@ -195,6 +234,10 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
}
#else // !USE_PCRE2
+char const *regex_arch_string(void)
+{
+ return "N/A";
+}
/* Prior to version 8.20, libpcre did not have pcre_free_study() */
#if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
@@ -247,7 +290,8 @@ char const *regex_version(void)
return pcre_version();
}
-int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
+int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
+ int unused __attribute__((unused)))
{
int rc;
uint32_t entry_len;
diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
index 810b3c5a..186c5ecc 100644
--- a/libselinux/src/regex.h
+++ b/libselinux/src/regex.h
@@ -34,6 +34,16 @@ struct regex_error_data {
struct mmap_area;
/**
+ * regex_arch_string return a string that represents the pointer width, the
+ * width of what the backend considers a size type, and the endianness of the
+ * system that this library was build for. (e.g. for x86_64: "8-8-el").
+ * This is required when loading stored regular espressions. PCRE2 regular
+ * expressions are not portable across architectures that do not have a
+ * matching arch-string.
+ */
+char const *regex_arch_string(void) hidden;
+
+/**
* regex_verison returns the version string of the underlying regular
* regular expressions library. In the case of PCRE it just returns the
* result of pcre_version(). In the case of PCRE2, the very first time this
@@ -86,12 +96,15 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
* representation of the precompiled pattern.
* @arg regex If successful, the structure returned through *regex was allocated
* with regex_data_create and must be freed with regex_data_free.
+ * @arg do_load_precompregex If non-zero precompiled patterns get loaded from
+ * the mmap region (ignored by PCRE1 back-end).
*
* @retval 0 on success
* @retval -1 on error
*/
int regex_load_mmap(struct mmap_area *map_area,
- struct regex_data **regex) hidden;
+ struct regex_data **regex,
+ int do_load_precompregex) hidden;
/**
* This function stores a precompiled regular expression to a file.
* In the case of PCRE, it just dumps the binary representation of the
diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
index ebd12648..e22ae81e 100644
--- a/libselinux/utils/sefcontext_compile.c
+++ b/libselinux/utils/sefcontext_compile.c
@@ -103,6 +103,7 @@ static int write_binary_file(struct saved_data *data, int fd,
uint32_t i;
int rc;
const char *reg_version;
+ const char *reg_arch;
bin_file = fdopen(fd, "w");
if (!bin_file) {
@@ -133,6 +134,18 @@ static int write_binary_file(struct saved_data *data, int fd,
if (len != section_len)
goto err;
+ /* write regex arch string */
+ reg_arch = regex_arch_string();
+ if (!reg_arch)
+ goto err;
+ section_len = strlen(reg_arch);
+ len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
+ if (len != 1)
+ goto err;
+ len = fwrite(reg_arch, sizeof(char), section_len, bin_file);
+ if (len != section_len)
+ goto err;
+
/* write the number of stems coming */
section_len = data->num_stems;
len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);