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