Gentoo Archives: gentoo-commits

From: Mike Frysinger <vapier@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/pax-utils:master commit in: /
Date: Tue, 24 Jan 2017 06:50:12
Message-Id: 1485224720.95e5489534ac9e9324c5096286899b688e19ae00.vapier@gentoo
1 commit: 95e5489534ac9e9324c5096286899b688e19ae00
2 Author: Mike Frysinger <vapier <AT> gentoo <DOT> org>
3 AuthorDate: Tue Jan 24 02:25:20 2017 +0000
4 Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org>
5 CommitDate: Tue Jan 24 02:25:20 2017 +0000
6 URL: https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=95e54895
7
8 scanelf: add helper for walking dynamic tags
9
10 We have many loops that operate on dynamic tags which all crash when
11 given an ELF with a corrupt dynamic table. Add a helper to walk the
12 table so we can centralize bounds checking in one place.
13
14 Reported-by: Agostino Sarubbo <ago <AT> gentoo.org>
15
16 scanelf.c | 131 +++++++++++++++++---------------------------------------------
17 1 file changed, 35 insertions(+), 96 deletions(-)
18
19 diff --git a/scanelf.c b/scanelf.c
20 index 52c436a..ceec26d 100644
21 --- a/scanelf.c
22 +++ b/scanelf.c
23 @@ -189,6 +189,14 @@ static void *scanelf_file_get_pt_dynamic(elfobj *elf)
24 return NULL;
25 }
26
27 +#define scanelf_dt_for_each(B, elf, dyn) \
28 + { \
29 + Elf##B##_Phdr *_phdr = scanelf_file_get_pt_dynamic(elf); \
30 + dyn = (_phdr == NULL) ? elf->data_end : DYN##B(elf->vdata + EGET(_phdr->p_offset)); \
31 + } \
32 + --dyn; \
33 + while ((void *)++dyn < elf->data_end - sizeof(*dyn) && EGET(dyn->d_tag) != DT_NULL)
34 +
35 /* sub-funcs for scanelf_fileat() */
36 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
37 {
38 @@ -258,10 +266,9 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
39 size_t i; \
40 static Elf ## B ## _Shdr sym_shdr, str_shdr; \
41 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
42 - Elf ## B ## _Phdr *phdr; \
43 + Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
44 Elf ## B ## _Addr vsym, vstr, vhash, vgnu_hash; \
45 Elf ## B ## _Dyn *dyn; \
46 - Elf ## B ## _Off doffset; \
47 \
48 /* lookup symbols used at runtime with DT_SYMTAB / DT_STRTAB */ \
49 vsym = vstr = vhash = vgnu_hash = 0; \
50 @@ -269,13 +276,7 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
51 memset(&str_shdr, 0, sizeof(str_shdr)); \
52 \
53 /* Find the dynamic headers */ \
54 - phdr = scanelf_file_get_pt_dynamic(elf); \
55 - if (phdr == NULL) \
56 - break; \
57 - doffset = EGET(phdr->p_offset); \
58 - \
59 - dyn = DYN ## B (elf->vdata + doffset); \
60 - while (EGET(dyn->d_tag) != DT_NULL) { \
61 + scanelf_dt_for_each(B, elf, dyn) { \
62 switch (EGET(dyn->d_tag)) { \
63 case DT_SYMTAB: vsym = EGET(dyn->d_un.d_val); break; \
64 case DT_SYMENT: sym_shdr.sh_entsize = dyn->d_un.d_val; break; \
65 @@ -284,13 +285,11 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
66 case DT_HASH: vhash = EGET(dyn->d_un.d_val); break; \
67 /*case DT_GNU_HASH: vgnu_hash = EGET(dyn->d_un.d_val); break;*/ \
68 } \
69 - ++dyn; \
70 } \
71 if (!vsym || !vstr || !(vhash || vgnu_hash)) \
72 return; \
73 \
74 /* calc offset into the ELF by finding the load addr of the syms */ \
75 - phdr = PHDR ## B (elf->phdr); \
76 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
77 Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \
78 Elf ## B ## _Addr filesz = EGET(phdr[i].p_filesz); \
79 @@ -539,23 +538,13 @@ static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
80
81 #define SHOW_TEXTREL(B) \
82 Elf ## B ## _Dyn *dyn; \
83 - Elf ## B ## _Phdr *phdr; \
84 - Elf ## B ## _Off offset; \
85 - \
86 - /* Find the dynamic headers */ \
87 - phdr = scanelf_file_get_pt_dynamic(elf); \
88 - if (phdr == NULL) \
89 - break; \
90 - offset = EGET(phdr->p_offset); \
91 \
92 - dyn = DYN ## B (elf->vdata + offset); \
93 - while (EGET(dyn->d_tag) != DT_NULL) { \
94 + scanelf_dt_for_each(B, elf, dyn) { \
95 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
96 *found_textrel = 1; \
97 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
98 return (be_wewy_wewy_quiet ? NULL : ret); \
99 } \
100 - ++dyn; \
101 }
102 if (elf->phdr)
103 SCANELF_ELF_SIZED(SHOW_TEXTREL);
104 @@ -588,7 +577,6 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun
105 size_t i; \
106 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
107 Elf ## B ## _Phdr *phdr; \
108 - Elf ## B ## _Off offset; \
109 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
110 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
111 Elf ## B ## _Rel *rel; \
112 @@ -596,16 +584,9 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun
113 Elf ## B ## _Dyn *dyn, *drel, *drelsz, *drelent, *dpltrel; \
114 uint32_t pltrel; \
115 \
116 - /* Find the dynamic headers */ \
117 - phdr = scanelf_file_get_pt_dynamic(elf); \
118 - if (phdr == NULL) \
119 - break; \
120 - offset = EGET(phdr->p_offset); \
121 - \
122 /* Walk all the dynamic tags to find relocation info */ \
123 - dyn = DYN ## B (elf->vdata + offset); \
124 drel = drelsz = drelent = dpltrel = NULL; \
125 - while (EGET(dyn->d_tag) != DT_NULL) { \
126 + scanelf_dt_for_each(B, elf, dyn) { \
127 switch (EGET(dyn->d_tag)) { \
128 case DT_REL: \
129 case DT_RELA: \
130 @@ -623,7 +604,6 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun
131 dpltrel = dyn; \
132 break; \
133 } \
134 - ++dyn; \
135 } \
136 if (!drel || !drelsz || !drelent || !dpltrel) { \
137 warnf("ELF is missing relocation information"); \
138 @@ -796,26 +776,18 @@ static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_
139
140 #define SHOW_RPATH(B) \
141 Elf ## B ## _Dyn *dyn; \
142 - Elf ## B ## _Phdr *phdr; \
143 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
144 Elf ## B ## _Off offset; \
145 Elf ## B ## _Xword word; \
146 \
147 - /* Find the dynamic headers */ \
148 - phdr = scanelf_file_get_pt_dynamic(elf); \
149 - if (phdr == NULL) \
150 - break; \
151 - offset = EGET(phdr->p_offset); \
152 - \
153 /* Just scan dynamic RPATH/RUNPATH headers */ \
154 - dyn = DYN ## B (elf->vdata + offset); \
155 - while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
156 + scanelf_dt_for_each(B, elf, dyn) { \
157 + word = EGET(dyn->d_tag); \
158 if (word == DT_RPATH) { \
159 r = &rpath; \
160 } else if (word == DT_RUNPATH) { \
161 r = &runpath; \
162 } else { \
163 - ++dyn; \
164 continue; \
165 } \
166 /* Verify the memory is somewhat sane */ \
167 @@ -900,7 +872,6 @@ static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_
168 *found_rpath = 1; \
169 } \
170 } \
171 - ++dyn; \
172 }
173 if (elf->phdr && strtbl_void)
174 SCANELF_ELF_SIZED(SHOW_RPATH);
175 @@ -956,26 +927,15 @@ static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char
176
177 #define SHOW_NEEDED(B) \
178 Elf ## B ## _Dyn *dyn; \
179 - Elf ## B ## _Phdr *phdr; \
180 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
181 - Elf ## B ## _Off offset; \
182 size_t matched = 0; \
183 \
184 - /* Find the dynamic headers */ \
185 - phdr = scanelf_file_get_pt_dynamic(elf); \
186 - if (phdr == NULL) \
187 - break; \
188 - offset = EGET(phdr->p_offset); \
189 - \
190 /* Walk all the dynamic tags to find NEEDED entries */ \
191 - dyn = DYN ## B (elf->vdata + offset); \
192 - while (EGET(dyn->d_tag) != DT_NULL) { \
193 + scanelf_dt_for_each(B, elf, dyn) { \
194 if (EGET(dyn->d_tag) == DT_NEEDED) { \
195 - offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
196 - if (offset >= (Elf ## B ## _Off)elf->len) { \
197 - ++dyn; \
198 + Elf ## B ## _Off offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
199 + if (offset >= (Elf ## B ## _Off)elf->len) \
200 continue; \
201 - } \
202 needed = elf->data + offset; \
203 if (op == 0) { \
204 /* -n -> print all entries */ \
205 @@ -1010,7 +970,6 @@ static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char
206 } \
207 } \
208 } \
209 - ++dyn; \
210 }
211 if (elf->phdr && strtbl_void) {
212 SCANELF_ELF_SIZED(SHOW_NEEDED);
213 @@ -1066,7 +1025,6 @@ static char *scanelf_file_interp(elfobj *elf, char *found_interp)
214 }
215 static const char *scanelf_file_bind(elfobj *elf, char *found_bind)
216 {
217 - unsigned long i;
218 struct stat s;
219 bool dynamic = false;
220
221 @@ -1075,24 +1033,15 @@ static const char *scanelf_file_bind(elfobj *elf, char *found_bind)
222
223 #define SHOW_BIND(B) \
224 Elf ## B ## _Dyn *dyn; \
225 - Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
226 - Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
227 - Elf ## B ## _Off offset; \
228 - for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
229 - if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
230 + \
231 + scanelf_dt_for_each(B, elf, dyn) { \
232 dynamic = true; \
233 - offset = EGET(phdr[i].p_offset); \
234 - if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
235 - dyn = DYN ## B (elf->vdata + offset); \
236 - while (EGET(dyn->d_tag) != DT_NULL) { \
237 - if (EGET(dyn->d_tag) == DT_BIND_NOW || \
238 - (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
239 - { \
240 - if (be_quiet) return NULL; \
241 - *found_bind = 1; \
242 - return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
243 - } \
244 - ++dyn; \
245 + if (EGET(dyn->d_tag) == DT_BIND_NOW || \
246 + (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) { \
247 + if (be_quiet) \
248 + return NULL; \
249 + *found_bind = 1; \
250 + return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
251 } \
252 }
253 SCANELF_ELF_SIZED(SHOW_BIND);
254 @@ -1109,7 +1058,6 @@ static const char *scanelf_file_bind(elfobj *elf, char *found_bind)
255 }
256 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
257 {
258 - unsigned long i;
259 char *soname;
260 void *strtbl_void;
261
262 @@ -1120,29 +1068,20 @@ static char *scanelf_file_soname(elfobj *elf, char *found_soname)
263 #define SHOW_SONAME(B) \
264 Elf ## B ## _Dyn *dyn; \
265 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
266 - Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
267 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
268 - Elf ## B ## _Off offset; \
269 + \
270 /* only look for soname in shared objects */ \
271 if (EGET(ehdr->e_type) != ET_DYN) \
272 return NULL; \
273 - for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
274 - if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
275 - offset = EGET(phdr[i].p_offset); \
276 - if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
277 - dyn = DYN ## B (elf->vdata + offset); \
278 - while (EGET(dyn->d_tag) != DT_NULL) { \
279 - if (EGET(dyn->d_tag) == DT_SONAME) { \
280 - offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
281 - if (offset >= (Elf ## B ## _Off)elf->len) { \
282 - ++dyn; \
283 - continue; \
284 - } \
285 - soname = elf->data + offset; \
286 - *found_soname = 1; \
287 - return (be_wewy_wewy_quiet ? NULL : soname); \
288 - } \
289 - ++dyn; \
290 + \
291 + scanelf_dt_for_each(B, elf, dyn) { \
292 + if (EGET(dyn->d_tag) == DT_SONAME) { \
293 + Elf ## B ## _Off offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
294 + if (offset >= (Elf ## B ## _Off)elf->len) \
295 + continue; \
296 + soname = elf->data + offset; \
297 + *found_soname = 1; \
298 + return (be_wewy_wewy_quiet ? NULL : soname); \
299 } \
300 }
301 if (elf->phdr && strtbl_void)