summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Sateler <fsateler@debian.org>2020-06-13 13:39:48 -0400
committerFelipe Sateler <fsateler@debian.org>2020-06-13 13:39:48 -0400
commit2adb846adcd942f5ccb0cf76f1aff577f79da3a9 (patch)
treec994d148ca25cfd0c679643eebe91dacbd582751
parent12152443758d33f815d24804eab452c56477de2b (diff)
Fix set-rpath corrupting binaries on mips
Pick a couple of proposed upstream patches to address the mips set-rpath failures. Closes: #821435
-rw-r--r--debian/patches/Adjust-DT_MIPS_RLD_MAP_REL-dynamic-section-entry-if-prese.patch82
-rw-r--r--debian/patches/Adjust-PT_MIPS_ABIFLAGS-segment-if-present.patch59
-rw-r--r--debian/patches/series2
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