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