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 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 @@ bool prop_area::foreach(void (*propfn)(const prop_info* pi, void* cookie), void*
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 @@ static context_node* contexts = nullptr;
* 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 @@ static bool check_access(context_node* cnode) {
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 @@ static prop_area* get_prop_area_for_name(const char* name) {
}
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 int read_spec_entries(char *line_buf, int num_args, ...)
}
static bool initialize_properties() {
list_free(&prefixes);
list_free(&contexts);
FILE* file = fopen("/property_contexts", "re");
if (!file) {
@ -927,7 +971,7 @@ static bool initialize_properties() {
}
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 @@ static bool is_dir(const char* pathname) {
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 @@ int __system_properties_init()
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_set_filename(const char *filename)
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 @@ int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
}
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;