Restorecon: factor out a lookup helper for context matches
This is part of the effort to save digest for subdirectories. Split out the non-android part to make the merge to upstream branch easier. Bug: 62302954 Test: build android, compile the upstream branch Change-Id: I4df94ed381f26356c539d604f31a65daabafc1da
This commit is contained in:
parent
65c6846e1a
commit
f69947cffa
4 changed files with 105 additions and 20 deletions
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue