aboutsummaryrefslogtreecommitdiffstats
path: root/libselinux/src
diff options
context:
space:
mode:
Diffstat (limited to 'libselinux/src')
-rw-r--r--libselinux/src/Makefile4
-rw-r--r--libselinux/src/label.c164
-rw-r--r--libselinux/src/label_file.c180
-rw-r--r--libselinux/src/label_file.h43
-rw-r--r--libselinux/src/label_internal.h13
-rw-r--r--libselinux/src/load_policy.c5
-rw-r--r--libselinux/src/regex.c31
-rw-r--r--libselinux/src/regex.h7
-rw-r--r--libselinux/src/selinux_internal.h32
9 files changed, 288 insertions, 191 deletions
diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile
index 4306dd0e..2408faea 100644
--- a/libselinux/src/Makefile
+++ b/libselinux/src/Makefile
@@ -17,7 +17,7 @@ PYLIBS ?= $(shell $(PKG_CONFIG) --libs $(PYPREFIX))
PYSITEDIR ?= $(DESTDIR)$(shell $(PYTHON) -c 'import site; print(site.getsitepackages()[0])')
PYCEXT ?= $(shell $(PYTHON) -c 'import imp;print([s for s,m,t in imp.get_suffixes() if t == imp.C_EXTENSION][0])')
RUBYINC ?= $(shell $(RUBY) -e 'puts "-I" + RbConfig::CONFIG["rubyarchhdrdir"] + " -I" + RbConfig::CONFIG["rubyhdrdir"]')
-RUBYLIBS ?= $(shell $(RUBY) -e 'puts "-L" + RbConfig::CONFIG["libdir"] + " -lruby"')
+RUBYLIBS ?= $(shell $(RUBY) -e 'puts "-L" + RbConfig::CONFIG["libdir"] + " -L" + RbConfig::CONFIG["archlibdir"] + " " + RbConfig::CONFIG["LIBRUBYARG_SHARED"]')
RUBYINSTALL ?= $(DESTDIR)$(shell $(RUBY) -e 'puts RbConfig::CONFIG["vendorarchdir"]')
LIBBASE ?= $(shell basename $(LIBDIR))
LIBSEPOLA ?= $(LIBDIR)/libsepol.a
@@ -59,7 +59,7 @@ ifeq ($(COMPILER), gcc)
EXTRA_CFLAGS = -fipa-pure-const -Wlogical-op -Wpacked-bitfield-compat -Wsync-nand \
-Wcoverage-mismatch -Wcpp -Wformat-contains-nul -Wnormalized=nfc -Wsuggest-attribute=const \
-Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines -Wjump-misses-init \
- -Wno-suggest-attribute=pure -Wno-suggest-attribute=const -Wp,-D_FORTIFY_SOURCE=2
+ -Wno-suggest-attribute=pure -Wno-suggest-attribute=const -Wp,-D_FORTIFY_SOURCE
else
EXTRA_CFLAGS = -Wunused-command-line-argument
endif
diff --git a/libselinux/src/label.c b/libselinux/src/label.c
index 8e0a8628..c051e9f9 100644
--- a/libselinux/src/label.c
+++ b/libselinux/src/label.c
@@ -60,113 +60,6 @@ static selabel_initfunc initfuncs[] = {
CONFIG_ANDROID_BACKEND(selabel_service_init),
};
-static void selabel_subs_fini(struct selabel_sub *ptr)
-{
- struct selabel_sub *next;
-
- while (ptr) {
- next = ptr->next;
- free(ptr->src);
- free(ptr->dst);
- free(ptr);
- ptr = next;
- }
-}
-
-static char *selabel_sub(struct selabel_sub *ptr, const char *src)
-{
- char *dst = NULL;
- int len;
-
- while (ptr) {
- if (strncmp(src, ptr->src, ptr->slen) == 0 ) {
- if (src[ptr->slen] == '/' ||
- src[ptr->slen] == 0) {
- if ((src[ptr->slen] == '/') &&
- (strcmp(ptr->dst, "/") == 0))
- len = ptr->slen + 1;
- else
- len = ptr->slen;
- if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0)
- return NULL;
- return dst;
- }
- }
- ptr = ptr->next;
- }
- return NULL;
-}
-
-struct selabel_sub *selabel_subs_init(const char *path,
- struct selabel_sub *list,
- struct selabel_digest *digest)
-{
- char buf[1024];
- FILE *cfg = fopen(path, "re");
- struct selabel_sub *sub = NULL;
- struct stat sb;
-
- if (!cfg)
- return list;
-
- if (fstat(fileno(cfg), &sb) < 0)
- return list;
-
- while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) {
- char *ptr = NULL;
- char *src = buf;
- char *dst = NULL;
-
- while (*src && isspace(*src))
- src++;
- if (src[0] == '#') continue;
- ptr = src;
- while (*ptr && ! isspace(*ptr))
- ptr++;
- *ptr++ = '\0';
- if (! *src) continue;
-
- dst = ptr;
- while (*dst && isspace(*dst))
- dst++;
- ptr=dst;
- while (*ptr && ! isspace(*ptr))
- ptr++;
- *ptr='\0';
- if (! *dst)
- continue;
-
- sub = malloc(sizeof(*sub));
- if (! sub)
- goto err;
- memset(sub, 0, sizeof(*sub));
-
- sub->src=strdup(src);
- if (! sub->src)
- goto err;
-
- sub->dst=strdup(dst);
- if (! sub->dst)
- goto err;
-
- sub->slen = strlen(src);
- sub->next = list;
- list = sub;
- }
-
- if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0)
- goto err;
-
-out:
- fclose(cfg);
- return list;
-err:
- if (sub)
- free(sub->src);
- free(sub);
- goto out;
-}
-
static inline struct selabel_digest *selabel_is_digest_set
(const struct selinux_opt *opts,
unsigned n,
@@ -252,27 +145,6 @@ out:
}
/* Public API helpers */
-static char *selabel_sub_key(struct selabel_handle *rec, const char *key)
-{
- char *ptr = NULL;
- char *dptr = NULL;
-
- ptr = selabel_sub(rec->subs, key);
- if (ptr) {
- dptr = selabel_sub(rec->dist_subs, ptr);
- if (dptr) {
- free(ptr);
- ptr = dptr;
- }
- } else {
- ptr = selabel_sub(rec->dist_subs, key);
- }
- if (ptr)
- return ptr;
-
- return NULL;
-}
-
static int selabel_fini(struct selabel_handle *rec,
struct selabel_lookup_rec *lr,
int translating)
@@ -296,20 +168,13 @@ selabel_lookup_common(struct selabel_handle *rec, int translating,
const char *key, int type)
{
struct selabel_lookup_rec *lr;
- char *ptr = NULL;
if (key == NULL) {
errno = EINVAL;
return NULL;
}
- ptr = selabel_sub_key(rec, key);
- if (ptr) {
- lr = rec->func_lookup(rec, ptr, type);
- free(ptr);
- } else {
- lr = rec->func_lookup(rec, key, type);
- }
+ lr = rec->func_lookup(rec, key, type);
if (!lr)
return NULL;
@@ -324,20 +189,13 @@ selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
const char *key, int type, const char **aliases)
{
struct selabel_lookup_rec *lr;
- char *ptr = NULL;
if (key == NULL) {
errno = EINVAL;
return NULL;
}
- ptr = selabel_sub_key(rec, key);
- if (ptr) {
- lr = rec->func_lookup_best_match(rec, ptr, aliases, type);
- free(ptr);
- } else {
- lr = rec->func_lookup_best_match(rec, key, aliases, type);
- }
+ lr = rec->func_lookup_best_match(rec, key, aliases, type);
if (!lr)
return NULL;
@@ -375,8 +233,6 @@ struct selabel_handle *selabel_open(unsigned int backend,
rec->backend = backend;
rec->validating = selabel_is_validate_set(opts, nopts);
- rec->subs = NULL;
- rec->dist_subs = NULL;
rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
if ((*initfuncs[backend])(rec, opts, nopts)) {
@@ -415,9 +271,6 @@ int selabel_lookup_raw(struct selabel_handle *rec, char **con,
bool selabel_partial_match(struct selabel_handle *rec, const char *key)
{
- char *ptr;
- bool ret;
-
if (!rec->func_partial_match) {
/*
* If the label backend does not support partial matching,
@@ -426,15 +279,7 @@ bool selabel_partial_match(struct selabel_handle *rec, const char *key)
return true;
}
- ptr = selabel_sub_key(rec, key);
- if (ptr) {
- ret = rec->func_partial_match(rec, ptr);
- free(ptr);
- } else {
- ret = rec->func_partial_match(rec, key);
- }
-
- return ret;
+ return rec->func_partial_match(rec, key);
}
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
@@ -501,8 +346,7 @@ int selabel_digest(struct selabel_handle *rec,
void selabel_close(struct selabel_handle *rec)
{
size_t i;
- selabel_subs_fini(rec->subs);
- selabel_subs_fini(rec->dist_subs);
+
if (rec->spec_files) {
for (i = 0; i < rec->spec_files_len; i++)
free(rec->spec_files[i]);
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 70f68382..b3b36bc2 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -389,10 +389,12 @@ end_arch_check:
spec->prefix_len = prefix_len;
}
- rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches);
+ rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches,
+ &spec->regex_compiled);
if (rc < 0)
goto out;
+ __pthread_mutex_init(&spec->regex_lock, NULL);
data->nspec++;
}
@@ -559,6 +561,148 @@ static int process_file(const char *path, const char *suffix,
return -1;
}
+static void selabel_subs_fini(struct selabel_sub *ptr)
+{
+ struct selabel_sub *next;
+
+ while (ptr) {
+ next = ptr->next;
+ free(ptr->src);
+ free(ptr->dst);
+ free(ptr);
+ ptr = next;
+ }
+}
+
+static char *selabel_sub(struct selabel_sub *ptr, const char *src)
+{
+ char *dst = NULL;
+ int len;
+
+ while (ptr) {
+ if (strncmp(src, ptr->src, ptr->slen) == 0 ) {
+ if (src[ptr->slen] == '/' ||
+ src[ptr->slen] == 0) {
+ if ((src[ptr->slen] == '/') &&
+ (strcmp(ptr->dst, "/") == 0))
+ len = ptr->slen + 1;
+ else
+ len = ptr->slen;
+ if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0)
+ return NULL;
+ return dst;
+ }
+ }
+ ptr = ptr->next;
+ }
+ return NULL;
+}
+
+static int selabel_subs_init(const char *path, struct selabel_digest *digest,
+ struct selabel_sub **out_subs)
+{
+ char buf[1024];
+ FILE *cfg = fopen(path, "re");
+ struct selabel_sub *list = NULL, *sub = NULL;
+ struct stat sb;
+ int status = -1;
+
+ *out_subs = NULL;
+ if (!cfg) {
+ /* If the file does not exist, it is not fatal */
+ return (errno == ENOENT) ? 0 : -1;
+ }
+
+ if (fstat(fileno(cfg), &sb) < 0)
+ goto out;
+
+ while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) {
+ char *ptr = NULL;
+ char *src = buf;
+ char *dst = NULL;
+
+ while (*src && isspace(*src))
+ src++;
+ if (src[0] == '#') continue;
+ ptr = src;
+ while (*ptr && ! isspace(*ptr))
+ ptr++;
+ *ptr++ = '\0';
+ if (! *src) continue;
+
+ dst = ptr;
+ while (*dst && isspace(*dst))
+ dst++;
+ ptr=dst;
+ while (*ptr && ! isspace(*ptr))
+ ptr++;
+ *ptr='\0';
+ if (! *dst)
+ continue;
+
+ sub = malloc(sizeof(*sub));
+ if (! sub)
+ goto err;
+ memset(sub, 0, sizeof(*sub));
+
+ sub->src=strdup(src);
+ if (! sub->src)
+ goto err;
+
+ sub->dst=strdup(dst);
+ if (! sub->dst)
+ goto err;
+
+ sub->slen = strlen(src);
+ sub->next = list;
+ list = sub;
+ sub = NULL;
+ }
+
+ if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0)
+ goto err;
+
+ *out_subs = list;
+ status = 0;
+
+out:
+ fclose(cfg);
+ return status;
+err:
+ if (sub)
+ free(sub->src);
+ free(sub);
+ while (list) {
+ sub = list->next;
+ free(list->src);
+ free(list->dst);
+ free(list);
+ list = sub;
+ }
+ goto out;
+}
+
+static char *selabel_sub_key(struct saved_data *data, const char *key)
+{
+ char *ptr = NULL;
+ char *dptr = NULL;
+
+ ptr = selabel_sub(data->subs, key);
+ if (ptr) {
+ dptr = selabel_sub(data->dist_subs, ptr);
+ if (dptr) {
+ free(ptr);
+ ptr = dptr;
+ }
+ } else {
+ ptr = selabel_sub(data->dist_subs, key);
+ }
+ if (ptr)
+ return ptr;
+
+ return NULL;
+}
+
static void closef(struct selabel_handle *rec);
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
@@ -620,20 +764,30 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
char subs_file[PATH_MAX + 1];
/* Process local and distribution substitution files */
if (!path_provided) {
- rec->dist_subs =
- selabel_subs_init(selinux_file_context_subs_dist_path(),
- rec->dist_subs, rec->digest);
- rec->subs = selabel_subs_init(selinux_file_context_subs_path(),
- rec->subs, rec->digest);
+ status = selabel_subs_init(
+ selinux_file_context_subs_dist_path(),
+ rec->digest, &data->dist_subs);
+ if (status)
+ goto finish;
+ status = selabel_subs_init(selinux_file_context_subs_path(),
+ rec->digest, &data->subs);
+ if (status)
+ goto finish;
rec->spec_files[0] = strdup(selinux_file_context_path());
if (rec->spec_files[0] == NULL)
goto finish;
} else {
for (i = 0; i < num_paths; i++) {
snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", rec->spec_files[i]);
- rec->dist_subs = selabel_subs_init(subs_file, rec->dist_subs, rec->digest);
+ status = selabel_subs_init(subs_file, rec->digest,
+ &data->dist_subs);
+ if (status)
+ goto finish;
snprintf(subs_file, sizeof(subs_file), "%s.subs", rec->spec_files[i]);
- rec->subs = selabel_subs_init(subs_file, rec->subs, rec->digest);
+ status = selabel_subs_init(subs_file, rec->digest,
+ &data->subs);
+ if (status)
+ goto finish;
}
}
#else
@@ -698,11 +852,15 @@ static void closef(struct selabel_handle *rec)
/* make sure successive ->func_close() calls are harmless */
rec->data = NULL;
+ selabel_subs_fini(data->subs);
+ selabel_subs_fini(data->dist_subs);
+
for (i = 0; i < data->nspec; i++) {
spec = &data->spec_arr[i];
free(spec->lr.ctx_trans);
free(spec->lr.ctx_raw);
regex_data_free(spec->regex);
+ __pthread_mutex_destroy(&spec->regex_lock);
if (spec->from_mmap)
continue;
free(spec->regex_str);
@@ -745,6 +903,7 @@ static struct spec *lookup_common(struct selabel_handle *rec,
char *clean_key = NULL;
const char *prev_slash, *next_slash;
unsigned int sofar = 0;
+ char *sub = NULL;
if (!data->nspec) {
errno = ENOENT;
@@ -767,6 +926,10 @@ static struct spec *lookup_common(struct selabel_handle *rec,
key = clean_key;
}
+ sub = selabel_sub_key(data, key);
+ if (sub)
+ key = sub;
+
buf = key;
file_stem = find_stem_from_file(data, &buf);
mode &= S_IFMT;
@@ -815,6 +978,7 @@ static struct spec *lookup_common(struct selabel_handle *rec,
finish:
free(clean_key);
+ free(sub);
return ret;
}
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
index 4ac64d59..aa576d8e 100644
--- a/libselinux/src/label_file.h
+++ b/libselinux/src/label_file.h
@@ -2,6 +2,7 @@
#define _SELABEL_FILE_H_
#include <errno.h>
+#include <pthread.h>
#include <string.h>
#include <sys/stat.h>
@@ -16,6 +17,7 @@
#include "callbacks.h"
#include "label_internal.h"
+#include "selinux_internal.h"
#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a
@@ -29,12 +31,21 @@
#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
+struct selabel_sub {
+ char *src;
+ int slen;
+ char *dst;
+ struct selabel_sub *next;
+};
+
/* A file security context specification. */
struct spec {
struct selabel_lookup_rec lr; /* holds contexts for lookup result */
char *regex_str; /* regular expession string for diagnostics */
char *type_str; /* type string for diagnostic messages */
struct regex_data * regex; /* backend dependent regular expression data */
+ bool regex_compiled; /* bool to indicate if the regex is compiled */
+ pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */
mode_t mode; /* mode format value */
int matches; /* number of matching pathnames */
int stem_id; /* indicates which stem-compression item */
@@ -76,6 +87,10 @@ struct saved_data {
int num_stems;
int alloc_stems;
struct mmap_area *mmap_areas;
+
+ /* substitution support */
+ struct selabel_sub *dist_subs;
+ struct selabel_sub *subs;
};
static inline mode_t string_to_mode(char *mode)
@@ -328,9 +343,27 @@ static inline int compile_regex(struct saved_data *data, struct spec *spec,
struct stem *stem_arr = data->stem_arr;
size_t len;
int rc;
-
- if (spec->regex)
+ bool regex_compiled;
+
+ /* We really want pthread_once() here, but since its
+ * init_routine does not take a parameter, it's not possible
+ * to use, so we generate the same effect with atomics and a
+ * mutex */
+ regex_compiled =
+ __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE);
+ if (regex_compiled) {
return 0; /* already done */
+ }
+
+ __pthread_mutex_lock(&spec->regex_lock);
+ /* Check if another thread compiled the regex while we waited
+ * on the mutex */
+ regex_compiled =
+ __atomic_load_n(&spec->regex_compiled, __ATOMIC_ACQUIRE);
+ if (regex_compiled) {
+ __pthread_mutex_unlock(&spec->regex_lock);
+ return 0;
+ }
/* Skip the fixed stem. */
reg_buf = spec->regex_str;
@@ -343,6 +376,7 @@ static inline int compile_regex(struct saved_data *data, struct spec *spec,
if (!anchored_regex) {
if (errbuf)
*errbuf = "out of memory";
+ __pthread_mutex_unlock(&spec->regex_lock);
return -1;
}
@@ -363,10 +397,13 @@ static inline int compile_regex(struct saved_data *data, struct spec *spec,
sizeof(regex_error_format_buffer));
*errbuf = &regex_error_format_buffer[0];
}
+ __pthread_mutex_unlock(&spec->regex_lock);
return -1;
}
/* Done. */
+ __atomic_store_n(&spec->regex_compiled, true, __ATOMIC_RELEASE);
+ __pthread_mutex_unlock(&spec->regex_lock);
return 0;
}
@@ -428,6 +465,8 @@ static inline int process_line(struct selabel_handle *rec,
/* process and store the specification in spec. */
spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
spec_arr[nspec].regex_str = regex;
+ __pthread_mutex_init(&spec_arr[nspec].regex_lock, NULL);
+ spec_arr[nspec].regex_compiled = false;
spec_arr[nspec].type_str = type;
spec_arr[nspec].mode = 0;
diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h
index 62c1720e..6810018f 100644
--- a/libselinux/src/label_internal.h
+++ b/libselinux/src/label_internal.h
@@ -46,12 +46,6 @@ int selabel_service_init(struct selabel_handle *rec,
/*
* Labeling internal structures
*/
-struct selabel_sub {
- char *src;
- int slen;
- char *dst;
- struct selabel_sub *next;
-};
/*
* Calculate an SHA1 hash of all the files used to build the specs.
@@ -75,10 +69,6 @@ extern int digest_add_specfile(struct selabel_digest *digest, FILE *fp,
const char *path);
extern void digest_gen_hash(struct selabel_digest *digest);
-extern struct selabel_sub *selabel_subs_init(const char *path,
- struct selabel_sub *list,
- struct selabel_digest *digest);
-
struct selabel_lookup_rec {
char * ctx_raw;
char * ctx_trans;
@@ -115,9 +105,6 @@ struct selabel_handle {
char **spec_files;
- /* substitution support */
- struct selabel_sub *dist_subs;
- struct selabel_sub *subs;
/* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */
struct selabel_digest *digest;
};
diff --git a/libselinux/src/load_policy.c b/libselinux/src/load_policy.c
index 7f083117..e9f1264a 100644
--- a/libselinux/src/load_policy.c
+++ b/libselinux/src/load_policy.c
@@ -449,8 +449,11 @@ int selinux_init_load_policy(int *enforce)
}
}
- if (seconfig == -1)
+ if (seconfig == -1) {
+ umount(selinux_mnt);
+ fini_selinuxmnt();
goto noload;
+ }
/* Load the policy. */
return selinux_mkload_policy(0);
diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
index 0c5ad274..dfc15d63 100644
--- a/libselinux/src/regex.c
+++ b/libselinux/src/regex.c
@@ -1,10 +1,12 @@
#include <assert.h>
+#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "regex.h"
#include "label_file.h"
+#include "selinux_internal.h"
#ifdef USE_PCRE2
#define REGEX_ARCH_SIZE_T PCRE2_SIZE
@@ -63,6 +65,7 @@ struct regex_data {
* pattern in pcre2
*/
pcre2_match_data *match_data;
+ pthread_mutex_t match_mutex;
};
int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
@@ -106,11 +109,12 @@ char const *regex_version(void)
}
int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
- int do_load_precompregex)
+ int do_load_precompregex, bool *regex_compiled)
{
int rc;
uint32_t entry_len;
+ *regex_compiled = false;
rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
if (rc < 0)
return -1;
@@ -138,6 +142,8 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
pcre2_match_data_create_from_pattern((*regex)->regex, NULL);
if (!(*regex)->match_data)
goto err;
+
+ *regex_compiled = true;
}
/* and skip the decoded bit */
@@ -199,6 +205,7 @@ void regex_data_free(struct regex_data *regex)
pcre2_code_free(regex->regex);
if (regex->match_data)
pcre2_match_data_free(regex->match_data);
+ __pthread_mutex_destroy(&regex->match_mutex);
free(regex);
}
}
@@ -206,9 +213,11 @@ void regex_data_free(struct regex_data *regex)
int regex_match(struct regex_data *regex, char const *subject, int partial)
{
int rc;
+ __pthread_mutex_lock(&regex->match_mutex);
rc = pcre2_match(
regex->regex, (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0,
partial ? PCRE2_PARTIAL_SOFT : 0, regex->match_data, NULL);
+ __pthread_mutex_unlock(&regex->match_mutex);
if (rc > 0)
return REGEX_MATCH;
switch (rc) {
@@ -244,6 +253,14 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
return SELABEL_EQUAL;
}
+struct regex_data *regex_data_create(void)
+{
+ struct regex_data *regex_data =
+ (struct regex_data *)calloc(1, sizeof(struct regex_data));
+ __pthread_mutex_init(&regex_data->match_mutex, NULL);
+ return regex_data;
+}
+
#else // !USE_PCRE2
char const *regex_arch_string(void)
{
@@ -302,7 +319,7 @@ char const *regex_version(void)
}
int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
- int unused __attribute__((unused)))
+ int unused __attribute__((unused)), bool *regex_compiled)
{
int rc;
uint32_t entry_len;
@@ -347,6 +364,8 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
if (rc < 0 || info_len != entry_len)
goto err;
}
+
+ *regex_compiled = true;
return 0;
err:
@@ -472,13 +491,13 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
return SELABEL_EQUAL;
}
-#endif
-
struct regex_data *regex_data_create(void)
{
return (struct regex_data *)calloc(1, sizeof(struct regex_data));
}
+#endif
+
void regex_format_error(struct regex_error_data const *error_data, char *buffer,
size_t buf_size)
{
@@ -539,12 +558,16 @@ truncated:
/* no break statements, fall-through is intended */
case 4:
*ptr++ = '.';
+ /* FALLTHRU */
case 3:
*ptr++ = '.';
+ /* FALLTHRU */
case 2:
*ptr++ = '.';
+ /* FALLTHRU */
case 1:
*ptr++ = '\0';
+ /* FALLTHRU */
default:
break;
}
diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
index 186c5ecc..eb8ca501 100644
--- a/libselinux/src/regex.h
+++ b/libselinux/src/regex.h
@@ -1,6 +1,7 @@
#ifndef SRC_REGEX_H_
#define SRC_REGEX_H_
+#include <stdbool.h>
#include <stdio.h>
#ifdef USE_PCRE2
@@ -98,13 +99,17 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
* 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).
+ * @arg regex_compiled Set to true if a precompiled pattern was loaded
+ * into regex, otherwise set to false to indicate later
+ * compilation must occur
*
* @retval 0 on success
* @retval -1 on error
*/
int regex_load_mmap(struct mmap_area *map_area,
struct regex_data **regex,
- int do_load_precompregex) hidden;
+ int do_load_precompregex,
+ bool *regex_compiled) 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/src/selinux_internal.h b/libselinux/src/selinux_internal.h
index 54949c13..dfc421cc 100644
--- a/libselinux/src/selinux_internal.h
+++ b/libselinux/src/selinux_internal.h
@@ -144,6 +144,38 @@ extern int selinux_page_size hidden;
pthread_setspecific(KEY, VALUE); \
} while (0)
+/* selabel_lookup() is only thread safe if we're compiled with pthreads */
+
+#pragma weak pthread_mutex_init
+#pragma weak pthread_mutex_destroy
+#pragma weak pthread_mutex_lock
+#pragma weak pthread_mutex_unlock
+
+#define __pthread_mutex_init(LOCK, ATTR) \
+ do { \
+ if (pthread_mutex_init != NULL) \
+ pthread_mutex_init(LOCK, ATTR); \
+ } while (0)
+
+#define __pthread_mutex_destroy(LOCK) \
+ do { \
+ if (pthread_mutex_destroy != NULL) \
+ pthread_mutex_destroy(LOCK); \
+ } while (0)
+
+#define __pthread_mutex_lock(LOCK) \
+ do { \
+ if (pthread_mutex_lock != NULL) \
+ pthread_mutex_lock(LOCK); \
+ } while (0)
+
+#define __pthread_mutex_unlock(LOCK) \
+ do { \
+ if (pthread_mutex_unlock != NULL) \
+ pthread_mutex_unlock(LOCK); \
+ } while (0)
+
+
#define SELINUXDIR "/etc/selinux/"
#define SELINUXCONFIG SELINUXDIR "config"