Skip to content

Commit 1f01b1d

Browse files
cataphractclaude
andcommitted
fix(ExecSolib): handle ET_EXEC trampoline in solib_bootstrap
The trampoline binary embedded in ddtrace.so is produced as ET_EXEC (non-PIE) by toolchains that don't default to -fPIE (e.g. devtoolset-7 on CentOS 7). elf_load_trampoline previously accepted only ET_DYN and used mmap(NULL) to pick a random load base -- an ET_EXEC binary loaded that way runs at the wrong virtual address and crashes with SIGSEGV. Two-pronged fix: 1. solib_bootstrap.c: accept both ET_DYN and ET_EXEC. For ET_EXEC, reserve the binary's fixed virtual address range with MAP_FIXED (valid in the bootstrap context: no ld.so yet, fresh address space). 2. libdatadog/spawn_worker/build.rs: add -fPIE/-pie on Linux so future builds always produce a PIE (ET_DYN) trampoline, matching the original design intent of elf_load_trampoline. Fixes "failed to map trampoline" (exit 121) on bookworm-slim for PHP 8.3-8.5. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent da0f6aa commit 1f01b1d

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

ext/solib_bootstrap.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,9 @@ static int elf_load_trampoline(const void *src, size_t src_len,
708708
if (src_len < sizeof(Elf64_Ehdr)) return -1;
709709
const Elf64_Ehdr *ehdr = (const Elf64_Ehdr *)src;
710710

711-
if (elf_check_header(ehdr, 1u << ET_DYN, 32) < 0) return -1;
711+
// Accept both ET_DYN (PIE, the ideal case) and ET_EXEC (non-PIE, produced
712+
// by toolchains that don't default to -fPIE; handled via MAP_FIXED below).
713+
if (elf_check_header(ehdr, (1u << ET_DYN) | (1u << ET_EXEC), 32) < 0) return -1;
712714
if (ehdr->e_phoff + (uint64_t)ehdr->e_phnum * sizeof(Elf64_Phdr) > src_len) return -1;
713715

714716
const Elf64_Phdr *phdrs = (const Elf64_Phdr *)((const char *)src + ehdr->e_phoff);
@@ -723,8 +725,28 @@ static int elf_load_trampoline(const void *src, size_t src_len,
723725
if (fd < 0) return -1;
724726

725727
uintptr_t base; long total;
726-
if (elf_reserve(phdrs, ehdr->e_phnum, page_size, &base, &total) < 0) {
727-
sys_close(fd); return -1;
728+
if (ehdr->e_type == ET_EXEC) {
729+
// ET_EXEC: fixed virtual addresses; the bootstrap runs before ld.so in a
730+
// fresh address space, so the low-address range should be available.
731+
// Reserve it with MAP_FIXED so elf_map_segments can overwrite it.
732+
uintptr_t lo = (uintptr_t)-1, hi = 0;
733+
for (int i = 0; i < ehdr->e_phnum; i++) {
734+
if (phdrs[i].p_type != PT_LOAD) continue;
735+
uintptr_t slo = BS_PAGE_DOWN(phdrs[i].p_vaddr, page_size);
736+
uintptr_t shi = BS_PAGE_UP(phdrs[i].p_vaddr + phdrs[i].p_memsz, page_size);
737+
if (slo < lo) lo = slo;
738+
if (shi > hi) hi = shi;
739+
}
740+
if (lo == (uintptr_t)-1) { sys_close(fd); return -1; }
741+
total = (long)(hi - lo);
742+
void *fixed = sys_mmap((void *)lo, total, BS_PROT_NONE,
743+
BS_MAP_PRIVATE | BS_MAP_ANONYMOUS | BS_MAP_FIXED, -1, 0);
744+
if (fixed == BS_MAP_FAILED) { sys_close(fd); return -1; }
745+
base = 0; // load bias is 0: runtime address == p_vaddr
746+
} else {
747+
if (elf_reserve(phdrs, ehdr->e_phnum, page_size, &base, &total) < 0) {
748+
sys_close(fd); return -1;
749+
}
728750
}
729751
if (elf_map_segments(fd, (long)tramp_file_bias, phdrs, ehdr->e_phnum,
730752
base, page_size) < 0) {

libdatadog

0 commit comments

Comments
 (0)