Merge "Reset access to system properties on reinitialization"
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index b9a373e..2720455 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -200,6 +200,7 @@
static bool compat_mode = false;
static size_t pa_data_size;
static size_t pa_size;
+static bool initialized = false;
// NOTE: This isn't static because system_properties_compat.c
// requires it.
@@ -642,22 +643,33 @@
return foreach_property(root_node(), propfn, cookie);
}
-struct context_node {
- context_node(struct context_node* next, const char* context, prop_area* pa)
- : context(strdup(context)), pa(pa), checked_access(false), next(next) {
- lock.init(false);
+class context_node {
+public:
+ context_node(context_node* next, const char* context, prop_area* pa)
+ : next(next), context_(strdup(context)), pa_(pa), no_access_(false) {
+ lock_.init(false);
}
~context_node() {
- if (pa) {
- munmap(pa, pa_size);
- }
- free(context);
+ unmap();
+ free(context_);
}
- Lock lock;
- char* context;
- prop_area* pa;
- bool checked_access;
- struct context_node* next;
+ bool open(bool access_rw, bool* fsetxattr_failed);
+ bool check_access_and_open();
+ void reset_access();
+
+ const char* context() const { return context_; }
+ prop_area* pa() { return pa_; }
+
+ context_node* next;
+
+private:
+ bool check_access();
+ void unmap();
+
+ Lock lock_;
+ char* context_;
+ prop_area* pa_;
+ bool no_access_;
};
struct prefix_node {
@@ -733,32 +745,50 @@
* allocation of memory for each filename.
*/
-static bool open_prop_file(context_node* cnode, bool access_rw, bool* fsetxattr_failed) {
- cnode->lock.lock();
- if (cnode->pa) {
- cnode->lock.unlock();
+bool context_node::open(bool access_rw, bool* fsetxattr_failed) {
+ lock_.lock();
+ if (pa_) {
+ lock_.unlock();
return true;
}
char filename[PROP_FILENAME_MAX];
- int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, cnode->context);
+ int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, context_);
if (len < 0 || len > PROP_FILENAME_MAX) {
- cnode->lock.unlock();
+ lock_.unlock();
return false;
}
if (access_rw) {
- cnode->pa = map_prop_area_rw(filename, cnode->context, fsetxattr_failed);
+ pa_ = map_prop_area_rw(filename, context_, fsetxattr_failed);
} else {
- cnode->pa = map_prop_area(filename, false);
+ pa_ = map_prop_area(filename, false);
}
- cnode->lock.unlock();
- return cnode->pa;
+ lock_.unlock();
+ return pa_;
}
-static bool check_access(context_node* cnode) {
+bool context_node::check_access_and_open() {
+ if (!pa_ && !no_access_) {
+ if (!check_access() || !open(false, nullptr)) {
+ no_access_ = true;
+ }
+ }
+ return pa_;
+}
+
+void context_node::reset_access() {
+ if (!check_access()) {
+ unmap();
+ no_access_ = true;
+ } else {
+ no_access_ = false;
+ }
+}
+
+bool context_node::check_access() {
char filename[PROP_FILENAME_MAX];
- int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, cnode->context);
+ int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, context_);
if (len < 0 || len > PROP_FILENAME_MAX) {
return false;
}
@@ -766,6 +796,18 @@
return access(filename, R_OK) == 0;
}
+void context_node::unmap() {
+ if (!pa_) {
+ return;
+ }
+
+ munmap(pa_, pa_size);
+ if (pa_ == __system_property_area__) {
+ __system_property_area__ = nullptr;
+ }
+ pa_ = nullptr;
+}
+
static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
char filename[PROP_FILENAME_MAX];
int len = snprintf(filename, sizeof(filename), "%s/properties_serial", property_filename);
@@ -792,10 +834,15 @@
}
auto cnode = entry->context;
- if (!cnode->pa) {
- open_prop_file(cnode, false, nullptr);
+ if (!cnode->pa()) {
+ /*
+ * We explicitly do not check no_access_ in this case because unlike the
+ * case of foreach(), we want to generate an selinux audit for each
+ * non-permitted property access in this function.
+ */
+ cnode->open(false, nullptr);
}
- return cnode->pa;
+ return cnode->pa();
}
/*
@@ -892,9 +939,6 @@
}
static bool initialize_properties() {
- list_free(&prefixes);
- list_free(&contexts);
-
FILE* file = fopen("/property_contexts", "re");
if (!file) {
@@ -927,7 +971,7 @@
}
auto old_context = list_find(
- contexts, [context](context_node* l) { return !strcmp(l->context, context); });
+ contexts, [context](context_node* l) { return !strcmp(l->context(), context); });
if (old_context) {
list_add_after_len(&prefixes, prop_prefix, old_context);
} else {
@@ -951,15 +995,27 @@
return S_ISDIR(info.st_mode);
}
+static void free_and_unmap_contexts() {
+ list_free(&prefixes);
+ list_free(&contexts);
+ if (__system_property_area__) {
+ munmap(__system_property_area__, pa_size);
+ __system_property_area__ = nullptr;
+ }
+}
+
int __system_properties_init()
{
+ if (initialized) {
+ list_foreach(contexts, [](context_node* l) { l->reset_access(); });
+ return 0;
+ }
if (is_dir(property_filename)) {
if (!initialize_properties()) {
return -1;
}
if (!map_system_property_area(false, nullptr)) {
- list_free(&prefixes);
- list_free(&contexts);
+ free_and_unmap_contexts();
return -1;
}
} else {
@@ -970,6 +1026,7 @@
list_add(&contexts, "legacy_system_prop_area", __system_property_area__);
list_add_after_len(&prefixes, "*", contexts);
}
+ initialized = true;
return 0;
}
@@ -985,22 +1042,23 @@
int __system_property_area_init()
{
+ free_and_unmap_contexts();
mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if (!initialize_properties()) {
return -1;
}
- bool open_prop_file_failed = false;
+ bool open_failed = false;
bool fsetxattr_failed = false;
- list_foreach(contexts, [&fsetxattr_failed, &open_prop_file_failed](context_node* l) {
- if (!open_prop_file(l, true, &fsetxattr_failed)) {
- open_prop_file_failed = true;
+ list_foreach(contexts, [&fsetxattr_failed, &open_failed](context_node* l) {
+ if (!l->open(true, &fsetxattr_failed)) {
+ open_failed = true;
}
});
- if (open_prop_file_failed || !map_system_property_area(true, &fsetxattr_failed)) {
- list_free(&prefixes);
- list_free(&contexts);
+ if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {
+ free_and_unmap_contexts();
return -1;
}
+ initialized = true;
return fsetxattr_failed ? -2 : 0;
}
@@ -1226,14 +1284,8 @@
}
list_foreach(contexts, [propfn, cookie](context_node* l) {
- if (!l->pa && !l->checked_access) {
- if (check_access(l)) {
- open_prop_file(l, false, nullptr);
- }
- l->checked_access = true;
- }
- if (l->pa) {
- l->pa->foreach(propfn, cookie);
+ if (l->check_access_and_open()) {
+ l->pa()->foreach(propfn, cookie);
}
});
return 0;