aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxunchang <xunchang@google.com>2019-03-14 11:01:47 -0700
committerxunchang <xunchang@google.com>2019-03-15 09:24:14 -0700
commitffb4432b9ae6fd1988f3c2c1a19ad9d606606697 (patch)
tree7c9187d186c773f6a469469c460a3dee65aa0bb3
parentde9339b29821fd961d7c56d56959e2139607964c (diff)
downloadandroid_external_selinux-ffb4432b9ae6fd1988f3c2c1a19ad9d606606697.tar.gz
android_external_selinux-ffb4432b9ae6fd1988f3c2c1a19ad9d606606697.tar.bz2
android_external_selinux-ffb4432b9ae6fd1988f3c2c1a19ad9d606606697.zip
Restorecon: Ignore the stem when looking up all matches in file context
The stem is a list of top level directory (without regex metachar) covered in the file context. And it constructs from finding the second '/' in the regex_string; and aims to speed up the lookup by skipping unnecessary regex matches. More contexts in https://lore.kernel.org/selinux/200309231522.25749.russell@coker.com.au/ However, this caused some issue when we try to find all the partial matches for a root directory. For example, the path "/data" doesn't have a stem while the regex "/data/misc/(/.*)?" has "/data" as the stem. As a result, all the regex for the subdirs of /data will not considered as a match for "/data". And the restorecon will wrongly skip on top level "/data" when there's a context change to one of subdir. This CL always includes the stem when compiling the regex in all circumstances. Also, it ignores the stem id check in the "match all" case, while the behavior for the single match stays unchanged. I will collect more data to find out if stem id check is still necessary at all with the new restorecon logic. Bug: 62302954 Bug: 127946548 Test: run restorecon on "/data"; change the context of one subdir and run again, and the context is restored on that subdir; search the caller of regex_match Change-Id: I4d6e554bb6abe124055782769d2f95083ed6c3a1
-rw-r--r--libselinux/src/label_file.c27
-rw-r--r--libselinux/src/label_file.h10
2 files changed, 14 insertions, 23 deletions
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index fe43c4a0..fd3e0130 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -39,18 +39,17 @@ static int get_stem_from_file_name(const char *const buf)
/* find the stem of a file name, returns the index into stem_arr (or -1 if
* there is no match - IE for a file in the root directory or a regex that is
- * too complex for us). Makes buf point to the text AFTER the stem. */
-static int find_stem_from_file(struct saved_data *data, const char **buf)
+ * too complex for us). */
+static int find_stem_from_file(struct saved_data *data, const char *key)
{
int i;
- int stem_len = get_stem_from_file_name(*buf);
+ int stem_len = get_stem_from_file_name(key);
if (!stem_len)
return -1;
for (i = 0; i < data->num_stems; i++) {
if (stem_len == data->stem_arr[i].len
- && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
- *buf += stem_len;
+ && !strncmp(key, data->stem_arr[i].buf, stem_len)) {
return i;
}
}
@@ -906,7 +905,6 @@ static const struct spec **lookup_all(struct selabel_handle *rec,
struct spec *spec_arr = data->spec_arr;
int i, rc, file_stem;
mode_t mode = (mode_t)type;
- const char *buf;
char *clean_key = NULL;
const char *prev_slash, *next_slash;
unsigned int sofar = 0;
@@ -949,8 +947,7 @@ static const struct spec **lookup_all(struct selabel_handle *rec,
if (sub)
key = sub;
- buf = key;
- file_stem = find_stem_from_file(data, &buf);
+ file_stem = find_stem_from_file(data, key);
mode &= S_IFMT;
/*
@@ -963,15 +960,15 @@ static const struct spec **lookup_all(struct selabel_handle *rec,
* 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->stem_id == -1 || spec->stem_id == file_stem) &&
+ bool stem_matches = spec->stem_id == -1 || spec->stem_id == file_stem;
+ // Don't check the stem if we want to find partial matches.
+ // Otherwise the case "/abc/efg/(/.*)?" will be considered
+ //a miss for "/abc".
+ if ((partial || stem_matches) &&
(!mode || !spec->mode || mode == spec->mode)) {
- if (compile_regex(data, spec, NULL) < 0)
+ if (compile_regex(spec, NULL) < 0)
goto finish;
- if (spec->stem_id == -1)
- rc = regex_match(spec->regex, key, partial);
- else
- rc = regex_match(spec->regex, buf, partial);
-
+ rc = regex_match(spec->regex, key, partial);
if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) {
if (rc == REGEX_MATCH) {
spec->matches++;
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
index 47859baf..6f4ee101 100644
--- a/libselinux/src/label_file.h
+++ b/libselinux/src/label_file.h
@@ -336,13 +336,11 @@ static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes)
return 0;
}
-static inline int compile_regex(struct saved_data *data, struct spec *spec,
- const char **errbuf)
+static inline int compile_regex(struct spec *spec, const char **errbuf)
{
char *reg_buf, *anchored_regex, *cp;
struct regex_error_data error_data;
static char regex_error_format_buffer[256];
- struct stem *stem_arr = data->stem_arr;
size_t len;
int rc;
bool regex_compiled;
@@ -379,11 +377,7 @@ static inline int compile_regex(struct saved_data *data, struct spec *spec,
return 0;
}
- /* Skip the fixed stem. */
reg_buf = spec->regex_str;
- if (spec->stem_id >= 0)
- reg_buf += stem_arr[spec->stem_id].len;
-
/* Anchor the regular expression. */
len = strlen(reg_buf);
cp = anchored_regex = malloc(len + 3);
@@ -501,7 +495,7 @@ static inline int process_line(struct selabel_handle *rec,
data->nspec++;
if (rec->validating
- && compile_regex(data, &spec_arr[nspec], &errbuf)) {
+ && compile_regex(&spec_arr[nspec], &errbuf)) {
COMPAT_LOG(SELINUX_ERROR,
"%s: line %u has invalid regex %s: %s\n",
path, lineno, regex, errbuf);