Implement Library Load Order Randomization
Bug: http://b/24047022 Change-Id: I36e05b403bfbaae8542a95147f9114a8b9c8ac0e
This commit is contained in:
parent
cf1cbbe432
commit
4f7a7ad3fe
@ -50,7 +50,6 @@
|
|||||||
#include "private/KernelArgumentBlock.h"
|
#include "private/KernelArgumentBlock.h"
|
||||||
#include "private/ScopedPthreadMutexLocker.h"
|
#include "private/ScopedPthreadMutexLocker.h"
|
||||||
#include "private/ScopeGuard.h"
|
#include "private/ScopeGuard.h"
|
||||||
#include "private/UniquePtr.h"
|
|
||||||
|
|
||||||
#include "linker.h"
|
#include "linker.h"
|
||||||
#include "linker_block_allocator.h"
|
#include "linker_block_allocator.h"
|
||||||
@ -325,7 +324,10 @@ static void parse_LD_LIBRARY_PATH(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void soinfo::set_dt_runpath(const char* path) {
|
void soinfo::set_dt_runpath(const char* path) {
|
||||||
if (!has_min_version(2)) return;
|
if (!has_min_version(2)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
parse_path(path, ":", &dt_runpath_);
|
parse_path(path, ":", &dt_runpath_);
|
||||||
|
|
||||||
std::string origin = dirname(get_realpath());
|
std::string origin = dirname(get_realpath());
|
||||||
@ -897,17 +899,17 @@ class LoadTask {
|
|||||||
public:
|
public:
|
||||||
struct deleter_t {
|
struct deleter_t {
|
||||||
void operator()(LoadTask* t) {
|
void operator()(LoadTask* t) {
|
||||||
|
t->~LoadTask();
|
||||||
TypeBasedAllocator<LoadTask>::free(t);
|
TypeBasedAllocator<LoadTask>::free(t);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef UniquePtr<LoadTask, deleter_t> unique_ptr;
|
|
||||||
|
|
||||||
static deleter_t deleter;
|
static deleter_t deleter;
|
||||||
|
|
||||||
static LoadTask* create(const char* name, soinfo* needed_by) {
|
static LoadTask* create(const char* name, soinfo* needed_by,
|
||||||
|
std::unordered_map<const soinfo*, ElfReader>* readers_map) {
|
||||||
LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
|
LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
|
||||||
return new (ptr) LoadTask(name, needed_by);
|
return new (ptr) LoadTask(name, needed_by, readers_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* get_name() const {
|
const char* get_name() const {
|
||||||
@ -917,12 +919,94 @@ class LoadTask {
|
|||||||
soinfo* get_needed_by() const {
|
soinfo* get_needed_by() const {
|
||||||
return needed_by_;
|
return needed_by_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
soinfo* get_soinfo() const {
|
||||||
|
return si_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_soinfo(soinfo* si) {
|
||||||
|
si_ = si;
|
||||||
|
}
|
||||||
|
|
||||||
|
off64_t get_file_offset() const {
|
||||||
|
return file_offset_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_file_offset(off64_t offset) {
|
||||||
|
file_offset_ = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_fd() const {
|
||||||
|
return fd_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_fd(int fd, bool assume_ownership) {
|
||||||
|
fd_ = fd;
|
||||||
|
close_fd_ = assume_ownership;
|
||||||
|
}
|
||||||
|
|
||||||
|
const android_dlextinfo* get_extinfo() const {
|
||||||
|
return extinfo_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_extinfo(const android_dlextinfo* extinfo) {
|
||||||
|
extinfo_ = extinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElfReader& get_elf_reader() const {
|
||||||
|
CHECK(si_ != nullptr);
|
||||||
|
return (*elf_readers_map_)[si_];
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfReader& get_elf_reader() {
|
||||||
|
CHECK(si_ != nullptr);
|
||||||
|
return (*elf_readers_map_)[si_];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
|
||||||
|
return elf_readers_map_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read(const char* realpath, off64_t file_size) {
|
||||||
|
ElfReader& elf_reader = get_elf_reader();
|
||||||
|
return elf_reader.Read(realpath, fd_, file_offset_, file_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load() {
|
||||||
|
ElfReader& elf_reader = get_elf_reader();
|
||||||
|
if (!elf_reader.Load(extinfo_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
si_->base = elf_reader.load_start();
|
||||||
|
si_->size = elf_reader.load_size();
|
||||||
|
si_->load_bias = elf_reader.load_bias();
|
||||||
|
si_->phnum = elf_reader.phdr_count();
|
||||||
|
si_->phdr = elf_reader.loaded_phdr();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LoadTask(const char* name, soinfo* needed_by)
|
LoadTask(const char* name, soinfo* needed_by,
|
||||||
: name_(name), needed_by_(needed_by) {}
|
std::unordered_map<const soinfo*, ElfReader>* readers_map)
|
||||||
|
: name_(name), needed_by_(needed_by), si_(nullptr),
|
||||||
|
fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map) {}
|
||||||
|
|
||||||
|
~LoadTask() {
|
||||||
|
if (fd_ != -1 && close_fd_) {
|
||||||
|
close(fd_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char* name_;
|
const char* name_;
|
||||||
soinfo* needed_by_;
|
soinfo* needed_by_;
|
||||||
|
soinfo* si_;
|
||||||
|
const android_dlextinfo* extinfo_;
|
||||||
|
int fd_;
|
||||||
|
bool close_fd_;
|
||||||
|
off64_t file_offset_;
|
||||||
|
std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
|
||||||
};
|
};
|
||||||
@ -934,7 +1018,7 @@ using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
|
|||||||
|
|
||||||
typedef linked_list_t<soinfo> SoinfoLinkedList;
|
typedef linked_list_t<soinfo> SoinfoLinkedList;
|
||||||
typedef linked_list_t<const char> StringLinkedList;
|
typedef linked_list_t<const char> StringLinkedList;
|
||||||
typedef linked_list_t<LoadTask> LoadTaskList;
|
typedef std::vector<LoadTask*> LoadTaskList;
|
||||||
|
|
||||||
|
|
||||||
// This function walks down the tree of soinfo dependencies
|
// This function walks down the tree of soinfo dependencies
|
||||||
@ -1336,7 +1420,7 @@ static int open_library(ZipArchiveCache* zip_archive_cache,
|
|||||||
|
|
||||||
// Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
|
// Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
|
||||||
int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths, realpath);
|
int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths, realpath);
|
||||||
if (fd == -1 && needed_by) {
|
if (fd == -1 && needed_by != nullptr) {
|
||||||
fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
|
fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1364,36 +1448,48 @@ static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unu
|
|||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
static void for_each_dt_needed(const soinfo* si, F action) {
|
static void for_each_dt_needed(const soinfo* si, F action) {
|
||||||
for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
|
for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
|
||||||
if (d->d_tag == DT_NEEDED) {
|
if (d->d_tag == DT_NEEDED) {
|
||||||
action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
|
action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo* load_library(int fd, off64_t file_offset,
|
template<typename F>
|
||||||
LoadTaskList& load_tasks,
|
static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
|
||||||
const char* name, int rtld_flags,
|
for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
|
||||||
const android_dlextinfo* extinfo,
|
if (d->d_tag == DT_NEEDED) {
|
||||||
const std::string& realpath) {
|
action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool load_library(LoadTask* task,
|
||||||
|
LoadTaskList* load_tasks,
|
||||||
|
int rtld_flags,
|
||||||
|
const std::string& realpath) {
|
||||||
|
off64_t file_offset = task->get_file_offset();
|
||||||
|
const char* name = task->get_name();
|
||||||
|
const android_dlextinfo* extinfo = task->get_extinfo();
|
||||||
|
|
||||||
if ((file_offset % PAGE_SIZE) != 0) {
|
if ((file_offset % PAGE_SIZE) != 0) {
|
||||||
DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
|
DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
if (file_offset < 0) {
|
if (file_offset < 0) {
|
||||||
DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
|
DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat file_stat;
|
struct stat file_stat;
|
||||||
if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
|
if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
|
||||||
DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
|
DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
if (file_offset >= file_stat.st_size) {
|
if (file_offset >= file_stat.st_size) {
|
||||||
DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
|
DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
|
||||||
name, file_offset, file_stat.st_size);
|
name, file_offset, file_stat.st_size);
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for symlink and other situations where
|
// Check for symlink and other situations where
|
||||||
@ -1407,48 +1503,59 @@ static soinfo* load_library(int fd, off64_t file_offset,
|
|||||||
si->get_file_offset() == file_offset) {
|
si->get_file_offset() == file_offset) {
|
||||||
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
|
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
|
||||||
"will return existing soinfo", name, si->get_realpath());
|
"will return existing soinfo", name, si->get_realpath());
|
||||||
return si;
|
task->set_soinfo(si);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rtld_flags & RTLD_NOLOAD) != 0) {
|
if ((rtld_flags & RTLD_NOLOAD) != 0) {
|
||||||
DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
|
DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Read the ELF header and load the segments.
|
|
||||||
ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
|
|
||||||
if (!elf_reader.Load(extinfo)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
|
soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
|
||||||
if (si == nullptr) {
|
if (si == nullptr) {
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
|
||||||
si->base = elf_reader.load_start();
|
|
||||||
si->size = elf_reader.load_size();
|
|
||||||
si->load_bias = elf_reader.load_bias();
|
|
||||||
si->phnum = elf_reader.phdr_count();
|
|
||||||
si->phdr = elf_reader.loaded_phdr();
|
|
||||||
|
|
||||||
if (!si->prelink_image()) {
|
|
||||||
soinfo_free(si);
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_dt_needed(si, [&] (const char* name) {
|
task->set_soinfo(si);
|
||||||
load_tasks.push_back(LoadTask::create(name, si));
|
|
||||||
|
// Read the ELF header and some of the segments.
|
||||||
|
if (!task->read(realpath.c_str(), file_stat.st_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find and set DT_RUNPATH and dt_soname
|
||||||
|
// Note that these field values are temporary and are
|
||||||
|
// going to be overwritten on soinfo::prelink_image
|
||||||
|
// with values from PT_LOAD segments.
|
||||||
|
const ElfReader& elf_reader = task->get_elf_reader();
|
||||||
|
for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
|
||||||
|
if (d->d_tag == DT_RUNPATH) {
|
||||||
|
si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
|
||||||
|
}
|
||||||
|
if (d->d_tag == DT_SONAME) {
|
||||||
|
si->set_soname(elf_reader.get_string(d->d_un.d_val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
|
||||||
|
load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
|
||||||
});
|
});
|
||||||
|
|
||||||
return si;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo* load_library(ZipArchiveCache* zip_archive_cache,
|
static bool load_library(LoadTask* task,
|
||||||
LoadTaskList& load_tasks, const char* name,
|
ZipArchiveCache* zip_archive_cache,
|
||||||
soinfo* needed_by, int rtld_flags,
|
LoadTaskList* load_tasks,
|
||||||
const android_dlextinfo* extinfo) {
|
int rtld_flags) {
|
||||||
|
const char* name = task->get_name();
|
||||||
|
soinfo* needed_by = task->get_needed_by();
|
||||||
|
const android_dlextinfo* extinfo = task->get_extinfo();
|
||||||
|
|
||||||
off64_t file_offset;
|
off64_t file_offset;
|
||||||
std::string realpath;
|
std::string realpath;
|
||||||
if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
|
if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
|
||||||
@ -1462,18 +1569,23 @@ static soinfo* load_library(ZipArchiveCache* zip_archive_cache,
|
|||||||
"Will use given name.", name);
|
"Will use given name.", name);
|
||||||
realpath = name;
|
realpath = name;
|
||||||
}
|
}
|
||||||
return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath);
|
|
||||||
|
task->set_fd(extinfo->library_fd, false);
|
||||||
|
task->set_file_offset(file_offset);
|
||||||
|
return load_library(task, load_tasks, rtld_flags, realpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the file.
|
// Open the file.
|
||||||
int fd = open_library(zip_archive_cache, name, needed_by, &file_offset, &realpath);
|
int fd = open_library(zip_archive_cache, name, needed_by, &file_offset, &realpath);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
DL_ERR("library \"%s\" not found", name);
|
DL_ERR("library \"%s\" not found", name);
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath);
|
|
||||||
close(fd);
|
task->set_fd(fd, true);
|
||||||
return result;
|
task->set_file_offset(file_offset);
|
||||||
|
|
||||||
|
return load_library(task, load_tasks, rtld_flags, realpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if library was found and false in 2 cases
|
// Returns true if library was found and false in 2 cases
|
||||||
@ -1513,31 +1625,35 @@ static bool find_loaded_library_by_soname(const char* name, soinfo** candidate)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo* find_library_internal(ZipArchiveCache* zip_archive_cache,
|
static bool find_library_internal(LoadTask* task,
|
||||||
LoadTaskList& load_tasks, const char* name,
|
ZipArchiveCache* zip_archive_cache,
|
||||||
soinfo* needed_by, int rtld_flags,
|
LoadTaskList* load_tasks,
|
||||||
const android_dlextinfo* extinfo) {
|
int rtld_flags) {
|
||||||
soinfo* candidate;
|
soinfo* candidate;
|
||||||
|
|
||||||
if (find_loaded_library_by_soname(name, &candidate)) {
|
if (find_loaded_library_by_soname(task->get_name(), &candidate)) {
|
||||||
return candidate;
|
task->set_soinfo(candidate);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Library might still be loaded, the accurate detection
|
// Library might still be loaded, the accurate detection
|
||||||
// of this fact is done by load_library.
|
// of this fact is done by load_library.
|
||||||
TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
|
TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
|
||||||
name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
|
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
|
||||||
|
|
||||||
soinfo* si = load_library(zip_archive_cache, load_tasks, name, needed_by, rtld_flags, extinfo);
|
if (load_library(task, zip_archive_cache, load_tasks, rtld_flags)) {
|
||||||
|
return true;
|
||||||
// In case we were unable to load the library but there
|
} else {
|
||||||
// is a candidate loaded under the same soname but different
|
// In case we were unable to load the library but there
|
||||||
// sdk level - return it anyways.
|
// is a candidate loaded under the same soname but different
|
||||||
if (si == nullptr && candidate != nullptr) {
|
// sdk level - return it anyways.
|
||||||
si = candidate;
|
if (candidate != nullptr) {
|
||||||
|
task->set_soinfo(candidate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return si;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void soinfo_unload(soinfo* si);
|
static void soinfo_unload(soinfo* si);
|
||||||
@ -1560,6 +1676,14 @@ static soinfo::soinfo_list_t make_global_group() {
|
|||||||
return global_group;
|
return global_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void shuffle(std::vector<LoadTask*>* v) {
|
||||||
|
for (size_t i = 0, size = v->size(); i < size; ++i) {
|
||||||
|
size_t n = size - i;
|
||||||
|
size_t r = arc4random_uniform(n);
|
||||||
|
std::swap((*v)[n-1], (*v)[r]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add_as_children - add first-level loaded libraries (i.e. library_names[], but
|
// add_as_children - add first-level loaded libraries (i.e. library_names[], but
|
||||||
// not their transitive dependencies) as children of the start_with library.
|
// not their transitive dependencies) as children of the start_with library.
|
||||||
// This is false when find_libraries is called for dlopen(), when newly loaded
|
// This is false when find_libraries is called for dlopen(), when newly loaded
|
||||||
@ -1573,9 +1697,11 @@ static bool find_libraries(soinfo* start_with,
|
|||||||
bool add_as_children) {
|
bool add_as_children) {
|
||||||
// Step 0: prepare.
|
// Step 0: prepare.
|
||||||
LoadTaskList load_tasks;
|
LoadTaskList load_tasks;
|
||||||
|
std::unordered_map<const soinfo*, ElfReader> readers_map;
|
||||||
|
|
||||||
for (size_t i = 0; i < library_names_count; ++i) {
|
for (size_t i = 0; i < library_names_count; ++i) {
|
||||||
const char* name = library_names[i];
|
const char* name = library_names[i];
|
||||||
load_tasks.push_back(LoadTask::create(name, start_with));
|
load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct global_group.
|
// Construct global_group.
|
||||||
@ -1597,12 +1723,14 @@ static bool find_libraries(soinfo* start_with,
|
|||||||
// list of libraries to link - see step 2.
|
// list of libraries to link - see step 2.
|
||||||
size_t soinfos_count = 0;
|
size_t soinfos_count = 0;
|
||||||
|
|
||||||
|
auto scope_guard = make_scope_guard([&]() {
|
||||||
|
for (LoadTask* t : load_tasks) {
|
||||||
|
LoadTask::deleter(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
auto failure_guard = make_scope_guard([&]() {
|
auto failure_guard = make_scope_guard([&]() {
|
||||||
// Housekeeping
|
// Housekeeping
|
||||||
load_tasks.for_each([] (LoadTask* t) {
|
|
||||||
LoadTask::deleter(t);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (size_t i = 0; i<soinfos_count; ++i) {
|
for (size_t i = 0; i<soinfos_count; ++i) {
|
||||||
soinfo_unload(soinfos[i]);
|
soinfo_unload(soinfos[i]);
|
||||||
}
|
}
|
||||||
@ -1610,20 +1738,21 @@ static bool find_libraries(soinfo* start_with,
|
|||||||
|
|
||||||
ZipArchiveCache zip_archive_cache;
|
ZipArchiveCache zip_archive_cache;
|
||||||
|
|
||||||
// Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
|
// Step 1: expand the list of load_tasks to include
|
||||||
for (LoadTask::unique_ptr task(load_tasks.pop_front());
|
// all DT_NEEDED libraries (do not load them just yet)
|
||||||
task.get() != nullptr; task.reset(load_tasks.pop_front())) {
|
for (size_t i = 0; i<load_tasks.size(); ++i) {
|
||||||
|
LoadTask* task = load_tasks[i];
|
||||||
soinfo* needed_by = task->get_needed_by();
|
soinfo* needed_by = task->get_needed_by();
|
||||||
|
|
||||||
bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
|
bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
|
||||||
|
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
|
||||||
|
|
||||||
soinfo* si = find_library_internal(&zip_archive_cache, load_tasks,
|
if(!find_library_internal(task, &zip_archive_cache, &load_tasks, rtld_flags)) {
|
||||||
task->get_name(), needed_by, rtld_flags,
|
|
||||||
is_dt_needed ? nullptr : extinfo);
|
|
||||||
|
|
||||||
if (si == nullptr) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
soinfo* si = task->get_soinfo();
|
||||||
|
|
||||||
if (is_dt_needed) {
|
if (is_dt_needed) {
|
||||||
needed_by->add_child(si);
|
needed_by->add_child(si);
|
||||||
}
|
}
|
||||||
@ -1635,11 +1764,6 @@ static bool find_libraries(soinfo* start_with,
|
|||||||
// When ld_preloads is not null, the first
|
// When ld_preloads is not null, the first
|
||||||
// ld_preloads_count libs are in fact ld_preloads.
|
// ld_preloads_count libs are in fact ld_preloads.
|
||||||
if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
|
if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
|
||||||
// Add LD_PRELOADed libraries to the global group for future runs.
|
|
||||||
// There is no need to explicitly add them to the global group
|
|
||||||
// for this run because they are going to appear in the local
|
|
||||||
// group in the correct order.
|
|
||||||
si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
|
|
||||||
ld_preloads->push_back(si);
|
ld_preloads->push_back(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1648,7 +1772,47 @@ static bool find_libraries(soinfo* start_with,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: link libraries.
|
// Step 2: Load libraries in random order (see b/24047022)
|
||||||
|
LoadTaskList load_list;
|
||||||
|
for (auto&& task : load_tasks) {
|
||||||
|
soinfo* si = task->get_soinfo();
|
||||||
|
auto pred = [&](const LoadTask* t) {
|
||||||
|
return t->get_soinfo() == si;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!si->is_linked() &&
|
||||||
|
std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
|
||||||
|
load_list.push_back(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shuffle(&load_list);
|
||||||
|
|
||||||
|
for (auto&& task : load_list) {
|
||||||
|
if (!task->load()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: pre-link all DT_NEEDED libraries in breadth first order.
|
||||||
|
for (auto&& task : load_tasks) {
|
||||||
|
soinfo* si = task->get_soinfo();
|
||||||
|
if (!si->is_linked() && !si->prelink_image()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Add LD_PRELOADed libraries to the global group for
|
||||||
|
// future runs. There is no need to explicitly add them to
|
||||||
|
// the global group for this run because they are going to
|
||||||
|
// appear in the local group in the correct order.
|
||||||
|
if (ld_preloads != nullptr) {
|
||||||
|
for (auto&& si : *ld_preloads) {
|
||||||
|
si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Step 5: link libraries.
|
||||||
soinfo::soinfo_list_t local_group;
|
soinfo::soinfo_list_t local_group;
|
||||||
walk_dependencies_tree(
|
walk_dependencies_tree(
|
||||||
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
|
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
|
||||||
@ -2532,6 +2696,17 @@ const char* soinfo::get_realpath() const {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void soinfo::set_soname(const char* soname) {
|
||||||
|
#if defined(__work_around_b_24465209__)
|
||||||
|
if (has_min_version(2)) {
|
||||||
|
soname_ = soname;
|
||||||
|
}
|
||||||
|
strlcpy(old_name_, soname_, sizeof(old_name_));
|
||||||
|
#else
|
||||||
|
soname_ = soname;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
const char* soinfo::get_soname() const {
|
const char* soinfo::get_soname() const {
|
||||||
#if defined(__work_around_b_24465209__)
|
#if defined(__work_around_b_24465209__)
|
||||||
if (has_min_version(2)) {
|
if (has_min_version(2)) {
|
||||||
@ -3063,13 +3238,9 @@ bool soinfo::prelink_image() {
|
|||||||
for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
|
for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
|
||||||
switch (d->d_tag) {
|
switch (d->d_tag) {
|
||||||
case DT_SONAME:
|
case DT_SONAME:
|
||||||
soname_ = get_string(d->d_un.d_val);
|
set_soname(get_string(d->d_un.d_val));
|
||||||
#if defined(__work_around_b_24465209__)
|
|
||||||
strlcpy(old_name_, soname_, sizeof(old_name_));
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case DT_RUNPATH:
|
case DT_RUNPATH:
|
||||||
// FIXME: $LIB, $PLATFORM unsupported.
|
|
||||||
set_dt_runpath(get_string(d->d_un.d_val));
|
set_dt_runpath(get_string(d->d_un.d_val));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -317,6 +317,7 @@ struct soinfo {
|
|||||||
|
|
||||||
soinfo* get_local_group_root() const;
|
soinfo* get_local_group_root() const;
|
||||||
|
|
||||||
|
void set_soname(const char* soname);
|
||||||
const char* get_soname() const;
|
const char* get_soname() const;
|
||||||
const char* get_realpath() const;
|
const char* get_realpath() const;
|
||||||
const ElfW(Versym)* get_versym(size_t n) const;
|
const ElfW(Versym)* get_versym(size_t n) const;
|
||||||
@ -329,6 +330,7 @@ struct soinfo {
|
|||||||
|
|
||||||
uint32_t get_target_sdk_version() const;
|
uint32_t get_target_sdk_version() const;
|
||||||
|
|
||||||
|
void set_dt_runpath(const char *);
|
||||||
const std::vector<std::string>& get_dt_runpath() const;
|
const std::vector<std::string>& get_dt_runpath() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -392,7 +394,6 @@ struct soinfo {
|
|||||||
|
|
||||||
uint32_t target_sdk_version_;
|
uint32_t target_sdk_version_;
|
||||||
|
|
||||||
void set_dt_runpath(const char *);
|
|
||||||
std::vector<std::string> dt_runpath_;
|
std::vector<std::string> dt_runpath_;
|
||||||
|
|
||||||
friend soinfo* get_libdl_info();
|
friend soinfo* get_libdl_info();
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../libc/arch-common/bionic/__dso_handle.h"
|
#include "../libc/arch-common/bionic/__dso_handle.h"
|
||||||
|
#include "../libc/arch-common/bionic/pthread_atfork.h"
|
||||||
|
|
||||||
int atexit(void (*function)(void) __attribute__((__unused__))) {
|
int atexit(void (*function)(void) __attribute__((__unused__))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,30 +133,59 @@ static int GetTargetElfMachine() {
|
|||||||
MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
|
MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
|
||||||
MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
|
MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
|
||||||
|
|
||||||
ElfReader::ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size)
|
ElfReader::ElfReader()
|
||||||
: name_(name), fd_(fd), file_offset_(file_offset), file_size_(file_size), phdr_num_(0),
|
: did_read_(false), did_load_(false), fd_(-1), file_offset_(0), file_size_(0), phdr_num_(0),
|
||||||
phdr_table_(nullptr), load_start_(nullptr), load_size_(0), load_bias_(0),
|
phdr_table_(nullptr), shdr_table_(nullptr), shdr_num_(0), dynamic_(nullptr), strtab_(nullptr),
|
||||||
loaded_phdr_(nullptr) {
|
strtab_size_(0), load_start_(nullptr), load_size_(0), load_bias_(0), loaded_phdr_(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file_size) {
|
||||||
|
CHECK(!did_read_);
|
||||||
|
CHECK(!did_load_);
|
||||||
|
name_ = name;
|
||||||
|
fd_ = fd;
|
||||||
|
file_offset_ = file_offset;
|
||||||
|
file_size_ = file_size;
|
||||||
|
|
||||||
|
if (ReadElfHeader() &&
|
||||||
|
VerifyElfHeader() &&
|
||||||
|
ReadProgramHeaders() &&
|
||||||
|
ReadSectionHeaders() &&
|
||||||
|
ReadDynamicSection()) {
|
||||||
|
did_read_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return did_read_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElfReader::Load(const android_dlextinfo* extinfo) {
|
bool ElfReader::Load(const android_dlextinfo* extinfo) {
|
||||||
return ReadElfHeader() &&
|
CHECK(did_read_);
|
||||||
VerifyElfHeader() &&
|
CHECK(!did_load_);
|
||||||
ReadProgramHeader() &&
|
if (ReserveAddressSpace(extinfo) &&
|
||||||
ReserveAddressSpace(extinfo) &&
|
LoadSegments() &&
|
||||||
LoadSegments() &&
|
FindPhdr()) {
|
||||||
FindPhdr();
|
did_load_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return did_load_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ElfReader::get_string(ElfW(Word) index) const {
|
||||||
|
CHECK(strtab_ != nullptr);
|
||||||
|
CHECK(index < strtab_size_);
|
||||||
|
|
||||||
|
return strtab_ + index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElfReader::ReadElfHeader() {
|
bool ElfReader::ReadElfHeader() {
|
||||||
ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
|
ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
|
DL_ERR("can't read file \"%s\": %s", name_.c_str(), strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc != sizeof(header_)) {
|
if (rc != sizeof(header_)) {
|
||||||
DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_,
|
DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_.c_str(),
|
||||||
static_cast<size_t>(rc));
|
static_cast<size_t>(rc));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -165,7 +194,7 @@ bool ElfReader::ReadElfHeader() {
|
|||||||
|
|
||||||
bool ElfReader::VerifyElfHeader() {
|
bool ElfReader::VerifyElfHeader() {
|
||||||
if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
|
if (memcmp(header_.e_ident, ELFMAG, SELFMAG) != 0) {
|
||||||
DL_ERR("\"%s\" has bad ELF magic", name_);
|
DL_ERR("\"%s\" has bad ELF magic", name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,40 +204,40 @@ bool ElfReader::VerifyElfHeader() {
|
|||||||
#if defined(__LP64__)
|
#if defined(__LP64__)
|
||||||
if (elf_class != ELFCLASS64) {
|
if (elf_class != ELFCLASS64) {
|
||||||
if (elf_class == ELFCLASS32) {
|
if (elf_class == ELFCLASS32) {
|
||||||
DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_);
|
DL_ERR("\"%s\" is 32-bit instead of 64-bit", name_.c_str());
|
||||||
} else {
|
} else {
|
||||||
DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
|
DL_ERR("\"%s\" has unknown ELF class: %d", name_.c_str(), elf_class);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (elf_class != ELFCLASS32) {
|
if (elf_class != ELFCLASS32) {
|
||||||
if (elf_class == ELFCLASS64) {
|
if (elf_class == ELFCLASS64) {
|
||||||
DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_);
|
DL_ERR("\"%s\" is 64-bit instead of 32-bit", name_.c_str());
|
||||||
} else {
|
} else {
|
||||||
DL_ERR("\"%s\" has unknown ELF class: %d", name_, elf_class);
|
DL_ERR("\"%s\" has unknown ELF class: %d", name_.c_str(), elf_class);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
|
if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
|
||||||
DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
|
DL_ERR("\"%s\" not little-endian: %d", name_.c_str(), header_.e_ident[EI_DATA]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header_.e_type != ET_DYN) {
|
if (header_.e_type != ET_DYN) {
|
||||||
DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
|
DL_ERR("\"%s\" has unexpected e_type: %d", name_.c_str(), header_.e_type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header_.e_version != EV_CURRENT) {
|
if (header_.e_version != EV_CURRENT) {
|
||||||
DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
|
DL_ERR("\"%s\" has unexpected e_version: %d", name_.c_str(), header_.e_version);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header_.e_machine != GetTargetElfMachine()) {
|
if (header_.e_machine != GetTargetElfMachine()) {
|
||||||
DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
|
DL_ERR("\"%s\" has unexpected e_machine: %d", name_.c_str(), header_.e_machine);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,18 +246,18 @@ bool ElfReader::VerifyElfHeader() {
|
|||||||
|
|
||||||
// Loads the program header table from an ELF file into a read-only private
|
// Loads the program header table from an ELF file into a read-only private
|
||||||
// anonymous mmap-ed block.
|
// anonymous mmap-ed block.
|
||||||
bool ElfReader::ReadProgramHeader() {
|
bool ElfReader::ReadProgramHeaders() {
|
||||||
phdr_num_ = header_.e_phnum;
|
phdr_num_ = header_.e_phnum;
|
||||||
|
|
||||||
// Like the kernel, we only accept program header tables that
|
// Like the kernel, we only accept program header tables that
|
||||||
// are smaller than 64KiB.
|
// are smaller than 64KiB.
|
||||||
if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
|
if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(ElfW(Phdr))) {
|
||||||
DL_ERR("\"%s\" has invalid e_phnum: %zd", name_, phdr_num_);
|
DL_ERR("\"%s\" has invalid e_phnum: %zd", name_.c_str(), phdr_num_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, phdr_num_ * sizeof(ElfW(Phdr)))) {
|
if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, phdr_num_ * sizeof(ElfW(Phdr)))) {
|
||||||
DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
|
DL_ERR("\"%s\" phdr mmap failed: %s", name_.c_str(), strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +265,63 @@ bool ElfReader::ReadProgramHeader() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ElfReader::ReadSectionHeaders() {
|
||||||
|
shdr_num_ = header_.e_shnum;
|
||||||
|
|
||||||
|
if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, shdr_num_ * sizeof(ElfW(Shdr)))) {
|
||||||
|
DL_ERR("\"%s\" shdr mmap failed: %s", name_.c_str(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
shdr_table_ = static_cast<const ElfW(Shdr)*>(shdr_fragment_.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElfReader::ReadDynamicSection() {
|
||||||
|
// 1. Find .dynamic section (in section headers)
|
||||||
|
const ElfW(Shdr)* dynamic_shdr = nullptr;
|
||||||
|
for (size_t i = 0; i < shdr_num_; ++i) {
|
||||||
|
if (shdr_table_[i].sh_type == SHT_DYNAMIC) {
|
||||||
|
dynamic_shdr = &shdr_table_ [i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dynamic_shdr == nullptr) {
|
||||||
|
DL_ERR("\"%s\" .dynamic section was not found", name_.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dynamic_shdr->sh_link >= shdr_num_) {
|
||||||
|
DL_ERR("\"%s\" .dynamic section has invalid sh_link: %d", name_.c_str(), dynamic_shdr->sh_link);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElfW(Shdr)* strtab_shdr = &shdr_table_[dynamic_shdr->sh_link];
|
||||||
|
|
||||||
|
if (strtab_shdr->sh_type != SHT_STRTAB) {
|
||||||
|
DL_ERR("\"%s\" .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)",
|
||||||
|
name_.c_str(), dynamic_shdr->sh_link, strtab_shdr->sh_type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dynamic_fragment_.Map(fd_, file_offset_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
|
||||||
|
DL_ERR("\"%s\" dynamic section mmap failed: %s", name_.c_str(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
|
||||||
|
|
||||||
|
if (!strtab_fragment_.Map(fd_, file_offset_, strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
|
||||||
|
DL_ERR("\"%s\" strtab section mmap failed: %s", name_.c_str(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strtab_ = static_cast<const char*>(strtab_fragment_.data());
|
||||||
|
strtab_size_ = strtab_fragment_.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns the size of the extent of all the possibly non-contiguous
|
/* Returns the size of the extent of all the possibly non-contiguous
|
||||||
* loadable segments in an ELF program header table. This corresponds
|
* loadable segments in an ELF program header table. This corresponds
|
||||||
* to the page-aligned size in bytes that needs to be reserved in the
|
* to the page-aligned size in bytes that needs to be reserved in the
|
||||||
@ -292,7 +378,7 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
|
|||||||
ElfW(Addr) min_vaddr;
|
ElfW(Addr) min_vaddr;
|
||||||
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
|
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
|
||||||
if (load_size_ == 0) {
|
if (load_size_ == 0) {
|
||||||
DL_ERR("\"%s\" has no loadable segments", name_);
|
DL_ERR("\"%s\" has no loadable segments", name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,13 +405,13 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
|
|||||||
if (load_size_ > reserved_size) {
|
if (load_size_ > reserved_size) {
|
||||||
if (!reserved_hint) {
|
if (!reserved_hint) {
|
||||||
DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
|
DL_ERR("reserved address space %zd smaller than %zd bytes needed for \"%s\"",
|
||||||
reserved_size - load_size_, load_size_, name_);
|
reserved_size - load_size_, load_size_, name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||||
start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0);
|
start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0);
|
||||||
if (start == MAP_FAILED) {
|
if (start == MAP_FAILED) {
|
||||||
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
|
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -362,14 +448,14 @@ bool ElfReader::LoadSegments() {
|
|||||||
ElfW(Addr) file_length = file_end - file_page_start;
|
ElfW(Addr) file_length = file_end - file_page_start;
|
||||||
|
|
||||||
if (file_size_ <= 0) {
|
if (file_size_ <= 0) {
|
||||||
DL_ERR("\"%s\" invalid file size: %" PRId64, name_, file_size_);
|
DL_ERR("\"%s\" invalid file size: %" PRId64, name_.c_str(), file_size_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_end > static_cast<size_t>(file_size_)) {
|
if (file_end > static_cast<size_t>(file_size_)) {
|
||||||
DL_ERR("invalid ELF file \"%s\" load segment[%zd]:"
|
DL_ERR("invalid ELF file \"%s\" load segment[%zd]:"
|
||||||
" p_offset (%p) + p_filesz (%p) ( = %p) past end of file (0x%" PRIx64 ")",
|
" p_offset (%p) + p_filesz (%p) ( = %p) past end of file (0x%" PRIx64 ")",
|
||||||
name_, i, reinterpret_cast<void*>(phdr->p_offset),
|
name_.c_str(), i, reinterpret_cast<void*>(phdr->p_offset),
|
||||||
reinterpret_cast<void*>(phdr->p_filesz),
|
reinterpret_cast<void*>(phdr->p_filesz),
|
||||||
reinterpret_cast<void*>(file_end), file_size_);
|
reinterpret_cast<void*>(file_end), file_size_);
|
||||||
return false;
|
return false;
|
||||||
@ -383,7 +469,7 @@ bool ElfReader::LoadSegments() {
|
|||||||
fd_,
|
fd_,
|
||||||
file_offset_ + file_page_start);
|
file_offset_ + file_page_start);
|
||||||
if (seg_addr == MAP_FAILED) {
|
if (seg_addr == MAP_FAILED) {
|
||||||
DL_ERR("couldn't map \"%s\" segment %zd: %s", name_, i, strerror(errno));
|
DL_ERR("couldn't map \"%s\" segment %zd: %s", name_.c_str(), i, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -408,7 +494,7 @@ bool ElfReader::LoadSegments() {
|
|||||||
-1,
|
-1,
|
||||||
0);
|
0);
|
||||||
if (zeromap == MAP_FAILED) {
|
if (zeromap == MAP_FAILED) {
|
||||||
DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
|
DL_ERR("couldn't zero fill \"%s\" gap: %s", name_.c_str(), strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -803,7 +889,7 @@ bool ElfReader::FindPhdr() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DL_ERR("can't find loaded phdr for \"%s\"", name_);
|
DL_ERR("can't find loaded phdr for \"%s\"", name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -824,6 +910,7 @@ bool ElfReader::CheckPhdr(ElfW(Addr) loaded) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast<void*>(loaded));
|
DL_ERR("\"%s\" loaded phdr %p not in loadable segment",
|
||||||
|
name_.c_str(), reinterpret_cast<void*>(loaded));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -40,26 +40,34 @@
|
|||||||
|
|
||||||
class ElfReader {
|
class ElfReader {
|
||||||
public:
|
public:
|
||||||
ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size);
|
ElfReader();
|
||||||
|
|
||||||
|
bool Read(const char* name, int fd, off64_t file_offset, off64_t file_size);
|
||||||
bool Load(const android_dlextinfo* extinfo);
|
bool Load(const android_dlextinfo* extinfo);
|
||||||
|
|
||||||
size_t phdr_count() { return phdr_num_; }
|
const char* name() const { return name_.c_str(); }
|
||||||
ElfW(Addr) load_start() { return reinterpret_cast<ElfW(Addr)>(load_start_); }
|
size_t phdr_count() const { return phdr_num_; }
|
||||||
size_t load_size() { return load_size_; }
|
ElfW(Addr) load_start() const { return reinterpret_cast<ElfW(Addr)>(load_start_); }
|
||||||
ElfW(Addr) load_bias() { return load_bias_; }
|
size_t load_size() const { return load_size_; }
|
||||||
const ElfW(Phdr)* loaded_phdr() { return loaded_phdr_; }
|
ElfW(Addr) load_bias() const { return load_bias_; }
|
||||||
|
const ElfW(Phdr)* loaded_phdr() const { return loaded_phdr_; }
|
||||||
|
const ElfW(Dyn)* dynamic() const { return dynamic_; }
|
||||||
|
const char* get_string(ElfW(Word) index) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadElfHeader();
|
bool ReadElfHeader();
|
||||||
bool VerifyElfHeader();
|
bool VerifyElfHeader();
|
||||||
bool ReadProgramHeader();
|
bool ReadProgramHeaders();
|
||||||
|
bool ReadSectionHeaders();
|
||||||
|
bool ReadDynamicSection();
|
||||||
bool ReserveAddressSpace(const android_dlextinfo* extinfo);
|
bool ReserveAddressSpace(const android_dlextinfo* extinfo);
|
||||||
bool LoadSegments();
|
bool LoadSegments();
|
||||||
bool FindPhdr();
|
bool FindPhdr();
|
||||||
bool CheckPhdr(ElfW(Addr));
|
bool CheckPhdr(ElfW(Addr));
|
||||||
|
|
||||||
const char* name_;
|
bool did_read_;
|
||||||
|
bool did_load_;
|
||||||
|
std::string name_;
|
||||||
int fd_;
|
int fd_;
|
||||||
off64_t file_offset_;
|
off64_t file_offset_;
|
||||||
off64_t file_size_;
|
off64_t file_size_;
|
||||||
@ -70,6 +78,17 @@ class ElfReader {
|
|||||||
MappedFileFragment phdr_fragment_;
|
MappedFileFragment phdr_fragment_;
|
||||||
const ElfW(Phdr)* phdr_table_;
|
const ElfW(Phdr)* phdr_table_;
|
||||||
|
|
||||||
|
MappedFileFragment shdr_fragment_;
|
||||||
|
const ElfW(Shdr)* shdr_table_;
|
||||||
|
size_t shdr_num_;
|
||||||
|
|
||||||
|
MappedFileFragment dynamic_fragment_;
|
||||||
|
const ElfW(Dyn)* dynamic_;
|
||||||
|
|
||||||
|
MappedFileFragment strtab_fragment_;
|
||||||
|
const char* strtab_;
|
||||||
|
size_t strtab_size_;
|
||||||
|
|
||||||
// First page of reserved address space.
|
// First page of reserved address space.
|
||||||
void* load_start_;
|
void* load_start_;
|
||||||
// Size in bytes of reserved address space.
|
// Size in bytes of reserved address space.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user