1 /*
2 * various helper functions to access elf structures
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation;
7 * version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "libelf-private.h"
19
20 /* ------------------------------------------------------------------------ */
21
elf_mark_broken(struct elf_binary * elf,const char * msg)22 void elf_mark_broken(struct elf_binary *elf, const char *msg)
23 {
24 if ( elf->broken == NULL )
25 elf->broken = msg;
26 }
27
elf_check_broken(const struct elf_binary * elf)28 const char *elf_check_broken(const struct elf_binary *elf)
29 {
30 return elf->broken;
31 }
32
elf_ptrval_in_range(elf_ptrval ptrval,uint64_t size,const void * region,uint64_t regionsize)33 static bool elf_ptrval_in_range(elf_ptrval ptrval, uint64_t size,
34 const void *region, uint64_t regionsize)
35 /*
36 * Returns true if the putative memory area [ptrval,ptrval+size>
37 * is completely inside the region [region,region+regionsize>.
38 *
39 * ptrval and size are the untrusted inputs to be checked.
40 * region and regionsize are trusted and must be correct and valid,
41 * although it is OK for region to perhaps be maliciously NULL
42 * (but not some other malicious value).
43 */
44 {
45 elf_ptrval regionp = (elf_ptrval)region;
46
47 if ( (region == NULL) ||
48 (ptrval < regionp) || /* start is before region */
49 (ptrval > regionp + regionsize) || /* start is after region */
50 (size > regionsize - (ptrval - regionp)) ) /* too big */
51 return 0;
52 return 1;
53 }
54
elf_access_ok(struct elf_binary * elf,uint64_t ptrval,size_t size)55 bool elf_access_ok(struct elf_binary * elf,
56 uint64_t ptrval, size_t size)
57 {
58 if ( elf_ptrval_in_range(ptrval, size, elf->image_base, elf->size) )
59 return 1;
60 if ( elf_ptrval_in_range(ptrval, size, elf->dest_base, elf->dest_size) )
61 return 1;
62 if ( elf_ptrval_in_range(ptrval, size, elf->xdest_base, elf->xdest_size) )
63 return 1;
64 elf_mark_broken(elf, "out of range access");
65 return 0;
66 }
67
elf_memcpy_safe(struct elf_binary * elf,elf_ptrval dst,elf_ptrval src,size_t size)68 void elf_memcpy_safe(struct elf_binary *elf, elf_ptrval dst,
69 elf_ptrval src, size_t size)
70 {
71 if ( elf_access_ok(elf, dst, size) &&
72 elf_access_ok(elf, src, size) )
73 {
74 /* use memmove because these checks do not prove that the
75 * regions don't overlap and overlapping regions grant
76 * permission for compiler malice */
77 elf_memmove_unchecked(ELF_UNSAFE_PTR(dst), ELF_UNSAFE_PTR(src), size);
78 }
79 }
80
elf_memset_safe(struct elf_binary * elf,elf_ptrval dst,int c,size_t size)81 void elf_memset_safe(struct elf_binary *elf, elf_ptrval dst, int c, size_t size)
82 {
83 if ( elf_access_ok(elf, dst, size) )
84 {
85 elf_memset_unchecked(ELF_UNSAFE_PTR(dst), c, size);
86 }
87 }
88
elf_access_unsigned(struct elf_binary * elf,elf_ptrval base,uint64_t moreoffset,size_t size)89 uint64_t elf_access_unsigned(struct elf_binary * elf, elf_ptrval base,
90 uint64_t moreoffset, size_t size)
91 {
92 elf_ptrval ptrval = base + moreoffset;
93 bool need_swap = elf_swap(elf);
94 const uint8_t *u8;
95 const uint16_t *u16;
96 const uint32_t *u32;
97 const uint64_t *u64;
98
99 if ( !elf_access_ok(elf, ptrval, size) )
100 return 0;
101
102 switch ( size )
103 {
104 case 1:
105 u8 = (const void*)ptrval;
106 return *u8;
107 case 2:
108 u16 = (const void*)ptrval;
109 return need_swap ? bswap_16(*u16) : *u16;
110 case 4:
111 u32 = (const void*)ptrval;
112 return need_swap ? bswap_32(*u32) : *u32;
113 case 8:
114 u64 = (const void*)ptrval;
115 return need_swap ? bswap_64(*u64) : *u64;
116 default:
117 return 0;
118 }
119 }
120
elf_round_up(struct elf_binary * elf,uint64_t addr)121 uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr)
122 {
123 uint64_t elf_round = (elf_64bit(elf) ? 8 : 4) - 1;
124
125 return (addr + elf_round) & ~elf_round;
126 }
127
128 /* ------------------------------------------------------------------------ */
129
elf_shdr_count(struct elf_binary * elf)130 unsigned elf_shdr_count(struct elf_binary *elf)
131 {
132 unsigned count = elf_uval(elf, elf->ehdr, e_shnum);
133 uint64_t max = elf->size / sizeof(Elf32_Shdr);
134
135 if ( max > UINT_MAX )
136 max = UINT_MAX;
137 if ( count > max )
138 {
139 elf_mark_broken(elf, "far too many section headers");
140 count = max;
141 }
142 return count;
143 }
144
elf_phdr_count(struct elf_binary * elf)145 unsigned elf_phdr_count(struct elf_binary *elf)
146 {
147 return elf_uval(elf, elf->ehdr, e_phnum);
148 }
149
elf_shdr_by_name(struct elf_binary * elf,const char * name)150 ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *name)
151 {
152 unsigned i, count = elf_shdr_count(elf);
153 ELF_HANDLE_DECL(elf_shdr) shdr;
154 const char *sname;
155
156 for ( i = 1; i < count; i++ )
157 {
158 shdr = elf_shdr_by_index(elf, i);
159 if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
160 /* input has an insane section header count field */
161 break;
162 sname = elf_section_name(elf, shdr);
163 if ( sname && !strcmp(sname, name) )
164 return shdr;
165 }
166 return ELF_INVALID_HANDLE(elf_shdr);
167 }
168
elf_shdr_by_index(struct elf_binary * elf,unsigned index)169 ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_index(struct elf_binary *elf, unsigned index)
170 {
171 unsigned count = elf_shdr_count(elf);
172 elf_ptrval ptr;
173
174 if ( index >= count )
175 return ELF_INVALID_HANDLE(elf_shdr);
176
177 ptr = (ELF_IMAGE_BASE(elf)
178 + elf_uval(elf, elf->ehdr, e_shoff)
179 + elf_uval(elf, elf->ehdr, e_shentsize) * index);
180 return ELF_MAKE_HANDLE(elf_shdr, ptr);
181 }
182
elf_phdr_by_index(struct elf_binary * elf,unsigned index)183 ELF_HANDLE_DECL(elf_phdr) elf_phdr_by_index(struct elf_binary *elf, unsigned index)
184 {
185 unsigned count = elf_phdr_count(elf);
186 elf_ptrval ptr;
187
188 if ( index >= count )
189 return ELF_INVALID_HANDLE(elf_phdr);
190
191 ptr = (ELF_IMAGE_BASE(elf)
192 + elf_uval(elf, elf->ehdr, e_phoff)
193 + elf_uval(elf, elf->ehdr, e_phentsize) * index);
194 return ELF_MAKE_HANDLE(elf_phdr, ptr);
195 }
196
197
elf_section_name(struct elf_binary * elf,ELF_HANDLE_DECL (elf_shdr)shdr)198 const char *elf_section_name(struct elf_binary *elf,
199 ELF_HANDLE_DECL(elf_shdr) shdr)
200 {
201 if ( ELF_PTRVAL_INVALID(elf->sec_strtab) )
202 return "unknown";
203
204 return elf_strval(elf, elf->sec_strtab + elf_uval(elf, shdr, sh_name));
205 }
206
elf_strval(struct elf_binary * elf,elf_ptrval start)207 const char *elf_strval(struct elf_binary *elf, elf_ptrval start)
208 {
209 uint64_t length;
210
211 for ( length = 0; ; length++ ) {
212 if ( !elf_access_ok(elf, start + length, 1) )
213 return NULL;
214 if ( !elf_access_unsigned(elf, start, length, 1) )
215 /* ok */
216 return ELF_UNSAFE_PTR(start);
217 if ( length >= ELF_MAX_STRING_LENGTH )
218 {
219 elf_mark_broken(elf, "excessively long string");
220 return NULL;
221 }
222 }
223 }
224
elf_strfmt(struct elf_binary * elf,elf_ptrval start)225 const char *elf_strfmt(struct elf_binary *elf, elf_ptrval start)
226 {
227 const char *str = elf_strval(elf, start);
228
229 if ( str == NULL )
230 return "(invalid)";
231 return str;
232 }
233
elf_section_start(struct elf_binary * elf,ELF_HANDLE_DECL (elf_shdr)shdr)234 elf_ptrval elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr)
235 {
236 return ELF_IMAGE_BASE(elf) + elf_uval(elf, shdr, sh_offset);
237 }
238
elf_section_end(struct elf_binary * elf,ELF_HANDLE_DECL (elf_shdr)shdr)239 elf_ptrval elf_section_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr)
240 {
241 return ELF_IMAGE_BASE(elf)
242 + elf_uval(elf, shdr, sh_offset) + elf_uval(elf, shdr, sh_size);
243 }
244
elf_segment_start(struct elf_binary * elf,ELF_HANDLE_DECL (elf_phdr)phdr)245 elf_ptrval elf_segment_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
246 {
247 return ELF_IMAGE_BASE(elf)
248 + elf_uval(elf, phdr, p_offset);
249 }
250
elf_segment_end(struct elf_binary * elf,ELF_HANDLE_DECL (elf_phdr)phdr)251 elf_ptrval elf_segment_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
252 {
253 return ELF_IMAGE_BASE(elf)
254 + elf_uval(elf, phdr, p_offset) + elf_uval(elf, phdr, p_filesz);
255 }
256
elf_sym_by_name(struct elf_binary * elf,const char * symbol)257 ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *symbol)
258 {
259 elf_ptrval ptr = elf_section_start(elf, elf->sym_tab);
260 elf_ptrval end = elf_section_end(elf, elf->sym_tab);
261 ELF_HANDLE_DECL(elf_sym) sym;
262 uint64_t info, name;
263 const char *sym_name;
264
265 for ( ; ptr < end; ptr += elf_size(elf, sym) )
266 {
267 sym = ELF_MAKE_HANDLE(elf_sym, ptr);
268 info = elf_uval(elf, sym, st_info);
269 name = elf_uval(elf, sym, st_name);
270 if ( ELF32_ST_BIND(info) != STB_GLOBAL )
271 continue;
272 sym_name = elf_strval(elf, elf->sym_strtab + name);
273 if ( sym_name == NULL ) /* out of range, oops */
274 return ELF_INVALID_HANDLE(elf_sym);
275 if ( strcmp(sym_name, symbol) )
276 continue;
277 return sym;
278 }
279 return ELF_INVALID_HANDLE(elf_sym);
280 }
281
elf_sym_by_index(struct elf_binary * elf,unsigned index)282 ELF_HANDLE_DECL(elf_sym) elf_sym_by_index(struct elf_binary *elf, unsigned index)
283 {
284 elf_ptrval ptr = elf_section_start(elf, elf->sym_tab);
285 ELF_HANDLE_DECL(elf_sym) sym;
286
287 sym = ELF_MAKE_HANDLE(elf_sym, ptr + index * elf_size(elf, sym));
288 return sym;
289 }
290
elf_note_name(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)291 const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
292 {
293 return elf_strval(elf, ELF_HANDLE_PTRVAL(note) + elf_size(elf, note));
294 }
295
elf_note_desc(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)296 elf_ptrval elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
297 {
298 unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
299
300 return ELF_HANDLE_PTRVAL(note) + elf_size(elf, note) + namesz;
301 }
302
elf_note_numeric(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)303 uint64_t elf_note_numeric(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
304 {
305 elf_ptrval desc = elf_note_desc(elf, note);
306 unsigned descsz = elf_uval(elf, note, descsz);
307
308 switch (descsz)
309 {
310 case 1:
311 case 2:
312 case 4:
313 case 8:
314 return elf_access_unsigned(elf, desc, 0, descsz);
315 default:
316 return 0;
317 }
318 }
319
elf_note_numeric_array(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note,unsigned int unitsz,unsigned int idx)320 uint64_t elf_note_numeric_array(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note,
321 unsigned int unitsz, unsigned int idx)
322 {
323 elf_ptrval desc = elf_note_desc(elf, note);
324 unsigned descsz = elf_uval(elf, note, descsz);
325
326 if ( descsz % unitsz || idx >= descsz / unitsz )
327 return 0;
328 switch (unitsz)
329 {
330 case 1:
331 case 2:
332 case 4:
333 case 8:
334 return elf_access_unsigned(elf, desc, idx * unitsz, unitsz);
335 default:
336 return 0;
337 }
338 }
339
elf_note_next(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)340 ELF_HANDLE_DECL(elf_note) elf_note_next(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
341 {
342 unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
343 unsigned descsz = (elf_uval(elf, note, descsz) + 3) & ~3;
344
345 elf_ptrval ptrval = ELF_HANDLE_PTRVAL(note)
346 + elf_size(elf, note) + namesz + descsz;
347
348 if ( ( ptrval <= ELF_HANDLE_PTRVAL(note) || /* wrapped or stuck */
349 !elf_access_ok(elf, ELF_HANDLE_PTRVAL(note), 1) ) )
350 ptrval = ELF_MAX_PTRVAL; /* terminate caller's loop */
351
352 return ELF_MAKE_HANDLE(elf_note, ptrval);
353 }
354
355 /* ------------------------------------------------------------------------ */
356
elf_is_elfbinary(const void * image_start,size_t image_size)357 bool elf_is_elfbinary(const void *image_start, size_t image_size)
358 {
359 const Elf32_Ehdr *ehdr = image_start;
360
361 if ( image_size < sizeof(*ehdr) )
362 return 0;
363
364 return IS_ELF(*ehdr);
365 }
366
elf_phdr_is_loadable(struct elf_binary * elf,ELF_HANDLE_DECL (elf_phdr)phdr)367 bool elf_phdr_is_loadable(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
368 {
369 uint64_t p_type = elf_uval(elf, phdr, p_type);
370 uint64_t p_flags = elf_uval(elf, phdr, p_flags);
371
372 return ((p_type == PT_LOAD) && (p_flags & (PF_R | PF_W | PF_X)) != 0);
373 }
374
elf_set_xdest(struct elf_binary * elf,void * addr,uint64_t size)375 void elf_set_xdest(struct elf_binary *elf, void *addr, uint64_t size)
376 {
377 elf->xdest_base = addr;
378 elf->xdest_size = size;
379 if ( addr != NULL )
380 elf_memset_safe(elf, ELF_REALPTR2PTRVAL(addr), 0, size);
381 }
382
383 /*
384 * Local variables:
385 * mode: C
386 * c-file-style: "BSD"
387 * c-basic-offset: 4
388 * tab-width: 4
389 * indent-tabs-mode: nil
390 * End:
391 */
392