Commit 500b9116 authored by Nick Kralevich's avatar Nick Kralevich
Browse files

implement partial matching using PCRE

To speed up the boot process, Android doesn't visit every directory
in /sys. Instead, only those directories which match a regular
expression in /file_contexts are visited. Other directories are
skipped. This results in 2-3 second boot time reduction.

The initial version of this optimization was implemented in
change 0e7340fb. However, because
PCRE wasn't available, it was recognized that false positives and
false negatives might occur.

Now that PCRE is available, start using it. It will avoid the
false positive / negatives problem.

Bug: 17682157

(cherry picked from commit d0b768ab)

(cherry picked from commit d514c5af)

Change-Id: I78a0453236d2c2ebf7a5dcd44f896c06a2b423c5
parent 3946f911
......@@ -48,6 +48,8 @@ LOCAL_SRC_FILES := $(common_SRC_FILES) $(common_HOST_FILES) src/android.c
LOCAL_MODULE:= libselinux
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libmincrypt
LOCAL_C_INCLUDES := external/pcre
LOCAL_WHOLE_STATIC_LIBRARIES := libpcre
# 1003 corresponds to auditd, from system/core/logd/event.logtags
LOCAL_CFLAGS := -DAUDITD_LOG_TAG=1003
include $(BUILD_STATIC_LIBRARY)
......@@ -64,6 +66,8 @@ LOCAL_MODULE:= libselinux
LOCAL_MODULE_TAGS := eng
LOCAL_COPY_HEADERS_TO := $(common_COPY_HEADERS_TO)
LOCAL_COPY_HEADERS := $(common_COPY_HEADERS)
LOCAL_WHOLE_STATIC_LIBRARIES := libpcre
LOCAL_C_INCLUDES := external/pcre
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
......@@ -74,7 +78,8 @@ LOCAL_COPY_HEADERS_TO := $(common_COPY_HEADERS_TO)
LOCAL_COPY_HEADERS := $(common_COPY_HEADERS)
LOCAL_PRELINK_MODULE := false
LOCAL_STATIC_LIBRARIES := libmincrypt
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := external/pcre
LOCAL_SHARED_LIBRARIES := liblog libpcre
# 1003 corresponds to auditd, from system/core/logd/event.logtags
LOCAL_CFLAGS := -DAUDITD_LOG_TAG=1003
include $(BUILD_SHARED_LIBRARY)
......@@ -11,12 +11,12 @@
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "callbacks.h"
#include "label_internal.h"
#include <pcre.h>
/*
* Internals, mostly moved over from matchpathcon.c
......@@ -27,7 +27,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; /* pcre study result */
char regcomp; /* regex_str has been compiled to regex */
mode_t mode; /* mode format value */
int matches; /* number of matching pathnames */
......@@ -224,12 +225,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 */
......@@ -254,21 +256,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 = (char *) 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;
......@@ -317,7 +318,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 = strdup(regex);
if (!spec_arr[nspec].regex_str) {
......@@ -552,8 +553,10 @@ static void closef(struct selabel_handle *rec)
free(spec->type_str);
free(spec->lr.ctx_raw);
free(spec->lr.ctx_trans);
if (spec->regcomp)
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++) {
......@@ -576,14 +579,13 @@ static spec_t *lookup_common(struct selabel_handle *rec,
{
struct saved_data *data = (struct saved_data *)rec->data;
spec_t *spec_arr = data->spec_arr;
int i, rc, file_stem;
int i, rc, file_stem, pcre_options = 0;
mode_t mode = (mode_t)type;
const char *buf;
spec_t *ret = NULL;
char *clean_key = NULL;
const char *prev_slash, *next_slash;
unsigned int sofar = 0;
size_t keylen = strlen(key);
if (!data->nspec) {
errno = ENOENT;
......@@ -610,6 +612,9 @@ static spec_t *lookup_common(struct selabel_handle *rec,
file_stem = find_stem_from_file(data, &buf);
mode &= S_IFMT;
if (partial)
pcre_options |= PCRE_PARTIAL_SOFT;
/*
* Check for matching specifications in reverse order, so that
* the last matching specification is used.
......@@ -626,38 +631,17 @@ static spec_t *lookup_common(struct selabel_handle *rec,
if (compile_regex(data, &spec_arr[i], NULL) < 0)
goto finish;
if (spec_arr[i].stem_id == -1)
rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
rc = pcre_exec(spec_arr[i].regex, spec_arr[i].sd, key, strlen(key), 0, pcre_options, NULL, 0);
else
rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0);
rc = pcre_exec(spec_arr[i].regex, spec_arr[i].sd, buf, strlen(buf), 0, pcre_options, NULL, 0);
if (rc == 0) {
spec_arr[i].matches++;
break;
}
if (partial) {
/*
* We already checked above to see if the
* key has any direct match. Now we just need
* to check for partial matches.
* Since POSIX regex functions do not support
* partial match, we crudely approximate it
* via a prefix match.
* This is imprecise and could yield
* false positives or negatives but
* appears to work with our current set of
* regex strings.
* Convert to using pcre partial match
* if/when pcre becomes available in Android.
*/
if (spec_arr[i].prefix_len > 1 &&
!strncmp(key, spec_arr[i].regex_str,
keylen < spec_arr[i].prefix_len ?
keylen : spec_arr[i].prefix_len))
break;
}
} else if (partial && rc == PCRE_ERROR_PARTIAL)
break;
if (rc == REG_NOMATCH)
if (rc == PCRE_ERROR_NOMATCH)
continue;
/* else it's an error */
goto finish;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment