1 |
commit: e7b8f34f4557d7071a955ccab813ec41aeeb966b |
2 |
Author: Sergei Trofimovich <slyfox <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sun Feb 18 20:10:45 2018 +0000 |
4 |
Commit: Sergei Trofimovich <slyfox <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Feb 18 20:10:45 2018 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=e7b8f34f |
7 |
|
8 |
scanelf.c: fix TEXTREL parsing for files with non-zero load address |
9 |
|
10 |
In bug #566118 scanelf failed to decode TEXTRELs on gcc binaries |
11 |
where program headers have absolute addresses: |
12 |
|
13 |
$ dumpelf ia64_bug_gcc/cc1plus |
14 |
/* Dynamic tag #25 'DT_RELA' 0x2099518 */ |
15 |
{ |
16 |
.d_tag = 0x7 , |
17 |
.d_un = { |
18 |
.d_val = 0x4000000000104B08 , |
19 |
.d_ptr = 0x4000000000104B08 , |
20 |
}, |
21 |
}, |
22 |
/* Section Header #8 '.rela.dyn' 0x20AA610 */ |
23 |
{ |
24 |
.sh_type = 4 , /* [SHT_RELA] */ |
25 |
.sh_addr = 0x4000000000104B08 , |
26 |
.sh_offset = 1067784 , /* (bytes) */ |
27 |
}, |
28 |
|
29 |
Before the change scanelf assumed DT_RELA.d_ptr is |
30 |
a relative offset. This is not true in general case |
31 |
but good-enough for DSOs as they have zero load address. |
32 |
|
33 |
This change extends the check for executables. |
34 |
To make addresses relative again we find load address |
35 |
of first byte from program header with 'p_offset'. |
36 |
|
37 |
/* Program Header #2 0xB0 */ |
38 |
{ |
39 |
.p_type = 1 , /* [PT_LOAD] */ |
40 |
.p_offset = 0 , /* (bytes into file) */ |
41 |
.p_vaddr = 0x4000000000000000 , /* (virtual addr at runtime) */ |
42 |
.p_paddr = 0x4000000000000000 , /* (physical addr at runtime) */ |
43 |
}, |
44 |
|
45 |
Bug: https://bugs.gentoo.org/566118 |
46 |
Signed-off-by: Sergei Trofimovich <slyfox <AT> gentoo.org> |
47 |
|
48 |
scanelf.c | 24 +++++++++++++++++++----- |
49 |
1 file changed, 19 insertions(+), 5 deletions(-) |
50 |
|
51 |
diff --git a/scanelf.c b/scanelf.c |
52 |
index a054408..530edfb 100644 |
53 |
--- a/scanelf.c |
54 |
+++ b/scanelf.c |
55 |
@@ -579,6 +579,8 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun |
56 |
Elf ## B ## _Rela *rela; \ |
57 |
Elf ## B ## _Dyn *dyn, *drel, *drelsz, *drelent, *dpltrel; \ |
58 |
uint32_t pltrel; \ |
59 |
+ Elf ## B ## _Addr load_address = 0; \ |
60 |
+ Elf ## B ## _Addr file_offset; \ |
61 |
\ |
62 |
/* Walk all the dynamic tags to find relocation info */ \ |
63 |
drel = drelsz = drelent = dpltrel = NULL; \ |
64 |
@@ -605,27 +607,40 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun |
65 |
warnf("ELF is missing relocation information"); \ |
66 |
break; \ |
67 |
} \ |
68 |
+ phdr = PHDR ## B(elf->phdr); \ |
69 |
+ /* Lookup load base: byte 0 is mapped at load_address */ \ |
70 |
+ for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ |
71 |
+ /* Only care about loadable segments. */ \ |
72 |
+ if (EGET(phdr[i].p_type) != PT_LOAD) \ |
73 |
+ continue; \ |
74 |
+ /* We search for the first program header to map into memory */ \ |
75 |
+ if (EGET(phdr[i].p_offset) != 0) \ |
76 |
+ continue; \ |
77 |
+ load_address = EGET(phdr[i].p_vaddr); \ |
78 |
+ } \ |
79 |
switch (EGET(dpltrel->d_un.d_val)) { \ |
80 |
case DT_REL: \ |
81 |
- if (!VALID_RANGE(elf, EGET(drel->d_un.d_val), sizeof (drel->d_un.d_val))) { \ |
82 |
+ file_offset = EGET(drel->d_un.d_val) - load_address; \ |
83 |
+ if (!VALID_RANGE(elf, file_offset, sizeof (drel->d_un.d_val))) { \ |
84 |
rel = NULL; \ |
85 |
rela = NULL; \ |
86 |
warn("%s: DT_REL is out of file range", elf->filename); \ |
87 |
break; \ |
88 |
} \ |
89 |
- rel = REL##B(elf->vdata + EGET(drel->d_un.d_val)); \ |
90 |
+ rel = REL##B(elf->vdata + file_offset); \ |
91 |
rela = NULL; \ |
92 |
pltrel = DT_REL; \ |
93 |
break; \ |
94 |
case DT_RELA: \ |
95 |
- if (!VALID_RANGE(elf, EGET(drel->d_un.d_val), sizeof (drel->d_un.d_val))) { \ |
96 |
+ file_offset = EGET(drel->d_un.d_val) - load_address; \ |
97 |
+ if (!VALID_RANGE(elf, file_offset, sizeof (drel->d_un.d_val))) { \ |
98 |
rel = NULL; \ |
99 |
rela = NULL; \ |
100 |
warn("%s: DT_RELA is out of file range", elf->filename); \ |
101 |
break; \ |
102 |
} \ |
103 |
rel = NULL; \ |
104 |
- rela = RELA##B(elf->vdata + EGET(drel->d_un.d_val)); \ |
105 |
+ rela = RELA##B(elf->vdata + file_offset); \ |
106 |
pltrel = DT_RELA; \ |
107 |
break; \ |
108 |
default: \ |
109 |
@@ -639,7 +654,6 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun |
110 |
rmax = EGET(drelsz->d_un.d_val) / EGET(drelent->d_un.d_val); \ |
111 |
\ |
112 |
/* search the program segments for relocations */ \ |
113 |
- phdr = PHDR ## B(elf->phdr); \ |
114 |
for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ |
115 |
Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \ |
116 |
uint ## B ## _t memsz = EGET(phdr[i].p_memsz); \ |