diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c index d2059d98c..d02a4e39d 100644 --- a/src/elfs/elfloader.c +++ b/src/elfs/elfloader.c @@ -432,6 +432,8 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin) head->file = NULL; head->fileno = -1; + PatchLoadedDynamicSection(head); + return 0; } @@ -1474,6 +1476,141 @@ void* GetDynamicSection(elfheader_t* h) return box64_is32bits?((void*)h->Dynamic._32):((void*)h->Dynamic._64); } +typedef struct { + void* addr; + size_t size; +} dynamic_info_t; + +static int GetLoadedDynamicInfo(elfheader_t* h, dynamic_info_t* info) +{ + if(!h) return 0; + if(box64_is32bits) { + for(int i = 0; i < h->numPHEntries; i++) { + if(h->PHEntries._32[i].p_type == PT_DYNAMIC) { + info->addr = (void*)(h->delta + h->PHEntries._32[i].p_vaddr); + info->size = h->PHEntries._32[i].p_memsz; + return 1; + } + } + } else { + for(int i = 0; i < h->numPHEntries; i++) { + if(h->PHEntries._64[i].p_type == PT_DYNAMIC) { + info->addr = (void*)(h->delta + h->PHEntries._64[i].p_vaddr); + info->size = h->PHEntries._64[i].p_memsz; + return 1; + } + } + } + return 0; +} + +void* GetLoadedDynamicSection(elfheader_t* h) +{ + dynamic_info_t info; + if(GetLoadedDynamicInfo(h, &info)) + return info.addr; + return NULL; +} + +static int isDynamicTagPointer(int tag) +{ + switch(tag) { + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_REL: + case DT_RELR: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT: + case DT_FINI: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + case DT_VERNEED: + case DT_VERDEF: + case DT_VERSYM: +#ifdef DT_GNU_HASH + case DT_GNU_HASH: +#else + case 0x6ffffef5: +#endif +#ifdef DT_TLSDESC_PLT + case DT_TLSDESC_PLT: +#else + case 0x6ffffef6: +#endif +#ifdef DT_TLSDESC_GOT + case DT_TLSDESC_GOT: +#else + case 0x6ffffef7: +#endif + return 1; + default: + return 0; + } +} + +void PatchLoadedDynamicSection(elfheader_t* h) +{ + if(!h || !h->delta || h->dynamic_patched) + return; + + dynamic_info_t dyninfo; + if(!GetLoadedDynamicInfo(h, &dyninfo)) + return; + + uintptr_t dyn_addr = (uintptr_t)dyninfo.addr; + uintptr_t dyn_size = dyninfo.size; + + uintptr_t page_addr = dyn_addr & ~(box64_pagesize - 1); + uintptr_t page_end = (dyn_addr + dyn_size + box64_pagesize - 1) & ~(box64_pagesize - 1); + + int need_restore = 0; + for(uintptr_t page = page_addr; page < page_end; page += box64_pagesize) { + uint32_t old_prot = getProtection(page); + if(old_prot && !(old_prot & PROT_WRITE)) { + if(mprotect((void*)page, box64_pagesize, (old_prot | PROT_WRITE) & ~PROT_CUSTOM)) { + for(uintptr_t restore = page_addr; restore < page; restore += box64_pagesize) { + uint32_t restore_prot = getProtection(restore); + if(restore_prot && !(restore_prot & PROT_WRITE)) + mprotect((void*)restore, box64_pagesize, restore_prot & ~PROT_CUSTOM); + } + return; + } + need_restore = 1; + } + } + + if(box64_is32bits) { + Elf32_Dyn* dyn = (Elf32_Dyn*)dyn_addr; + for(int j = 0; dyn[j].d_tag != DT_NULL; j++) { + if(isDynamicTagPointer(dyn[j].d_tag) && dyn[j].d_un.d_ptr) { + dyn[j].d_un.d_ptr += h->delta; + } + } + } else { + Elf64_Dyn* dyn = (Elf64_Dyn*)dyn_addr; + for(int j = 0; dyn[j].d_tag != DT_NULL; j++) { + if(isDynamicTagPointer(dyn[j].d_tag) && dyn[j].d_un.d_ptr) { + dyn[j].d_un.d_ptr += h->delta; + } + } + } + + if(need_restore) { + for(uintptr_t page = page_addr; page < page_end; page += box64_pagesize) { + uint32_t old_prot = getProtection(page); + if(old_prot && !(old_prot & PROT_WRITE)) + mprotect((void*)page, box64_pagesize, old_prot & ~PROT_CUSTOM); + } + } + + h->dynamic_patched = 1; +} + typedef struct my_dl_phdr_info_s { void* dlpi_addr; const char* dlpi_name; @@ -1973,4 +2110,4 @@ const char* getAddrFunctionName(uintptr_t addr) } } return ret; -} \ No newline at end of file +} diff --git a/src/elfs/elfloader32.c b/src/elfs/elfloader32.c index 04cc486b8..657be5508 100644 --- a/src/elfs/elfloader32.c +++ b/src/elfs/elfloader32.c @@ -344,6 +344,8 @@ int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin head->file = NULL; head->fileno = -1; + PatchLoadedDynamicSection(head); + return 0; } diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h index f57d5fd83..62780f4a1 100644 --- a/src/elfs/elfloader_private.h +++ b/src/elfs/elfloader_private.h @@ -128,6 +128,7 @@ typedef struct elfheader_s { int refcnt; // ref count for the elf int malloc_hook_2; // this elf hook malloc, hacking it int gnuunique; // set if contains some STB_GNU_UNIQUE binding, preventing dlclose to unload the lib + int dynamic_patched; char* memory; // char* and not void* to allow math on memory pointer multiblock_t* multiblocks; diff --git a/src/include/elfloader.h b/src/include/elfloader.h index 39ffe466a..d5071d549 100644 --- a/src/include/elfloader.h +++ b/src/include/elfloader.h @@ -74,6 +74,8 @@ void* GetDTatOffset(x64emu_t* emu, unsigned long int index, unsigned long int of void ResetSpecialCaseMainElf(elfheader_t* h); void CreateMemorymapFile(box64context_t* context, int fd); void* GetDynamicSection(elfheader_t* h); +void* GetLoadedDynamicSection(elfheader_t* h); +void PatchLoadedDynamicSection(elfheader_t* h); int ElfCheckIfUseTCMallocMinimal(elfheader_t* h); // return 1 if tcmalloc is used diff --git a/src/librarian/librarian.c b/src/librarian/librarian.c index 28a0fa47e..6a62e0f7b 100644 --- a/src/librarian/librarian.c +++ b/src/librarian/librarian.c @@ -267,7 +267,7 @@ static int AddNeededLib_add(lib_t** maplib, int local, needed_libs_t* needed, in } lm->l_addr = (Elf32_Addr)to_ptrv(GetElfDelta(lib->e.elf)); lm->l_name = to_cstring(lib->name); - lm->l_ld = to_ptrv(GetDynamicSection(lib->e.elf)); + lm->l_ld = to_ptrv(GetLoadedDynamicSection(lib->e.elf)); } else #endif { @@ -279,7 +279,7 @@ static int AddNeededLib_add(lib_t** maplib, int local, needed_libs_t* needed, in } lm->l_addr = (Elf64_Addr)GetElfDelta(lib->e.elf); lm->l_name = lib->name; - lm->l_ld = GetDynamicSection(lib->e.elf); + lm->l_ld = GetLoadedDynamicSection(lib->e.elf); } //TODO: it seems to never be removed! } diff --git a/src/librarian/library.c b/src/librarian/library.c index e6cf8c056..ec71ba06e 100644 --- a/src/librarian/library.c +++ b/src/librarian/library.c @@ -1180,7 +1180,7 @@ void AddMainElfToLinkmap32(elfheader_t* elf) lm->l_addr = (Elf32_Addr)to_ptrv(GetElfDelta(elf)); lm->l_name = to_cstring(my_context->fullpath); - lm->l_ld = to_ptrv(GetDynamicSection(elf)); + lm->l_ld = to_ptrv(GetLoadedDynamicSection(elf)); } #endif @@ -1236,7 +1236,7 @@ void AddMainElfToLinkmap(elfheader_t* elf) lm->l_addr = (Elf64_Addr)GetElfDelta(elf); lm->l_name = my_context->fullpath; - lm->l_ld = GetDynamicSection(elf); + lm->l_ld = GetLoadedDynamicSection(elf); } needed_libs_t* new_neededlib(int n)