Merge "Reset access to system properties on reinitialization"

This commit is contained in:
Tom Cherry 2015-12-17 17:54:05 +00:00 committed by Gerrit Code Review
commit dd57119ced

View File

@ -200,6 +200,7 @@ static char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
static bool compat_mode = false; static bool compat_mode = false;
static size_t pa_data_size; static size_t pa_data_size;
static size_t pa_size; static size_t pa_size;
static bool initialized = false;
// NOTE: This isn't static because system_properties_compat.c // NOTE: This isn't static because system_properties_compat.c
// requires it. // requires it.
@ -642,22 +643,33 @@ bool prop_area::foreach(void (*propfn)(const prop_info* pi, void* cookie), void*
return foreach_property(root_node(), propfn, cookie); return foreach_property(root_node(), propfn, cookie);
} }
struct context_node { class context_node {
context_node(struct context_node* next, const char* context, prop_area* pa) public:
: context(strdup(context)), pa(pa), checked_access(false), next(next) { context_node(context_node* next, const char* context, prop_area* pa)
lock.init(false); : next(next), context_(strdup(context)), pa_(pa), no_access_(false) {
lock_.init(false);
} }
~context_node() { ~context_node() {
if (pa) { unmap();
munmap(pa, pa_size); free(context_);
}
free(context);
} }
Lock lock; bool open(bool access_rw, bool* fsetxattr_failed);
char* context; bool check_access_and_open();
prop_area* pa; void reset_access();
bool checked_access;
struct context_node* next; 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 { struct prefix_node {
@ -733,32 +745,50 @@ static context_node* contexts = nullptr;
* allocation of memory for each filename. * allocation of memory for each filename.
*/ */
static bool open_prop_file(context_node* cnode, bool access_rw, bool* fsetxattr_failed) { bool context_node::open(bool access_rw, bool* fsetxattr_failed) {
cnode->lock.lock(); lock_.lock();
if (cnode->pa) { if (pa_) {
cnode->lock.unlock(); lock_.unlock();
return true; return true;
} }
char filename[PROP_FILENAME_MAX]; 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) { if (len < 0 || len > PROP_FILENAME_MAX) {
cnode->lock.unlock(); lock_.unlock();
return false; return false;
} }
if (access_rw) { if (access_rw) {
cnode->pa = map_prop_area_rw(filename, cnode->context, fsetxattr_failed); pa_ = map_prop_area_rw(filename, context_, fsetxattr_failed);
} else { } else {
cnode->pa = map_prop_area(filename, false); pa_ = map_prop_area(filename, false);
} }
cnode->lock.unlock(); lock_.unlock();
return cnode->pa; 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]; 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) { if (len < 0 || len > PROP_FILENAME_MAX) {
return false; return false;
} }
@ -766,6 +796,18 @@ static bool check_access(context_node* cnode) {
return access(filename, R_OK) == 0; 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) { static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
char filename[PROP_FILENAME_MAX]; char filename[PROP_FILENAME_MAX];
int len = snprintf(filename, sizeof(filename), "%s/properties_serial", property_filename); int len = snprintf(filename, sizeof(filename), "%s/properties_serial", property_filename);
@ -792,10 +834,15 @@ static prop_area* get_prop_area_for_name(const char* name) {
} }
auto cnode = entry->context; auto cnode = entry->context;
if (!cnode->pa) { if (!cnode->pa()) {
open_prop_file(cnode, false, nullptr); /*
* 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 int read_spec_entries(char *line_buf, int num_args, ...)
} }
static bool initialize_properties() { static bool initialize_properties() {
list_free(&prefixes);
list_free(&contexts);
FILE* file = fopen("/property_contexts", "re"); FILE* file = fopen("/property_contexts", "re");
if (!file) { if (!file) {
@ -927,7 +971,7 @@ static bool initialize_properties() {
} }
auto old_context = list_find( 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) { if (old_context) {
list_add_after_len(&prefixes, prop_prefix, old_context); list_add_after_len(&prefixes, prop_prefix, old_context);
} else { } else {
@ -951,15 +995,27 @@ static bool is_dir(const char* pathname) {
return S_ISDIR(info.st_mode); 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() int __system_properties_init()
{ {
if (initialized) {
list_foreach(contexts, [](context_node* l) { l->reset_access(); });
return 0;
}
if (is_dir(property_filename)) { if (is_dir(property_filename)) {
if (!initialize_properties()) { if (!initialize_properties()) {
return -1; return -1;
} }
if (!map_system_property_area(false, nullptr)) { if (!map_system_property_area(false, nullptr)) {
list_free(&prefixes); free_and_unmap_contexts();
list_free(&contexts);
return -1; return -1;
} }
} else { } else {
@ -970,6 +1026,7 @@ int __system_properties_init()
list_add(&contexts, "legacy_system_prop_area", __system_property_area__); list_add(&contexts, "legacy_system_prop_area", __system_property_area__);
list_add_after_len(&prefixes, "*", contexts); list_add_after_len(&prefixes, "*", contexts);
} }
initialized = true;
return 0; return 0;
} }
@ -985,22 +1042,23 @@ int __system_property_set_filename(const char *filename)
int __system_property_area_init() int __system_property_area_init()
{ {
free_and_unmap_contexts();
mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if (!initialize_properties()) { if (!initialize_properties()) {
return -1; return -1;
} }
bool open_prop_file_failed = false; bool open_failed = false;
bool fsetxattr_failed = false; bool fsetxattr_failed = false;
list_foreach(contexts, [&fsetxattr_failed, &open_prop_file_failed](context_node* l) { list_foreach(contexts, [&fsetxattr_failed, &open_failed](context_node* l) {
if (!open_prop_file(l, true, &fsetxattr_failed)) { if (!l->open(true, &fsetxattr_failed)) {
open_prop_file_failed = true; open_failed = true;
} }
}); });
if (open_prop_file_failed || !map_system_property_area(true, &fsetxattr_failed)) { if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {
list_free(&prefixes); free_and_unmap_contexts();
list_free(&contexts);
return -1; return -1;
} }
initialized = true;
return fsetxattr_failed ? -2 : 0; return fsetxattr_failed ? -2 : 0;
} }
@ -1226,14 +1284,8 @@ int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
} }
list_foreach(contexts, [propfn, cookie](context_node* l) { list_foreach(contexts, [propfn, cookie](context_node* l) {
if (!l->pa && !l->checked_access) { if (l->check_access_and_open()) {
if (check_access(l)) { l->pa()->foreach(propfn, cookie);
open_prop_file(l, false, nullptr);
}
l->checked_access = true;
}
if (l->pa) {
l->pa->foreach(propfn, cookie);
} }
}); });
return 0; return 0;