From c3ffe621533a19f9273960e0f50c5d21f98c3597 Mon Sep 17 00:00:00 2001 From: rcombs Date: Tue, 16 Jun 2020 13:50:19 -0500 Subject: [PATCH 1/2] rewriteSectionsLibrary: assume all libraries may be executable; fixes #165 --- src/patchelf.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 2d9077ce..35707db2 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -106,8 +106,6 @@ class ElfFile bool changed = false; - bool isExecutable = false; - typedef std::string SectionName; typedef std::map ReplacedSections; @@ -415,10 +413,8 @@ ElfFile::ElfFile(FileContents fileContents) error("program headers have wrong size"); /* Copy the program and section headers. */ - for (int i = 0; i < rdi(hdr->e_phnum); ++i) { + for (int i = 0; i < rdi(hdr->e_phnum); ++i) phdrs.push_back(* ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i)); - if (rdi(phdrs[i].p_type) == PT_INTERP) isExecutable = true; - } for (int i = 0; i < rdi(hdr->e_shnum); ++i) shdrs.push_back(* ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i)); @@ -741,10 +737,9 @@ void ElfFile::rewriteSectionsLibrary() since DYN executables tend to start at virtual address 0, so rewriteSectionsExecutable() won't work because it doesn't have any virtual address space to grow downwards into. */ - if (isExecutable && startOffset > startPage) { + if (startOffset > startPage) debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage); - startPage = startOffset; - } + startPage = startOffset; /* Add a segment that maps the replaced sections into memory. */ wri(hdr->e_phoff, sizeof(Elf_Ehdr)); From 5daa3576014a9cf45aad21be13b6273abe689a21 Mon Sep 17 00:00:00 2001 From: Rodger Combs Date: Fri, 29 Mar 2019 19:54:38 -0500 Subject: [PATCH 2/2] modifyRPath: when possible, avoid growing the dynamic section Growing the section can require changing its position, which results in crashes if the code relies on a symbol within it (e.g. _DYNAMIC). Instead, we can usually find an entry that isn't actually required and replace it. --- src/patchelf.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 35707db2..992cd3ee 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -1142,7 +1142,7 @@ void ElfFile::modifyRPath(RPathOp op, string. */ std::vector neededLibs; Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset)); - Elf_Dyn * dynRPath = 0, * dynRunPath = 0; + Elf_Dyn * dynRPath = 0, * dynRunPath = 0, * dynReplaceable = 0; char * rpath = 0; for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { if (rdi(dyn->d_tag) == DT_RPATH) { @@ -1157,6 +1157,12 @@ void ElfFile::modifyRPath(RPathOp op, } else if (rdi(dyn->d_tag) == DT_NEEDED) neededLibs.push_back(std::string(strTab + rdi(dyn->d_un.d_val))); + /* Try to replace an IGNORE rather than growing and moving the section, if possible */ + else if (rdi(dyn->d_tag) == DT_IGNORE) + dynReplaceable = dyn; + /* If we don't find an IGNORE, RELCOUNT/RELACOUNT are redundant and optional, so we can replace those */ + else if (!dynReplaceable && (rdi(dyn->d_tag) == DT_RELCOUNT || rdi(dyn->d_tag) == DT_RELACOUNT)) + dynReplaceable = dyn; } if (op == rpPrint) { @@ -1283,7 +1289,11 @@ void ElfFile::modifyRPath(RPathOp op, if (dynRunPath) dynRunPath->d_un.d_val = shdrDynStr.sh_size; if (dynRPath) dynRPath->d_un.d_val = shdrDynStr.sh_size; } - + /* Convert an unused or redundant entry to a DT_RPATH or DT_RUNPATH */ + else if (dynReplaceable) { + dynReplaceable->d_un.d_val = shdrDynStr.sh_size; + dynReplaceable->d_tag = forceRPath ? DT_RPATH : DT_RUNPATH; + } else { /* There is no DT_RUNPATH entry in the .dynamic section, so we have to grow the .dynamic section. */