diff options
-rw-r--r-- | debian/patches/Adjust-DT_MIPS_RLD_MAP_REL-dynamic-section-entry-if-prese.patch | 82 | ||||
-rw-r--r-- | debian/patches/Adjust-PT_MIPS_ABIFLAGS-segment-if-present.patch | 59 | ||||
-rw-r--r-- | debian/patches/series | 2 |
3 files changed, 143 insertions, 0 deletions
diff --git a/debian/patches/Adjust-DT_MIPS_RLD_MAP_REL-dynamic-section-entry-if-prese.patch b/debian/patches/Adjust-DT_MIPS_RLD_MAP_REL-dynamic-section-entry-if-prese.patch new file mode 100644 index 0000000..ffee4b9 --- /dev/null +++ b/debian/patches/Adjust-DT_MIPS_RLD_MAP_REL-dynamic-section-entry-if-prese.patch @@ -0,0 +1,82 @@ +From: "Ivan A. Melnikov" <iv@altlinux.org> +Date: Thu, 22 Aug 2019 15:30:11 +0400 +Subject: Adjust DT_MIPS_RLD_MAP_REL dynamic section entry if present + +`patchelf --set-rpath` corrupted executables on mips32el: the dynamic +liker crushed with Segmentation fault when loading any executable with +RPATH added that way. + +The problem was around the MIPS-specific mechanism of setting up the +debug map pointer. When DT_MIPS_RLD_MAP_REL entry in the dynamic section +is not zero, it holds the relative address of __RLD_MAP -- an offset +relative to this dynamic section entry. Dynamic linker puts the +pointer to the `r_debug` structure there. + +When patchelf updates the executable RPATH, it moves the .dynamic +section both in the binary and in memory, while __RLD_MAP is not moved +in memory, since it belongs to special .rld_map section that has type +PROGBITS. So, the offset stored in DT_MIPS_RLD_MAP_REL entry is not +valid anymore and should be updated. + +This commit adds the necessary update. + +Here we also import DT_MIPS_RLD_MAP_REL definition in elf.h form +glibc commit a2057c984e4314c3740f04cf54e36c824e4c8f32. + +Refs: #82 +Signed-off-by: Ivan A. Melnikov <iv@altlinux.org> + +DT_MIPS_RLD_MAP_REL +--- + src/elf.h | 6 +++++- + src/patchelf.cc | 12 ++++++++++-- + 2 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/src/elf.h b/src/elf.h +index 87cb141..e4e167c 100644 +--- a/src/elf.h ++++ b/src/elf.h +@@ -1640,7 +1640,11 @@ typedef struct + PLT is writable. For a non-writable PLT, this is omitted or has a zero + value. */ + #define DT_MIPS_RWPLT 0x70000034 +-#define DT_MIPS_NUM 0x35 ++/* An alternative description of the classic MIPS RLD_MAP that is usable ++ in a PIE as it stores a relative offset from the address of the tag ++ rather than an absolute address. */ ++#define DT_MIPS_RLD_MAP_REL 0x70000035 ++#define DT_MIPS_NUM 0x36 + + /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +diff --git a/src/patchelf.cc b/src/patchelf.cc +index 965686a..d8ea097 100644 +--- a/src/patchelf.cc ++++ b/src/patchelf.cc +@@ -949,9 +949,9 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress) + (e.g., those produced by klibc's klcc). */ + Elf_Shdr * shdrDynamic = findSection2(".dynamic"); + if (shdrDynamic) { +- Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic->sh_offset)); ++ Elf_Dyn * dyn_table = (Elf_Dyn *) (contents + rdi(shdrDynamic->sh_offset)); + unsigned int d_tag; +- for ( ; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++) ++ for (Elf_Dyn * dyn = dyn_table; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++) + if (d_tag == DT_STRTAB) + dyn->d_un.d_ptr = findSection(".dynstr").sh_addr; + else if (d_tag == DT_STRSZ) +@@ -990,6 +990,14 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress) + dyn->d_un.d_ptr = findSection(".gnu.version_r").sh_addr; + else if (d_tag == DT_VERSYM) + dyn->d_un.d_ptr = findSection(".gnu.version").sh_addr; ++ else if (d_tag == DT_MIPS_RLD_MAP_REL) { ++ /* the MIPS_RLD_MAP_REL tag stores the offset to the debug ++ pointer, relative to the address of the tag */ ++ debug("Updating DT_MIPS_RLD_MAP_REL"); ++ Elf_Addr rtld_map_addr = findSection(".rld_map").sh_addr; ++ auto dyn_offset = ((char*)dyn) - ((char*)dyn_table); ++ dyn->d_un.d_ptr = rtld_map_addr + dyn_offset - shdrDynamic->sh_addr; ++ } + } + + diff --git a/debian/patches/Adjust-PT_MIPS_ABIFLAGS-segment-if-present.patch b/debian/patches/Adjust-PT_MIPS_ABIFLAGS-segment-if-present.patch new file mode 100644 index 0000000..7cdf2c1 --- /dev/null +++ b/debian/patches/Adjust-PT_MIPS_ABIFLAGS-segment-if-present.patch @@ -0,0 +1,59 @@ +From: "Ivan A. Melnikov" <iv@altlinux.org> +Date: Thu, 22 Aug 2019 18:04:57 +0400 +Subject: Adjust PT_MIPS_ABIFLAGS segment if present + +When loading the executable on MIPS, the dynamic loader looks for MIPS +ABI flags using PT_MIPS_ABIFLAGS header. The flags themselves are stored +in the .MIPS.abiflags section, so the header must be updated when the +section is moved. + +Here we also import PT_MIPS_ABIFLAGS definition from glibc commit +0bd956720c457ff054325b48f26ac7c91cb060e8. + +Closes: #82 +Signed-off-by: Ivan A. Melnikov <iv@altlinux.org> +--- + src/elf.h | 7 ++++--- + src/patchelf.cc | 11 +++++++++++ + 2 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/src/elf.h b/src/elf.h +index e4e167c..a92289d 100644 +--- a/src/elf.h ++++ b/src/elf.h +@@ -1572,9 +1572,10 @@ typedef struct + + /* Legal values for p_type field of Elf32_Phdr. */ + +-#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +-#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +-#define PT_MIPS_OPTIONS 0x70000002 ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information. */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++#define PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement. */ + + /* Special program header types. */ + +diff --git a/src/patchelf.cc b/src/patchelf.cc +index d8ea097..fecfc90 100644 +--- a/src/patchelf.cc ++++ b/src/patchelf.cc +@@ -687,6 +687,17 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff, + } + } + ++ /* If there is .MIPS.abiflags section, then the PT_MIPS_ABIFLAGS ++ segment must be sync'ed with it. */ ++ if (sectionName == ".MIPS.abiflags") { ++ for (unsigned int j = 0; j < phdrs.size(); ++j) ++ if (rdi(phdrs[j].p_type) == PT_MIPS_ABIFLAGS) { ++ phdrs[j].p_offset = shdr.sh_offset; ++ phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr; ++ phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size; ++ } ++ } ++ + curOff += roundUp(i.second.size(), sectionAlignment); + } + diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..c9bfdcd --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,2 @@ +Adjust-DT_MIPS_RLD_MAP_REL-dynamic-section-entry-if-prese.patch +Adjust-PT_MIPS_ABIFLAGS-segment-if-present.patch |