aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTianjie Xu <xunchang@google.com>2019-03-05 16:07:11 -0800
committerandroid-build-merger <android-build-merger@google.com>2019-03-05 16:07:11 -0800
commit82dff6230739063abfa66e96c7d2ea978452148b (patch)
treecbe608b39b9f4c8a9e466f12af99000aad80b36f
parent4f7a3eaafc94f5c9dfeb06f0a3f5f404782d69be (diff)
parentabc9cf497874426405251569f507e2979602e1c9 (diff)
downloadandroid_external_selinux-82dff6230739063abfa66e96c7d2ea978452148b.tar.gz
android_external_selinux-82dff6230739063abfa66e96c7d2ea978452148b.tar.bz2
android_external_selinux-82dff6230739063abfa66e96c7d2ea978452148b.zip
Merge "Restorecon: factor out a lookup helper for context matches" am: de42e97aa8
am: abc9cf4978 Change-Id: Ica14a5fb5a28272a2ce7129963345ca5ef5b2624
-rw-r--r--libselinux/include/selinux/label.h4
-rw-r--r--libselinux/src/label.c9
-rw-r--r--libselinux/src/label_file.c110
-rw-r--r--libselinux/src/label_internal.h2
4 files changed, 105 insertions, 20 deletions
diff --git a/libselinux/include/selinux/label.h b/libselinux/include/selinux/label.h
index 277287ed..e537aa11 100644
--- a/libselinux/include/selinux/label.h
+++ b/libselinux/include/selinux/label.h
@@ -7,6 +7,7 @@
#define _SELABEL_H_
#include <stdbool.h>
+#include <stdint.h>
#include <sys/types.h>
#include <selinux/selinux.h>
@@ -105,6 +106,9 @@ int selabel_lookup_raw(struct selabel_handle *handle, char **con,
bool selabel_partial_match(struct selabel_handle *handle, const char *key);
+bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
+ const char *key, uint8_t* digest);
+
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type);
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
diff --git a/libselinux/src/label.c b/libselinux/src/label.c
index ce786cd4..e232eb1b 100644
--- a/libselinux/src/label.c
+++ b/libselinux/src/label.c
@@ -282,6 +282,15 @@ bool selabel_partial_match(struct selabel_handle *rec, const char *key)
return rec->func_partial_match(rec, key);
}
+bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
+ const char *key, uint8_t *digest) {
+ if (!rec->func_hash_all_partial_matches) {
+ return false;
+ }
+
+ return rec->func_hash_all_partial_matches(rec, key, digest);
+}
+
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type)
{
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 6b64d66b..fe43c4a0 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -893,22 +893,37 @@ static void closef(struct selabel_handle *rec)
free(data);
}
-static struct spec *lookup_common(struct selabel_handle *rec,
- const char *key,
- int type,
- bool partial)
+// Finds all the matches of |key| in the given context. Returns the result in
+// the allocated array and updates the match count. If match_count is NULL,
+// stops early once the 1st match is found.
+static const struct spec **lookup_all(struct selabel_handle *rec,
+ const char *key,
+ int type,
+ bool partial,
+ size_t *match_count)
{
struct saved_data *data = (struct saved_data *)rec->data;
struct spec *spec_arr = data->spec_arr;
int i, rc, file_stem;
mode_t mode = (mode_t)type;
const char *buf;
- struct spec *ret = NULL;
char *clean_key = NULL;
const char *prev_slash, *next_slash;
unsigned int sofar = 0;
char *sub = NULL;
+ const struct spec **result = NULL;
+ if (match_count) {
+ *match_count = 0;
+ result = calloc(data->nspec, sizeof(struct spec*));
+ } else {
+ result = calloc(1, sizeof(struct spec*));
+ }
+ if (!result) {
+ selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
+ goto finish;
+ }
+
if (!data->nspec) {
errno = ENOENT;
goto finish;
@@ -949,18 +964,33 @@ static struct spec *lookup_common(struct selabel_handle *rec,
* 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) &&
- (!mode || !spec->mode || mode == spec->mode)) {
+ (!mode || !spec->mode || mode == spec->mode)) {
if (compile_regex(data, 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);
- if (rc == REGEX_MATCH) {
- spec->matches++;
- break;
- } else if (partial && rc == REGEX_MATCH_PARTIAL)
+
+ if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) {
+ if (rc == REGEX_MATCH) {
+ spec->matches++;
+ }
+
+ if (strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
+ errno = ENOENT;
+ goto finish;
+ }
+
+ if (match_count) {
+ result[*match_count] = spec;
+ *match_count += 1;
+ // Continue to find all the matches.
+ continue;
+ }
+ result[0] = spec;
break;
+ }
if (rc == REGEX_NO_MATCH)
continue;
@@ -971,19 +1001,58 @@ static struct spec *lookup_common(struct selabel_handle *rec,
}
}
- if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
- /* No matching specification. */
- errno = ENOENT;
- goto finish;
- }
-
- errno = 0;
- ret = &spec_arr[i];
-
finish:
free(clean_key);
free(sub);
- return ret;
+ if (result && !result[0]) {
+ free(result);
+ result = NULL;
+ }
+ return result;
+}
+
+static struct spec *lookup_common(struct selabel_handle *rec,
+ const char *key,
+ int type,
+ bool partial) {
+ const struct spec **matches = lookup_all(rec, key, type, partial, NULL);
+ if (!matches) {
+ return NULL;
+ }
+ struct spec *result = (struct spec*)matches[0];
+ free(matches);
+ return result;
+}
+
+static bool hash_all_partial_matches(struct selabel_handle *rec, const char *key, uint8_t *digest)
+{
+ assert(digest);
+
+ size_t total_matches;
+ const struct spec **matches = lookup_all(rec, key, 0, true, &total_matches);
+ if (!matches) {
+ return false;
+ }
+
+ Sha1Context context;
+ Sha1Initialise(&context);
+ size_t i;
+ for (i = 0; i < total_matches; i++) {
+ char* regex_str = matches[i]->regex_str;
+ uint32_t mode = matches[i]->mode;
+ char* ctx_raw = matches[i]->lr.ctx_raw;
+
+ Sha1Update(&context, regex_str, strlen(regex_str) + 1);
+ Sha1Update(&context, &mode, sizeof(uint32_t));
+ Sha1Update(&context, ctx_raw, strlen(ctx_raw) + 1);
+ }
+
+ SHA1_HASH sha1_hash;
+ Sha1Finalise(&context, &sha1_hash);
+ memcpy(digest, sha1_hash.bytes, SHA1_HASH_SIZE);
+
+ free(matches);
+ return true;
}
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
@@ -1183,6 +1252,7 @@ int selabel_file_init(struct selabel_handle *rec,
rec->func_stats = &stats;
rec->func_lookup = &lookup;
rec->func_partial_match = &partial_match;
+ rec->func_hash_all_partial_matches = &hash_all_partial_matches;
rec->func_lookup_best_match = &lookup_best_match;
rec->func_cmp = &cmp;
diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h
index a05a10a6..8add71a5 100644
--- a/libselinux/src/label_internal.h
+++ b/libselinux/src/label_internal.h
@@ -87,6 +87,8 @@ struct selabel_handle {
void (*func_close) (struct selabel_handle *h);
void (*func_stats) (struct selabel_handle *h);
bool (*func_partial_match) (struct selabel_handle *h, const char *key);
+ bool (*func_hash_all_partial_matches) (struct selabel_handle *h,
+ const char *key, uint8_t *digest);
struct selabel_lookup_rec *(*func_lookup_best_match)
(struct selabel_handle *h,
const char *key,