aboutsummaryrefslogtreecommitdiffstats
path: root/linker
diff options
context:
space:
mode:
authorRyan Prichard <rprichard@google.com>2019-02-08 22:33:11 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-02-08 22:33:11 +0000
commit808d176e7e0dd727c7f929622ec017f6e065c582 (patch)
tree2f34e0a7bd1822e8235e0d0f51b941beadc47927 /linker
parent2eb1fc9df0e8e90caed5145ab2f627b8d8961b97 (diff)
parent1990ba5601f5230851d1e2112c28bebbf78c3f40 (diff)
downloadandroid_bionic-808d176e7e0dd727c7f929622ec017f6e065c582.tar.gz
android_bionic-808d176e7e0dd727c7f929622ec017f6e065c582.tar.bz2
android_bionic-808d176e7e0dd727c7f929622ec017f6e065c582.zip
Merge "Fix linker self-exec detection"
Diffstat (limited to 'linker')
-rw-r--r--linker/linker_main.cpp32
1 files changed, 20 insertions, 12 deletions
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 7486cd79b..9129a529f 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -553,6 +553,24 @@ static void get_elf_base_from_phdr(const ElfW(Phdr)* phdr_table, size_t phdr_cou
async_safe_fatal("Could not find a PHDR: broken executable?");
}
+// Detect an attempt to run the linker on itself. e.g.:
+// /system/bin/linker64 /system/bin/linker64
+// Use priority-1 to run this constructor before other constructors.
+__attribute__((constructor(1))) static void detect_self_exec() {
+ // Normally, the linker initializes the auxv global before calling its
+ // constructors. If the linker loads itself, though, the first loader calls
+ // the second loader's constructors before calling __linker_init.
+ if (__libc_shared_globals()->auxv != nullptr) {
+ return;
+ }
+#if defined(__i386__)
+ // We don't have access to the auxv struct from here, so use the int 0x80
+ // fallback.
+ __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
+#endif
+ __linker_error("error: linker cannot load itself\n");
+}
+
static ElfW(Addr) __attribute__((noinline))
__linker_init_post_relocation(KernelArgumentBlock& args, soinfo& linker_so);
@@ -575,18 +593,8 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
// another program), AT_BASE is 0.
ElfW(Addr) linker_addr = getauxval(AT_BASE);
if (linker_addr == 0) {
- // Detect an attempt to run the linker on itself (e.g.
- // `linker64 /system/bin/linker64`). If the kernel loaded this instance of
- // the linker, then AT_ENTRY will refer to &_start. If it doesn't, then
- // something else must have loaded this instance of the linker. It's
- // simpler if we only allow one copy of the linker to be loaded at a time.
- if (getauxval(AT_ENTRY) != reinterpret_cast<uintptr_t>(&_start)) {
- // The first linker already relocated this one and set up TLS, so we don't
- // need further libc initialization.
- __linker_error("error: linker cannot load itself\n");
- }
- // Otherwise, the AT_PHDR and AT_PHNUM aux values describe this linker
- // instance, so use the phdr to find the linker's base address.
+ // The AT_PHDR and AT_PHNUM aux values describe this linker instance, so use
+ // the phdr to find the linker's base address.
ElfW(Addr) load_bias;
get_elf_base_from_phdr(
reinterpret_cast<ElfW(Phdr)*>(getauxval(AT_PHDR)), getauxval(AT_PHNUM),