Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 138 additions & 1 deletion src/elfs/elfloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
head->file = NULL;
head->fileno = -1;

PatchLoadedDynamicSection(head);

return 0;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1973,4 +2110,4 @@ const char* getAddrFunctionName(uintptr_t addr)
}
}
return ret;
}
}
2 changes: 2 additions & 0 deletions src/elfs/elfloader32.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin
head->file = NULL;
head->fileno = -1;

PatchLoadedDynamicSection(head);

return 0;
}

Expand Down
1 change: 1 addition & 0 deletions src/elfs/elfloader_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/include/elfloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions src/librarian/librarian.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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!
}
Expand Down
4 changes: 2 additions & 2 deletions src/librarian/library.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
Loading