mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-10 17:24:29 +00:00
Backed out 2 changesets (bug 635961) at developer's request a=backout
Backed out changeset c56fa9c1eda0 (bug 635961) Backed out changeset ddda63d5366e (bug 635961) MozReview-Commit-ID: I6NxBctFn8e
This commit is contained in:
parent
cd3f69980b
commit
5dbd554bdd
@ -89,8 +89,8 @@ private:
|
||||
|
||||
class ElfRelHackCode_Section: public ElfSection {
|
||||
public:
|
||||
ElfRelHackCode_Section(Elf_Shdr &s, Elf &e, unsigned int init, unsigned int mprotect_cb)
|
||||
: ElfSection(s, nullptr, nullptr), parent(e), init(init), mprotect_cb(mprotect_cb) {
|
||||
ElfRelHackCode_Section(Elf_Shdr &s, Elf &e, unsigned int init)
|
||||
: ElfSection(s, nullptr, nullptr), parent(e), init(init) {
|
||||
std::string file(rundir);
|
||||
file += "/inject/";
|
||||
switch (parent.getMachine()) {
|
||||
@ -125,17 +125,9 @@ public:
|
||||
if (symtab == nullptr)
|
||||
throw std::runtime_error("Couldn't find a symbol table for the injected code");
|
||||
|
||||
relro = parent.getSegmentByType(PT_GNU_RELRO);
|
||||
align = parent.getSegmentByType(PT_LOAD)->getAlign();
|
||||
|
||||
// Find the init symbol
|
||||
entry_point = -1;
|
||||
std::string symbol = "init";
|
||||
if (!init)
|
||||
symbol += "_noinit";
|
||||
if (relro)
|
||||
symbol += "_relro";
|
||||
Elf_SymValue *sym = symtab->lookup(symbol.c_str());
|
||||
Elf_SymValue *sym = symtab->lookup(init ? "init" : "init_noinit");
|
||||
if (!sym)
|
||||
throw std::runtime_error("Couldn't find an 'init' symbol in the injected code");
|
||||
|
||||
@ -361,14 +353,6 @@ private:
|
||||
addr = ehdr->getAddr();
|
||||
} else if (strcmp(name, "original_init") == 0) {
|
||||
addr = init;
|
||||
} else if (relro && strcmp(name, "mprotect_cb") == 0) {
|
||||
addr = mprotect_cb;
|
||||
} else if (relro && strcmp(name, "relro_start") == 0) {
|
||||
// Align relro segment start to the start of the page it starts in.
|
||||
addr = relro->getAddr() & ~(align - 1);
|
||||
// Align relro segment end to the start of the page it ends into.
|
||||
} else if (relro && strcmp(name, "relro_end") == 0) {
|
||||
addr = (relro->getAddr() + relro->getMemSize()) & ~(align - 1);
|
||||
} else if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0) {
|
||||
// We actually don't need a GOT, but need it as a reference for
|
||||
// GOTOFF relocations. We'll just use the start of the ELF file
|
||||
@ -419,10 +403,7 @@ private:
|
||||
Elf *elf, &parent;
|
||||
std::vector<ElfSection *> code;
|
||||
unsigned int init;
|
||||
unsigned int mprotect_cb;
|
||||
int entry_point;
|
||||
ElfSegment *relro;
|
||||
unsigned int align;
|
||||
};
|
||||
|
||||
unsigned int get_addend(Elf_Rel *rel, Elf *elf) {
|
||||
@ -522,6 +503,8 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
|
||||
return -1;
|
||||
}
|
||||
|
||||
ElfSegment *relro = elf->getSegmentByType(PT_GNU_RELRO);
|
||||
|
||||
ElfRel_Section<Rel_Type> *section = (ElfRel_Section<Rel_Type> *)dyn->getSectionForType(Rel_Type::d_tag);
|
||||
if (section == nullptr) {
|
||||
fprintf(stderr, "No relocations\n");
|
||||
@ -616,7 +599,9 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
|
||||
}
|
||||
new_rels.push_back(*i);
|
||||
init_array_reloc = new_rels.size();
|
||||
} else if (!(loc.getSection()->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type)) {
|
||||
} else if (!(loc.getSection()->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type) ||
|
||||
(relro && (i->r_offset >= relro->getAddr()) &&
|
||||
(i->r_offset < relro->getAddr() + relro->getMemSize()))) {
|
||||
// Don't pack relocations happening in non writable sections.
|
||||
// Our injected code is likely not to be allowed to write there.
|
||||
new_rels.push_back(*i);
|
||||
@ -685,72 +670,10 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int mprotect_cb = 0;
|
||||
// If there is a relro segment, our injected code will run after the linker sets the
|
||||
// corresponding pages read-only. We need to make our code change that to read-write
|
||||
// before applying relocations, which means it needs to call mprotect.
|
||||
// To do that, we need to find a reference to the mprotect symbol. In case the library
|
||||
// already has one, we use that, but otherwise, we add the symbol.
|
||||
// Then the injected code needs to be able to call the corresponding function, which
|
||||
// means it needs access to a pointer to it. We get such a pointer by making the linker
|
||||
// apply a relocation for the symbol at an address our code can read.
|
||||
// The problem here is that there is not much relocated space where we can put such a
|
||||
// pointer, so we abuse the bss section temporarily (it will be restored to a null
|
||||
// value before any code can actually use it)
|
||||
if (elf->getSegmentByType(PT_GNU_RELRO)) {
|
||||
Elf_SymValue *mprotect = symtab->lookup("mprotect", STT(FUNC));
|
||||
if (!mprotect) {
|
||||
symtab->syms.emplace_back();
|
||||
mprotect = &symtab->syms.back();
|
||||
symtab->grow(symtab->syms.size() * symtab->getEntSize());
|
||||
mprotect->name = ((ElfStrtab_Section *)symtab->getLink())->getStr("mprotect");
|
||||
mprotect->info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC);
|
||||
mprotect->other = STV_DEFAULT;
|
||||
new (&mprotect->value) ElfLocation(nullptr, 0, ElfLocation::ABSOLUTE);
|
||||
mprotect->size = 0;
|
||||
mprotect->defined = false;
|
||||
|
||||
// The DT_VERSYM data (in the .gnu.version section) has the same number of
|
||||
// entries as the symbols table. Since we added one entry there, we need to
|
||||
// add one entry here. Zeroes in the extra data means no version for that
|
||||
// symbol, which is the simplest thing to do.
|
||||
ElfSection *gnu_versym = dyn->getSectionForType(DT_VERSYM);
|
||||
if (gnu_versym) {
|
||||
gnu_versym->grow(gnu_versym->getSize() + gnu_versym->getEntSize());
|
||||
}
|
||||
}
|
||||
|
||||
// Add a relocation for the mprotect symbol.
|
||||
new_rels.emplace_back();
|
||||
Rel_Type &rel = new_rels.back();
|
||||
memset(&rel, 0, sizeof(rel));
|
||||
rel.r_info = ELF32_R_INFO(std::distance(symtab->syms.begin(), std::vector<Elf_SymValue>::iterator(mprotect)), rel_type2);
|
||||
|
||||
// Find the beginning of the bss section, and use an aligned location in there
|
||||
// for the relocation.
|
||||
for (ElfSegment *segment = elf->getSegmentByType(PT_LOAD); segment;
|
||||
segment = elf->getSegmentByType(PT_LOAD, segment)) {
|
||||
if (segment->getFlags() & PF_W == 0)
|
||||
continue;
|
||||
size_t ptr_size = Elf_Addr::size(elf->getClass());
|
||||
size_t aligned_mem_end = (segment->getAddr() + segment->getFileSize() + ptr_size - 1) & ~(ptr_size - 1);
|
||||
size_t aligned_file_end = (segment->getAddr() + segment->getMemSize() + ptr_size - 1) & ~(ptr_size - 1);
|
||||
if (aligned_mem_end - aligned_file_end >= Elf_Addr::size(elf->getClass())) {
|
||||
mprotect_cb = rel.r_offset = aligned_file_end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mprotect_cb == 0) {
|
||||
fprintf(stderr, "Couldn't find .bss. Skipping\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
section->rels.assign(new_rels.begin(), new_rels.end());
|
||||
section->shrink(new_rels.size() * section->getEntSize());
|
||||
|
||||
ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf, original_init, mprotect_cb);
|
||||
ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf, original_init);
|
||||
relhackcode->insertBefore(section);
|
||||
relhack->insertAfter(relhackcode);
|
||||
if (section->getOffset() + section->getSize() >= old_end) {
|
||||
|
@ -327,17 +327,8 @@ public:
|
||||
SectionInfo getInfo() { return info; }
|
||||
|
||||
void shrink(unsigned int newsize) {
|
||||
if (newsize < shdr.sh_size) {
|
||||
if (newsize < shdr.sh_size)
|
||||
shdr.sh_size = newsize;
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void grow(unsigned int newsize) {
|
||||
if (newsize > shdr.sh_size) {
|
||||
shdr.sh_size = newsize;
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getOffset();
|
||||
|
@ -3,8 +3,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <elf.h>
|
||||
|
||||
/* The Android NDK headers define those */
|
||||
@ -24,10 +22,6 @@ extern __attribute__((visibility("hidden"))) void original_init(int argc, char *
|
||||
extern __attribute__((visibility("hidden"))) Elf32_Rel relhack[];
|
||||
extern __attribute__((visibility("hidden"))) Elf_Ehdr elf_header;
|
||||
|
||||
extern __attribute__((visibility("hidden"))) int (*mprotect_cb)(void *addr, size_t len, int prot);
|
||||
extern __attribute__((visibility("hidden"))) char relro_start[];
|
||||
extern __attribute__((visibility("hidden"))) char relro_end[];
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void do_relocations(void)
|
||||
{
|
||||
@ -56,40 +50,3 @@ int init(int argc, char **argv, char **env)
|
||||
// B.W instruction in Thumb for the call above.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void relro_pre()
|
||||
{
|
||||
// By the time the injected code runs, the relro segment is read-only. But
|
||||
// we want to apply relocations in it, so we set it r/w first. We'll restore
|
||||
// it to read-only in relro_post.
|
||||
mprotect_cb(relro_start, relro_end - relro_start, PROT_READ | PROT_WRITE);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void relro_post()
|
||||
{
|
||||
mprotect_cb(relro_start, relro_end - relro_start, PROT_READ);
|
||||
// mprotect_cb is a pointer allocated in .bss, so we need to restore it to
|
||||
// a NULL value.
|
||||
mprotect_cb = NULL;
|
||||
}
|
||||
|
||||
__attribute__((section(".text._init_noinit_relro")))
|
||||
int init_noinit_relro(int argc, char **argv, char **env)
|
||||
{
|
||||
relro_pre();
|
||||
do_relocations();
|
||||
relro_post();
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((section(".text._init_relro")))
|
||||
int init_relro(int argc, char **argv, char **env)
|
||||
{
|
||||
relro_pre();
|
||||
do_relocations();
|
||||
original_init(argc, argv, env);
|
||||
relro_post();
|
||||
return 0;
|
||||
}
|
||||
|
@ -3981,6 +3981,47 @@ if test "$USE_ELF_HACK" = 1; then
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -n "$COMPILE_ENVIRONMENT" -a -n "$USE_ELF_HACK"; then
|
||||
dnl PT_GNU_RELRO segment makes the dynamic linker set a read-only flag on
|
||||
dnl memory addresses it maps to. The result is that by the time elfhack
|
||||
dnl kicks in, it is not possible to apply relocations because of that,
|
||||
dnl thus elfhack effectively skips relocations inside the PT_GNU_RELRO
|
||||
dnl segment. It makes elfhack mostly useless, so considering the problems
|
||||
dnl we have we PT_GNU_RELRO (e.g. bug 664366), and until elfhack can deal
|
||||
dnl with PT_GNU_RELRO segments, it's just simpler to disable elfhack when
|
||||
dnl the linker creates PT_GNU_RELRO segments. However, when we do want
|
||||
dnl elfhack enabled, disable PT_GNU_RELRO instead.
|
||||
AC_CACHE_CHECK([whether linker creates PT_GNU_RELRO segments],
|
||||
LINK_WITH_PT_GNU_RELRO,
|
||||
[echo "int main() {return 0;}" > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.${ac_ext} $LIBS 1>&2) &&
|
||||
test -s conftest${ac_exeext}; then
|
||||
if ${TOOLCHAIN_PREFIX}readelf -l conftest${ac_exeext} | grep GNU_RELRO > /dev/null; then
|
||||
LINK_WITH_PT_GNU_RELRO=yes
|
||||
else
|
||||
LINK_WITH_PT_GNU_RELRO=no
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
AC_ERROR([couldn't compile a simple C file])
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
if test "$LINK_WITH_PT_GNU_RELRO" = yes; then
|
||||
if test "$USE_ELF_HACK" = F; then
|
||||
AC_MSG_CHECKING([for -z norelro option to ld])
|
||||
_SAVE_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -Wl,-z,norelro"
|
||||
AC_TRY_LINK(,,AC_MSG_RESULT([yes])
|
||||
[NSPR_LDFLAGS="$NSPR_LDFLAGS -Wl,-z,norelro"],
|
||||
AC_ERROR([--enable-elf-hack is not compatible with a linker creating a PT_GNU_RELRO segment and that doesn't support the "-z norelro" option.]))
|
||||
USE_ELF_HACK=1
|
||||
else
|
||||
AC_MSG_WARN([Disabling elfhack])
|
||||
USE_ELF_HACK=
|
||||
fi
|
||||
fi
|
||||
fi # COMPILE_ENVIRONMENT and others.
|
||||
|
||||
dnl ========================================================
|
||||
dnl = libstdc++ compatibility hacks
|
||||
dnl ========================================================
|
||||
|
Loading…
x
Reference in New Issue
Block a user