Skip to content

Commit

Permalink
Adjust DT_MIPS_RLD_MAP_REL dynamic section entry if present
Browse files Browse the repository at this point in the history
`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
  • Loading branch information
iv-m committed Aug 22, 2019
1 parent 1bc54f0 commit 0f3e619
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 3 deletions.
6 changes: 5 additions & 1 deletion src/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */

Expand Down
12 changes: 10 additions & 2 deletions src/patchelf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -946,9 +946,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)
Expand Down Expand Up @@ -987,6 +987,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;
ptrdiff_t dyn_offset = ((char*)dyn) - ((char*)dyn_table);
dyn->d_un.d_ptr = rtld_map_addr + dyn_offset - shdrDynamic->sh_addr;
}
}


Expand Down

0 comments on commit 0f3e619

Please sign in to comment.