aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Trofimovich <slyfox@gentoo.org>2018-02-18 20:10:45 +0000
committerSergei Trofimovich <slyfox@gentoo.org>2018-02-18 20:10:45 +0000
commite7b8f34f4557d7071a955ccab813ec41aeeb966b (patch)
tree645050cb3f45f4c9a29310672c08bdc9462dfd57
parentautogen.sh: add gnulib modules for Solaris (diff)
downloadpax-utils-e7b8f34f4557d7071a955ccab813ec41aeeb966b.tar.gz
pax-utils-e7b8f34f4557d7071a955ccab813ec41aeeb966b.tar.bz2
pax-utils-e7b8f34f4557d7071a955ccab813ec41aeeb966b.zip
scanelf.c: fix TEXTREL parsing for files with non-zero load addressv1.2.3
In bug #566118 scanelf failed to decode TEXTRELs on gcc binaries where program headers have absolute addresses: $ dumpelf ia64_bug_gcc/cc1plus /* Dynamic tag #25 'DT_RELA' 0x2099518 */ { .d_tag = 0x7 , .d_un = { .d_val = 0x4000000000104B08 , .d_ptr = 0x4000000000104B08 , }, }, /* Section Header #8 '.rela.dyn' 0x20AA610 */ { .sh_type = 4 , /* [SHT_RELA] */ .sh_addr = 0x4000000000104B08 , .sh_offset = 1067784 , /* (bytes) */ }, Before the change scanelf assumed DT_RELA.d_ptr is a relative offset. This is not true in general case but good-enough for DSOs as they have zero load address. This change extends the check for executables. To make addresses relative again we find load address of first byte from program header with 'p_offset'. /* Program Header #2 0xB0 */ { .p_type = 1 , /* [PT_LOAD] */ .p_offset = 0 , /* (bytes into file) */ .p_vaddr = 0x4000000000000000 , /* (virtual addr at runtime) */ .p_paddr = 0x4000000000000000 , /* (physical addr at runtime) */ }, Bug: https://bugs.gentoo.org/566118 Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
-rw-r--r--scanelf.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/scanelf.c b/scanelf.c
index a054408..530edfb 100644
--- a/scanelf.c
+++ b/scanelf.c
@@ -579,6 +579,8 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun
Elf ## B ## _Rela *rela; \
Elf ## B ## _Dyn *dyn, *drel, *drelsz, *drelent, *dpltrel; \
uint32_t pltrel; \
+ Elf ## B ## _Addr load_address = 0; \
+ Elf ## B ## _Addr file_offset; \
\
/* Walk all the dynamic tags to find relocation info */ \
drel = drelsz = drelent = dpltrel = NULL; \
@@ -605,27 +607,40 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun
warnf("ELF is missing relocation information"); \
break; \
} \
+ phdr = PHDR ## B(elf->phdr); \
+ /* Lookup load base: byte 0 is mapped at load_address */ \
+ for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
+ /* Only care about loadable segments. */ \
+ if (EGET(phdr[i].p_type) != PT_LOAD) \
+ continue; \
+ /* We search for the first program header to map into memory */ \
+ if (EGET(phdr[i].p_offset) != 0) \
+ continue; \
+ load_address = EGET(phdr[i].p_vaddr); \
+ } \
switch (EGET(dpltrel->d_un.d_val)) { \
case DT_REL: \
- if (!VALID_RANGE(elf, EGET(drel->d_un.d_val), sizeof (drel->d_un.d_val))) { \
+ file_offset = EGET(drel->d_un.d_val) - load_address; \
+ if (!VALID_RANGE(elf, file_offset, sizeof (drel->d_un.d_val))) { \
rel = NULL; \
rela = NULL; \
warn("%s: DT_REL is out of file range", elf->filename); \
break; \
} \
- rel = REL##B(elf->vdata + EGET(drel->d_un.d_val)); \
+ rel = REL##B(elf->vdata + file_offset); \
rela = NULL; \
pltrel = DT_REL; \
break; \
case DT_RELA: \
- if (!VALID_RANGE(elf, EGET(drel->d_un.d_val), sizeof (drel->d_un.d_val))) { \
+ file_offset = EGET(drel->d_un.d_val) - load_address; \
+ if (!VALID_RANGE(elf, file_offset, sizeof (drel->d_un.d_val))) { \
rel = NULL; \
rela = NULL; \
warn("%s: DT_RELA is out of file range", elf->filename); \
break; \
} \
rel = NULL; \
- rela = RELA##B(elf->vdata + EGET(drel->d_un.d_val)); \
+ rela = RELA##B(elf->vdata + file_offset); \
pltrel = DT_RELA; \
break; \
default: \
@@ -639,7 +654,6 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun
rmax = EGET(drelsz->d_un.d_val) / EGET(drelent->d_un.d_val); \
\
/* search the program segments for relocations */ \
- phdr = PHDR ## B(elf->phdr); \
for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \
uint ## B ## _t memsz = EGET(phdr[i].p_memsz); \