From 091eb526dd2036d993517d09e4fc67b2bec3ec5e Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 22 Aug 2012 11:43:29 -0400 Subject: [PATCH] libselinux: label_file: use PCRE instead of glibc regex functions The PCRE functions are about x10 faster than the glibc functions. So use the external library. Signed-off-by: Eric Paris --- libselinux/src/Makefile | 2 ++ libselinux/src/label_file.c | 63 +++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile index 74e53bb1..ac019df0 100644 --- a/libselinux/src/Makefile +++ b/libselinux/src/Makefile @@ -20,6 +20,8 @@ RUBYINC ?= $(shell pkg-config --cflags ruby-$(RUBYLIBVER)) RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM) LIBBASE=$(shell basename $(LIBDIR)) +LDFLAGS ?= -lpcre + VERSION = $(shell cat ../VERSION) LIBVERSION = 1 diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c index 7bc46ccc..25ad617f 100644 --- a/libselinux/src/label_file.c +++ b/libselinux/src/label_file.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -32,7 +32,8 @@ typedef 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 */ - regex_t regex; /* compiled regular expression */ + pcre *regex; /* compiled regular expression */ + pcre_extra *sd; /* extra compiled stuff */ char regcomp; /* regex_str has been compiled to regex */ mode_t mode; /* mode format value */ int matches; /* number of matching pathnames */ @@ -223,12 +224,13 @@ static void spec_hasMetaChars(struct spec *spec) return; } -static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf) +static int compile_regex(struct saved_data *data, spec_t *spec, const char **errbuf) { + const char *tmperrbuf; char *reg_buf, *anchored_regex, *cp; stem_t *stem_arr = data->stem_arr; size_t len; - int regerr; + int erroff; if (spec->regcomp) return 0; /* already done */ @@ -245,6 +247,7 @@ static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf) cp = anchored_regex = malloc(len + 3); if (!anchored_regex) return -1; + /* Create ^...$ regexp. */ *cp++ = '^'; cp = mempcpy(cp, reg_buf, len); @@ -252,21 +255,20 @@ static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf) *cp = '\0'; /* Compile the regular expression. */ - regerr = regcomp(&spec->regex, anchored_regex, - REG_EXTENDED | REG_NOSUB); - if (regerr != 0) { - size_t errsz = 0; - errsz = regerror(regerr, &spec->regex, NULL, 0); - if (errsz && errbuf) - *errbuf = malloc(errsz); - if (errbuf && *errbuf) - (void)regerror(regerr, &spec->regex, - *errbuf, errsz); - - free(anchored_regex); + spec->regex = pcre_compile(anchored_regex, 0, &tmperrbuf, &erroff, NULL); + free(anchored_regex); + if (!spec->regex) { + if (errbuf) + *errbuf=tmperrbuf; + return -1; + } + + spec->sd = pcre_study(spec->regex, 0, &tmperrbuf); + if (!spec->sd) { + if (errbuf) + *errbuf=tmperrbuf; return -1; } - free(anchored_regex); /* Done. */ spec->regcomp = 1; @@ -320,7 +322,7 @@ static int process_line(struct selabel_handle *rec, if (pass == 1) { /* On the second pass, process and store the specification in spec. */ - char *errbuf = NULL; + const char *errbuf = NULL; spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); spec_arr[nspec].regex_str = regex; if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) { @@ -575,7 +577,10 @@ static void closef(struct selabel_handle *rec) free(spec->type_str); free(spec->lr.ctx_raw); free(spec->lr.ctx_trans); - regfree(&spec->regex); + if (spec->regcomp) { + pcre_free(spec->regex); + pcre_free_study(spec->sd); + } } for (i = 0; i < (unsigned int)data->num_stems; i++) { @@ -634,26 +639,24 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, * the last matching specification is used. */ for (i = data->nspec - 1; i >= 0; i--) { + spec_t *spec = &spec_arr[i]; /* if the spec in question matches no stem or has the same * stem as the file AND if the spec in question has no mode * specified or if the mode matches the file mode then we do * a regex check */ - if ((spec_arr[i].stem_id == -1 - || spec_arr[i].stem_id == file_stem) - && (!mode || !spec_arr[i].mode - || mode == spec_arr[i].mode)) { - if (compile_regex(data, &spec_arr[i], NULL) < 0) + if ((spec->stem_id == -1 || spec->stem_id == file_stem) && + (!mode || !spec->mode || mode == spec->mode)) { + if (compile_regex(data, spec, NULL) < 0) goto finish; - if (spec_arr[i].stem_id == -1) - rc = regexec(&spec_arr[i].regex, key, 0, 0, 0); + if (spec->stem_id == -1) + rc = pcre_exec(spec->regex, spec->sd, key, strlen(key), 0, 0, NULL, 0); else - rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0); + rc = pcre_exec(spec->regex, spec->sd, buf, strlen(buf), 0, 0, NULL, 0); if (rc == 0) { - spec_arr[i].matches++; + spec->matches++; break; - } - if (rc == REG_NOMATCH) + } else if (rc == PCRE_ERROR_NOMATCH) continue; /* else it's an error */ goto finish;