Skip to content

Commit 9d0f8d1

Browse files
[ELF] Fix SIGSEGV when calling dlinfo RTLD_DI_LINKMAP for emulated code (#3331)
* [ELF] Fix dlinfo RTLD_DI_LINKMAP for emulated code * [ELF] Tidy dynamic section patching * [ELF] Fix dynamic section patch protections
1 parent 24076b6 commit 9d0f8d1

File tree

6 files changed

+147
-5
lines changed

6 files changed

+147
-5
lines changed

src/elfs/elfloader.c

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,8 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
432432
head->file = NULL;
433433
head->fileno = -1;
434434

435+
PatchLoadedDynamicSection(head);
436+
435437
return 0;
436438
}
437439

@@ -1474,6 +1476,141 @@ void* GetDynamicSection(elfheader_t* h)
14741476
return box64_is32bits?((void*)h->Dynamic._32):((void*)h->Dynamic._64);
14751477
}
14761478

1479+
typedef struct {
1480+
void* addr;
1481+
size_t size;
1482+
} dynamic_info_t;
1483+
1484+
static int GetLoadedDynamicInfo(elfheader_t* h, dynamic_info_t* info)
1485+
{
1486+
if(!h) return 0;
1487+
if(box64_is32bits) {
1488+
for(int i = 0; i < h->numPHEntries; i++) {
1489+
if(h->PHEntries._32[i].p_type == PT_DYNAMIC) {
1490+
info->addr = (void*)(h->delta + h->PHEntries._32[i].p_vaddr);
1491+
info->size = h->PHEntries._32[i].p_memsz;
1492+
return 1;
1493+
}
1494+
}
1495+
} else {
1496+
for(int i = 0; i < h->numPHEntries; i++) {
1497+
if(h->PHEntries._64[i].p_type == PT_DYNAMIC) {
1498+
info->addr = (void*)(h->delta + h->PHEntries._64[i].p_vaddr);
1499+
info->size = h->PHEntries._64[i].p_memsz;
1500+
return 1;
1501+
}
1502+
}
1503+
}
1504+
return 0;
1505+
}
1506+
1507+
void* GetLoadedDynamicSection(elfheader_t* h)
1508+
{
1509+
dynamic_info_t info;
1510+
if(GetLoadedDynamicInfo(h, &info))
1511+
return info.addr;
1512+
return NULL;
1513+
}
1514+
1515+
static int isDynamicTagPointer(int tag)
1516+
{
1517+
switch(tag) {
1518+
case DT_PLTGOT:
1519+
case DT_HASH:
1520+
case DT_STRTAB:
1521+
case DT_SYMTAB:
1522+
case DT_RELA:
1523+
case DT_REL:
1524+
case DT_RELR:
1525+
case DT_DEBUG:
1526+
case DT_JMPREL:
1527+
case DT_INIT:
1528+
case DT_FINI:
1529+
case DT_INIT_ARRAY:
1530+
case DT_FINI_ARRAY:
1531+
case DT_PREINIT_ARRAY:
1532+
case DT_VERNEED:
1533+
case DT_VERDEF:
1534+
case DT_VERSYM:
1535+
#ifdef DT_GNU_HASH
1536+
case DT_GNU_HASH:
1537+
#else
1538+
case 0x6ffffef5:
1539+
#endif
1540+
#ifdef DT_TLSDESC_PLT
1541+
case DT_TLSDESC_PLT:
1542+
#else
1543+
case 0x6ffffef6:
1544+
#endif
1545+
#ifdef DT_TLSDESC_GOT
1546+
case DT_TLSDESC_GOT:
1547+
#else
1548+
case 0x6ffffef7:
1549+
#endif
1550+
return 1;
1551+
default:
1552+
return 0;
1553+
}
1554+
}
1555+
1556+
void PatchLoadedDynamicSection(elfheader_t* h)
1557+
{
1558+
if(!h || !h->delta || h->dynamic_patched)
1559+
return;
1560+
1561+
dynamic_info_t dyninfo;
1562+
if(!GetLoadedDynamicInfo(h, &dyninfo))
1563+
return;
1564+
1565+
uintptr_t dyn_addr = (uintptr_t)dyninfo.addr;
1566+
uintptr_t dyn_size = dyninfo.size;
1567+
1568+
uintptr_t page_addr = dyn_addr & ~(box64_pagesize - 1);
1569+
uintptr_t page_end = (dyn_addr + dyn_size + box64_pagesize - 1) & ~(box64_pagesize - 1);
1570+
1571+
int need_restore = 0;
1572+
for(uintptr_t page = page_addr; page < page_end; page += box64_pagesize) {
1573+
uint32_t old_prot = getProtection(page);
1574+
if(old_prot && !(old_prot & PROT_WRITE)) {
1575+
if(mprotect((void*)page, box64_pagesize, (old_prot | PROT_WRITE) & ~PROT_CUSTOM)) {
1576+
for(uintptr_t restore = page_addr; restore < page; restore += box64_pagesize) {
1577+
uint32_t restore_prot = getProtection(restore);
1578+
if(restore_prot && !(restore_prot & PROT_WRITE))
1579+
mprotect((void*)restore, box64_pagesize, restore_prot & ~PROT_CUSTOM);
1580+
}
1581+
return;
1582+
}
1583+
need_restore = 1;
1584+
}
1585+
}
1586+
1587+
if(box64_is32bits) {
1588+
Elf32_Dyn* dyn = (Elf32_Dyn*)dyn_addr;
1589+
for(int j = 0; dyn[j].d_tag != DT_NULL; j++) {
1590+
if(isDynamicTagPointer(dyn[j].d_tag) && dyn[j].d_un.d_ptr) {
1591+
dyn[j].d_un.d_ptr += h->delta;
1592+
}
1593+
}
1594+
} else {
1595+
Elf64_Dyn* dyn = (Elf64_Dyn*)dyn_addr;
1596+
for(int j = 0; dyn[j].d_tag != DT_NULL; j++) {
1597+
if(isDynamicTagPointer(dyn[j].d_tag) && dyn[j].d_un.d_ptr) {
1598+
dyn[j].d_un.d_ptr += h->delta;
1599+
}
1600+
}
1601+
}
1602+
1603+
if(need_restore) {
1604+
for(uintptr_t page = page_addr; page < page_end; page += box64_pagesize) {
1605+
uint32_t old_prot = getProtection(page);
1606+
if(old_prot && !(old_prot & PROT_WRITE))
1607+
mprotect((void*)page, box64_pagesize, old_prot & ~PROT_CUSTOM);
1608+
}
1609+
}
1610+
1611+
h->dynamic_patched = 1;
1612+
}
1613+
14771614
typedef struct my_dl_phdr_info_s {
14781615
void* dlpi_addr;
14791616
const char* dlpi_name;
@@ -1973,4 +2110,4 @@ const char* getAddrFunctionName(uintptr_t addr)
19732110
}
19742111
}
19752112
return ret;
1976-
}
2113+
}

