Merge "Reset access to system properties on reinitialization"
This commit is contained in:
commit
dd57119ced
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user