summaryrefslogtreecommitdiff
path: root/linker/linker.cpp
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2014-02-27 13:18:00 +0000
committerTorne (Richard Coles) <torne@google.com>2014-04-17 14:30:46 +0100
commit183ad9df536ab04ef35a397a1f4724e4e401d11f (patch)
tree65c76a120390c1350ff1d38b725b54cabd91c06b /linker/linker.cpp
parent12bbb9164578b6512b8b07a3fb093858244b7c7b (diff)
Allow sharing the RELRO section via a file.
Add flags and a file descriptor to android_dlopen_ext() to allow writing the RELRO section of the loaded library to a file after relocation processing, and to allow mapping identical pages from the file over the top of relocated memory in another process. Explicitly comparing the pages is required in case a page contains a reference to a symbol defined in another library loaded at a random base address. Bug: 13005501 Change-Id: Ibb5b2d384edfaa5acf3e97a5f8b6115c10497a1e
Diffstat (limited to 'linker/linker.cpp')
-rwxr-xr-xlinker/linker.cpp27
1 files changed, 22 insertions, 5 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 85ef63b24..40237f3fb 100755
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -65,7 +65,7 @@
* and NOEXEC
*/
-static bool soinfo_link_image(soinfo* si);
+static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo);
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
// We can't use malloc(3) in the dynamic linker. We use a linked list of anonymous
@@ -760,7 +760,7 @@ static soinfo* find_library_internal(const char* name, const android_dlextinfo*
TRACE("[ find_library_internal base=%p size=%zu name='%s' ]",
reinterpret_cast<void*>(si->base), si->size, si->name);
- if (!soinfo_link_image(si)) {
+ if (!soinfo_link_image(si, extinfo)) {
munmap(reinterpret_cast<void*>(si->base), si->size);
soinfo_free(si);
return NULL;
@@ -1566,7 +1566,7 @@ static int nullify_closed_stdio() {
return return_value;
}
-static bool soinfo_link_image(soinfo* si) {
+static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
/* "base" might wrap around UINT32_MAX. */
ElfW(Addr) base = si->load_bias;
const ElfW(Phdr)* phdr = si->phdr;
@@ -1902,6 +1902,23 @@ static bool soinfo_link_image(soinfo* si) {
return false;
}
+ /* Handle serializing/sharing the RELRO segment */
+ if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
+ if (phdr_table_serialize_gnu_relro(si->phdr, si->phnum, si->load_bias,
+ extinfo->relro_fd) < 0) {
+ DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
+ si->name, strerror(errno));
+ return false;
+ }
+ } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
+ if (phdr_table_map_gnu_relro(si->phdr, si->phnum, si->load_bias,
+ extinfo->relro_fd) < 0) {
+ DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
+ si->name, strerror(errno));
+ return false;
+ }
+ }
+
notify_gdb_of_load(si);
return true;
}
@@ -2055,7 +2072,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
somain = si;
- if (!soinfo_link_image(si)) {
+ if (!soinfo_link_image(si, NULL)) {
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
exit(EXIT_FAILURE);
}
@@ -2172,7 +2189,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
linker_so.phnum = elf_hdr->e_phnum;
linker_so.flags |= FLAG_LINKER;
- if (!soinfo_link_image(&linker_so)) {
+ if (!soinfo_link_image(&linker_so, NULL)) {
// It would be nice to print an error message, but if the linker
// can't link itself, there's no guarantee that we'll be able to
// call write() (because it involves a GOT reference). We may as