src/elfs/elfloader32.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin
344344
head->file = NULL;
345345
head->fileno = -1;
346346

347+
PatchLoadedDynamicSection(head);
348+
347349
return 0;
348350
}
349351

src/elfs/elfloader_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ typedef struct elfheader_s {
128128
int refcnt; // ref count for the elf
129129
int malloc_hook_2; // this elf hook malloc, hacking it
130130
int gnuunique; // set if contains some STB_GNU_UNIQUE binding, preventing dlclose to unload the lib
131+
int dynamic_patched;
131132

132133
char* memory; // char* and not void* to allow math on memory pointer
133134
multiblock_t* multiblocks;

src/include/elfloader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ void* GetDTatOffset(x64emu_t* emu, unsigned long int index, unsigned long int of
7474
void ResetSpecialCaseMainElf(elfheader_t* h);
7575
void CreateMemorymapFile(box64context_t* context, int fd);
7676
void* GetDynamicSection(elfheader_t* h);
77+
void* GetLoadedDynamicSection(elfheader_t* h);
78+
void PatchLoadedDynamicSection(elfheader_t* h);
7779

7880
int ElfCheckIfUseTCMallocMinimal(elfheader_t* h); // return 1 if tcmalloc is used
7981

src/librarian/librarian.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ static int AddNeededLib_add(lib_t** maplib, int local, needed_libs_t* needed, in
267267
}
268268
lm->l_addr = (Elf32_Addr)to_ptrv(GetElfDelta(lib->e.elf));
269269
lm->l_name = to_cstring(lib->name);
270-
lm->l_ld = to_ptrv(GetDynamicSection(lib->e.elf));
270+
lm->l_ld = to_ptrv(GetLoadedDynamicSection(lib->e.elf));
271271
} else
272272
#endif
273273
{
@@ -279,7 +279,7 @@ static int AddNeededLib_add(lib_t** maplib, int local, needed_libs_t* needed, in
279279
}
280280
lm->l_addr = (Elf64_Addr)GetElfDelta(lib->e.elf);
281281
lm->l_name = lib->name;
282-
lm->l_ld = GetDynamicSection(lib->e.elf);
282+
lm->l_ld = GetLoadedDynamicSection(lib->e.elf);
283283
}
284284
//TODO: it seems to never be removed!
285285
}

src/librarian/library.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,7 @@ void AddMainElfToLinkmap32(elfheader_t* elf)
11801180

11811181
lm->l_addr = (Elf32_Addr)to_ptrv(GetElfDelta(elf));
11821182
lm->l_name = to_cstring(my_context->fullpath);
1183-
lm->l_ld = to_ptrv(GetDynamicSection(elf));
1183+
lm->l_ld = to_ptrv(GetLoadedDynamicSection(elf));
11841184
}
11851185
#endif
11861186

@@ -1236,7 +1236,7 @@ void AddMainElfToLinkmap(elfheader_t* elf)
12361236

12371237
lm->l_addr = (Elf64_Addr)GetElfDelta(elf);
12381238
lm->l_name = my_context->fullpath;
1239-
lm->l_ld = GetDynamicSection(elf);
1239+
lm->l_ld = GetLoadedDynamicSection(elf);
12401240
}
12411241

12421242
needed_libs_t* new_neededlib(int n)

0 commit comments

Comments
 (0)