diff options
-rw-r--r-- | libselinux/src/label_file.c | 43 | ||||
-rw-r--r-- | libselinux/src/label_file.h | 4 | ||||
-rw-r--r-- | libselinux/src/regex.c | 50 | ||||
-rw-r--r-- | libselinux/src/regex.h | 15 | ||||
-rw-r--r-- | libselinux/utils/sefcontext_compile.c | 13 |
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(§ion_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(§ion_len, sizeof(uint32_t), 1, bin_file); |