aboutsummaryrefslogtreecommitdiffstats
path: root/libselinux/src/label_file.c
diff options
context:
space:
mode:
authorDan Cashman <dcashman@google.com>2017-08-07 14:58:55 -0700
committerDan Cashman <dcashman@google.com>2017-08-07 17:00:18 -0700
commit706ddd16f3f4a3e5e9754904957fe2efe5066989 (patch)
tree0c05bc5318a2d0834cfc341cfe68a95d846f071a /libselinux/src/label_file.c
parent7e29d17754156636a79c60f7ce195039b94d7197 (diff)
parentbd75c5695c629a20aeb7c9d723290e2d7bb8a3f3 (diff)
downloadandroid_external_selinux-706ddd16f3f4a3e5e9754904957fe2efe5066989.tar.gz
android_external_selinux-706ddd16f3f4a3e5e9754904957fe2efe5066989.tar.bz2
android_external_selinux-706ddd16f3f4a3e5e9754904957fe2efe5066989.zip
Merge remote-tracking branch 'aosp/upstream-master' into mymerge
Bug: 63861738 Test: Builds 'n' boots Change-Id: Idfb333d4cc1568dd2273f74731f12d52a413c07b
Diffstat (limited to 'libselinux/src/label_file.c')
-rw-r--r--libselinux/src/label_file.c180
1 files changed, 172 insertions, 8 deletions
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 70f68382..b3b36bc2 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -389,10 +389,12 @@ end_arch_check:
spec->prefix_len = prefix_len;
}
- rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches);
+ rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches,
+ &spec->regex_compiled);
if (rc < 0)
goto out;
+ __pthread_mutex_init(&spec->regex_lock, NULL);
data->nspec++;
}
@@ -559,6 +561,148 @@ static int process_file(const char *path, const char *suffix,
return -1;
}
+static void selabel_subs_fini(struct selabel_sub *ptr)
+{
+ struct selabel_sub *next;
+
+ while (ptr) {
+ next = ptr->next;
+ free(ptr->src);
+ free(ptr->dst);
+ free(ptr);
+ ptr = next;
+ }
+}
+
+static char *selabel_sub(struct selabel_sub *ptr, const char *src)
+{
+ char *dst = NULL;
+ int len;
+
+ while (ptr) {
+ if (strncmp(src, ptr->src, ptr->slen) == 0 ) {
+ if (src[ptr->slen] == '/' ||
+ src[ptr->slen] == 0) {
+ if ((src[ptr->slen] == '/') &&
+ (strcmp(ptr->dst, "/") == 0))
+ len = ptr->slen + 1;
+ else
+ len = ptr->slen;
+ if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0)
+ return NULL;
+ return dst;
+ }
+ }
+ ptr = ptr->next;
+ }
+ return NULL;
+}
+
+static int selabel_subs_init(const char *path, struct selabel_digest *digest,
+ struct selabel_sub **out_subs)
+{
+ char buf[1024];
+ FILE *cfg = fopen(path, "re");
+ struct selabel_sub *list = NULL, *sub = NULL;
+ struct stat sb;
+ int status = -1;
+
+ *out_subs = NULL;
+ if (!cfg) {
+ /* If the file does not exist, it is not fatal */
+ return (errno == ENOENT) ? 0 : -1;
+ }
+
+ if (fstat(fileno(cfg), &sb) < 0)
+ goto out;
+
+ while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) {
+ char *ptr = NULL;
+ char *src = buf;
+ char *dst = NULL;
+
+ while (*src && isspace(*src))
+ src++;
+ if (src[0] == '#') continue;
+ ptr = src;
+ while (*ptr && ! isspace(*ptr))
+ ptr++;
+ *ptr++ = '\0';
+ if (! *src) continue;
+
+ dst = ptr;
+ while (*dst && isspace(*dst))
+ dst++;
+ ptr=dst;
+ while (*ptr && ! isspace(*ptr))
+ ptr++;
+ *ptr='\0';
+ if (! *dst)
+ continue;
+
+ sub = malloc(sizeof(*sub));
+ if (! sub)
+ goto err;
+ memset(sub, 0, sizeof(*sub));
+
+ sub->src=strdup(src);
+ if (! sub->src)
+ goto err;
+
+ sub->dst=strdup(dst);
+ if (! sub->dst)
+ goto err;
+
+ sub->slen = strlen(src);
+ sub->next = list;
+ list = sub;
+ sub = NULL;
+ }
+
+ if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0)
+ goto err;
+
+ *out_subs = list;
+ status = 0;
+
+out:
+ fclose(cfg);
+ return status;
+err:
+ if (sub)
+ free(sub->src);
+ free(sub);
+ while (list) {
+ sub = list->next;
+ free(list->src);
+ free(list->dst);
+ free(list);
+ list = sub;
+ }
+ goto out;
+}
+
+static char *selabel_sub_key(struct saved_data *data, const char *key)
+{
+ char *ptr = NULL;
+ char *dptr = NULL;
+
+ ptr = selabel_sub(data->subs, key);
+ if (ptr) {
+ dptr = selabel_sub(data->dist_subs, ptr);
+ if (dptr) {
+ free(ptr);
+ ptr = dptr;
+ }
+ } else {
+ ptr = selabel_sub(data->dist_subs, key);
+ }
+ if (ptr)
+ return ptr;
+
+ return NULL;
+}
+
static void closef(struct selabel_handle *rec);
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
@@ -620,20 +764,30 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
char subs_file[PATH_MAX + 1];
/* Process local and distribution substitution files */
if (!path_provided) {
- rec->dist_subs =
- selabel_subs_init(selinux_file_context_subs_dist_path(),
- rec->dist_subs, rec->digest);
- rec->subs = selabel_subs_init(selinux_file_context_subs_path(),
- rec->subs, rec->digest);
+ status = selabel_subs_init(
+ selinux_file_context_subs_dist_path(),
+ rec->digest, &data->dist_subs);
+ if (status)
+ goto finish;
+ status = selabel_subs_init(selinux_file_context_subs_path(),
+ rec->digest, &data->subs);
+ if (status)
+ goto finish;
rec->spec_files[0] = strdup(selinux_file_context_path());
if (rec->spec_files[0] == NULL)
goto finish;
} else {
for (i = 0; i < num_paths; i++) {
snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", rec->spec_files[i]);
- rec->dist_subs = selabel_subs_init(subs_file, rec->dist_subs, rec->digest);
+ status = selabel_subs_init(subs_file, rec->digest,
+ &data->dist_subs);
+ if (status)
+ goto finish;
snprintf(subs_file, sizeof(subs_file), "%s.subs", rec->spec_files[i]);
- rec->subs = selabel_subs_init(subs_file, rec->subs, rec->digest);
+ status = selabel_subs_init(subs_file, rec->digest,
+ &data->subs);
+ if (status)
+ goto finish;
}
}
#else
@@ -698,11 +852,15 @@ static void closef(struct selabel_handle *rec)
/* make sure successive ->func_close() calls are harmless */
rec->data = NULL;
+ selabel_subs_fini(data->subs);
+ selabel_subs_fini(data->dist_subs);
+
for (i = 0; i < data->nspec; i++) {
spec = &data->spec_arr[i];
free(spec->lr.ctx_trans);
free(spec->lr.ctx_raw);
regex_data_free(spec->regex);
+ __pthread_mutex_destroy(&spec->regex_lock);
if (spec->from_mmap)
continue;
free(spec->regex_str);
@@ -745,6 +903,7 @@ static struct spec *lookup_common(struct selabel_handle *rec,
char *clean_key = NULL;
const char *prev_slash, *next_slash;
unsigned int sofar = 0;
+ char *sub = NULL;
if (!data->nspec) {
errno = ENOENT;
@@ -767,6 +926,10 @@ static struct spec *lookup_common(struct selabel_handle *rec,
key = clean_key;
}
+ sub = selabel_sub_key(data, key);
+ if (sub)
+ key = sub;
+
buf = key;
file_stem = find_stem_from_file(data, &buf);
mode &= S_IFMT;
@@ -815,6 +978,7 @@ static struct spec *lookup_common(struct selabel_handle *rec,
finish:
free(clean_key);
+ free(sub);
return ret;
}