Restore protection flags for ifunc during relocs.
IFUNC relocations require executable flag for the load segment containing .text. When dso has text relocs linker removes exec which causes crash during ifunc relocations. This patch fixes this problem by restoring segments protection for ifunc relocs. Bug: http://b/22611399 Change-Id: Icbf3be0fec0e42bf805bcad7533e2032a2e11b9c
This commit is contained in:
@@ -1921,9 +1921,32 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
|
|||||||
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
|
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else { // We got a definition.
|
||||||
// We got a definition.
|
#if !defined(__LP64__)
|
||||||
|
// When relocating dso with text_relocation .text segment is
|
||||||
|
// not executable. We need to restore elf flags before resolving
|
||||||
|
// STT_GNU_IFUNC symbol.
|
||||||
|
bool protect_segments = has_text_relocations &&
|
||||||
|
lsi == this &&
|
||||||
|
ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
|
||||||
|
if (protect_segments) {
|
||||||
|
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't protect segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
sym_addr = lsi->resolve_symbol_address(s);
|
sym_addr = lsi->resolve_symbol_address(s);
|
||||||
|
#if !defined(__LP64__)
|
||||||
|
if (protect_segments) {
|
||||||
|
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
count_relocation(kRelocSymbol);
|
count_relocation(kRelocSymbol);
|
||||||
}
|
}
|
||||||
@@ -1960,7 +1983,32 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
|
|||||||
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
|
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
|
||||||
reinterpret_cast<void*>(reloc),
|
reinterpret_cast<void*>(reloc),
|
||||||
reinterpret_cast<void*>(load_bias + addend));
|
reinterpret_cast<void*>(load_bias + addend));
|
||||||
*reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend);
|
{
|
||||||
|
#if !defined(__LP64__)
|
||||||
|
// When relocating dso with text_relocation .text segment is
|
||||||
|
// not executable. We need to restore elf flags for this
|
||||||
|
// particular call.
|
||||||
|
if (has_text_relocations) {
|
||||||
|
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't protect segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
|
||||||
|
#if !defined(__LP64__)
|
||||||
|
// Unprotect it afterwards...
|
||||||
|
if (has_text_relocations) {
|
||||||
|
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
|
||||||
|
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
|
||||||
|
get_realpath(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
|
Reference in New Issue
Block a user