• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Return the next data element from the section after possibly converting it.
2    Copyright (C) 1998-2005, 2006, 2007, 2015, 2016 Red Hat, Inc.
3    Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
4    This file is part of elfutils.
5    Written by Ulrich Drepper <drepper@redhat.com>, 1998.
6 
7    This file is free software; you can redistribute it and/or modify
8    it under the terms of either
9 
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at
12        your option) any later version
13 
14    or
15 
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at
18        your option) any later version
19 
20    or both in parallel, as here.
21 
22    elfutils is distributed in the hope that it will be useful, but
23    WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26 
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see <http://www.gnu.org/licenses/>.  */
30 
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #include <errno.h>
36 #include <stddef.h>
37 #include <string.h>
38 
39 #include "libelfP.h"
40 #include "common.h"
41 #include "elf-knowledge.h"
42 
43 
44 #define TYPEIDX(Sh_Type) \
45   (Sh_Type >= SHT_NULL && Sh_Type < SHT_NUM				      \
46    ? Sh_Type								      \
47    : (Sh_Type >= SHT_GNU_HASH && Sh_Type <= SHT_HISUNW			      \
48       ? SHT_NUM + Sh_Type - SHT_GNU_HASH				      \
49       : 0))
50 
51 /* Associate section types with libelf types.  */
52 static const Elf_Type shtype_map[TYPEIDX (SHT_HISUNW) + 1] =
53   {
54       [SHT_SYMTAB] = ELF_T_SYM,
55       [SHT_RELA] = ELF_T_RELA,
56       [SHT_HASH] = ELF_T_WORD,
57       [SHT_DYNAMIC] = ELF_T_DYN,
58       [SHT_REL] = ELF_T_REL,
59       [SHT_DYNSYM] = ELF_T_SYM,
60       [SHT_INIT_ARRAY] = ELF_T_ADDR,
61       [SHT_FINI_ARRAY] = ELF_T_ADDR,
62       [SHT_PREINIT_ARRAY] = ELF_T_ADDR,
63       [SHT_GROUP] = ELF_T_WORD,
64       [SHT_SYMTAB_SHNDX] = ELF_T_WORD,
65       [SHT_NOTE] = ELF_T_NHDR, /* Need alignment to guess ELF_T_NHDR8.  */
66       [TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF,
67       [TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED,
68       [TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF,
69       [TYPEIDX (SHT_SUNW_syminfo)] = ELF_T_SYMINFO,
70       [TYPEIDX (SHT_SUNW_move)] = ELF_T_MOVE,
71       [TYPEIDX (SHT_GNU_LIBLIST)] = ELF_T_LIB,
72       [TYPEIDX (SHT_GNU_HASH)] = ELF_T_GNUHASH,
73   };
74 
75 /* Associate libelf types with their internal alignment requirements.  */
76 const uint_fast8_t __libelf_type_aligns[ELFCLASSNUM - 1][ELF_T_NUM] =
77   {
78 # define TYPE_ALIGNS(Bits)						      \
79       [ELF_T_ADDR] = __alignof__ (ElfW2(Bits,Addr)),			      \
80       [ELF_T_EHDR] = __alignof__ (ElfW2(Bits,Ehdr)),			      \
81       [ELF_T_HALF] = __alignof__ (ElfW2(Bits,Half)),			      \
82       [ELF_T_OFF] = __alignof__ (ElfW2(Bits,Off)),			      \
83       [ELF_T_PHDR] = __alignof__ (ElfW2(Bits,Phdr)),			      \
84       [ELF_T_SHDR] = __alignof__ (ElfW2(Bits,Shdr)),			      \
85       [ELF_T_SWORD] = __alignof__ (ElfW2(Bits,Sword)),			      \
86       [ELF_T_WORD] = __alignof__ (ElfW2(Bits,Word)),			      \
87       [ELF_T_XWORD] = __alignof__ (ElfW2(Bits,Xword)),			      \
88       [ELF_T_SXWORD] = __alignof__ (ElfW2(Bits,Sxword)),		      \
89       [ELF_T_SYM] = __alignof__ (ElfW2(Bits,Sym)),			      \
90       [ELF_T_SYMINFO] = __alignof__ (ElfW2(Bits,Syminfo)),		      \
91       [ELF_T_REL] = __alignof__ (ElfW2(Bits,Rel)),			      \
92       [ELF_T_RELA] = __alignof__ (ElfW2(Bits,Rela)),			      \
93       [ELF_T_DYN] = __alignof__ (ElfW2(Bits,Dyn)),			      \
94       [ELF_T_VDEF] = __alignof__ (ElfW2(Bits,Verdef)),			      \
95       [ELF_T_VDAUX] = __alignof__ (ElfW2(Bits,Verdaux)),		      \
96       [ELF_T_VNEED] = __alignof__ (ElfW2(Bits,Verneed)),		      \
97       [ELF_T_VNAUX] = __alignof__ (ElfW2(Bits,Vernaux)),		      \
98       [ELF_T_MOVE] = __alignof__ (ElfW2(Bits,Move)),			      \
99       [ELF_T_LIB] = __alignof__ (ElfW2(Bits,Lib)),			      \
100       [ELF_T_NHDR] = __alignof__ (ElfW2(Bits,Nhdr)),			      \
101       [ELF_T_AUXV] = __alignof__ (ElfW2(Bits,auxv_t)),			      \
102       [ELF_T_CHDR] = __alignof__ (ElfW2(Bits,Chdr)),			      \
103       [ELF_T_NHDR8] = 8 /* Special case for GNU Property note.  */
104     [ELFCLASS32 - 1] =  {
105 	TYPE_ALIGNS (32),
106 	[ELF_T_GNUHASH] = __alignof__ (Elf32_Word),
107     },
108     [ELFCLASS64 - 1] = {
109 	TYPE_ALIGNS (64),
110 	[ELF_T_GNUHASH] = __alignof__ (Elf64_Xword),
111     },
112 # undef TYPE_ALIGNS
113   };
114 
115 
116 Elf_Type
117 internal_function
__libelf_data_type(GElf_Ehdr * ehdr,int sh_type,GElf_Xword align)118 __libelf_data_type (GElf_Ehdr *ehdr, int sh_type, GElf_Xword align)
119 {
120   /* Some broken ELF ABI for 64-bit machines use the wrong hash table
121      entry size.  See elf-knowledge.h for more information.  */
122   if (sh_type == SHT_HASH && ehdr->e_ident[EI_CLASS] == ELFCLASS64)
123     {
124       return (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
125     }
126   else
127     {
128       Elf_Type t = shtype_map[TYPEIDX (sh_type)];
129       /* Special case for GNU Property notes.  */
130       if (t == ELF_T_NHDR && align == 8)
131 	t = ELF_T_NHDR8;
132       return t;
133     }
134 }
135 
136 /* Convert the data in the current section.  */
137 static void
convert_data(Elf_Scn * scn,int eclass,int data,size_t size,Elf_Type type)138 convert_data (Elf_Scn *scn, int eclass,
139 	      int data, size_t size, Elf_Type type)
140 {
141   const size_t align = __libelf_type_align (eclass, type);
142 
143   /* Do we need to convert the data and/or adjust for alignment?  */
144   if (data == MY_ELFDATA || type == ELF_T_BYTE)
145     {
146       if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
147 	/* No need to copy, we can use the raw data.  */
148 	scn->data_base = scn->rawdata_base;
149       else
150 	{
151 	  scn->data_base = malloc (size);
152 	  if (scn->data_base == NULL)
153 	    {
154 	      __libelf_seterrno (ELF_E_NOMEM);
155 	      return;
156 	    }
157 
158 	  /* The copy will be appropriately aligned for direct access.  */
159 	  memcpy (scn->data_base, scn->rawdata_base, size);
160 	}
161     }
162   else
163     {
164       xfct_t fp;
165 
166       scn->data_base = malloc (size);
167       if (scn->data_base == NULL)
168 	{
169 	  __libelf_seterrno (ELF_E_NOMEM);
170 	  return;
171 	}
172 
173       /* Make sure the source is correctly aligned for the conversion
174 	 function to directly access the data elements.  */
175       char *rawdata_source;
176       if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
177 	rawdata_source = scn->rawdata_base;
178       else
179 	{
180 	  rawdata_source = malloc (size);
181 	  if (rawdata_source == NULL)
182 	    {
183 	      __libelf_seterrno (ELF_E_NOMEM);
184 	      return;
185 	    }
186 
187 	  /* The copy will be appropriately aligned for direct access.  */
188 	  memcpy (rawdata_source, scn->rawdata_base, size);
189 	}
190 
191       /* Get the conversion function.  */
192       fp = __elf_xfctstom[eclass - 1][type];
193 
194       fp (scn->data_base, rawdata_source, size, 0);
195 
196       if (rawdata_source != scn->rawdata_base)
197 	free (rawdata_source);
198     }
199 
200   scn->data_list.data.d.d_buf = scn->data_base;
201   scn->data_list.data.d.d_size = size;
202   scn->data_list.data.d.d_type = type;
203   scn->data_list.data.d.d_off = scn->rawdata.d.d_off;
204   scn->data_list.data.d.d_align = scn->rawdata.d.d_align;
205   scn->data_list.data.d.d_version = scn->rawdata.d.d_version;
206 
207   scn->data_list.data.s = scn;
208 }
209 
210 
211 /* Store the information for the raw data in the `rawdata' element.  */
212 int
213 internal_function
__libelf_set_rawdata_wrlock(Elf_Scn * scn)214 __libelf_set_rawdata_wrlock (Elf_Scn *scn)
215 {
216   Elf64_Off offset;
217   Elf64_Xword size;
218   Elf64_Xword align;
219   Elf64_Xword flags;
220   int type;
221   Elf *elf = scn->elf;
222 
223   if (elf->class == ELFCLASS32)
224     {
225       Elf32_Shdr *shdr
226 	= scn->shdr.e32 ?: __elf32_getshdr_wrlock (scn);
227 
228       if (shdr == NULL)
229 	/* Something went terribly wrong.  */
230 	return 1;
231 
232       offset = shdr->sh_offset;
233       size = shdr->sh_size;
234       type = shdr->sh_type;
235       align = shdr->sh_addralign;
236       flags = shdr->sh_flags;
237     }
238   else
239     {
240       Elf64_Shdr *shdr
241 	= scn->shdr.e64 ?: __elf64_getshdr_wrlock (scn);
242 
243       if (shdr == NULL)
244 	/* Something went terribly wrong.  */
245 	return 1;
246 
247       offset = shdr->sh_offset;
248       size = shdr->sh_size;
249       type = shdr->sh_type;
250       align = shdr->sh_addralign;
251       flags = shdr->sh_flags;
252     }
253 
254   /* If the section has no data (for whatever reason), leave the `d_buf'
255      pointer NULL.  */
256   if (size != 0 && type != SHT_NOBITS)
257     {
258       /* First a test whether the section is valid at all.  */
259       size_t entsize;
260 
261       /* Compressed data has a header, but then compressed data.
262 	 Make sure to set the alignment of the header explicitly,
263 	 don't trust the file alignment for the section, it is
264 	 often wrong.  */
265       if ((flags & SHF_COMPRESSED) != 0)
266 	{
267 	  entsize = 1;
268 	  align = __libelf_type_align (elf->class, ELF_T_CHDR);
269 	}
270       else if (type == SHT_HASH)
271 	{
272 	  GElf_Ehdr ehdr_mem;
273 	  GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
274 	  if (unlikely (ehdr == NULL))
275 	    return 1;
276 	  entsize = SH_ENTSIZE_HASH (ehdr);
277 	}
278       else
279 	{
280 	  Elf_Type t = shtype_map[TYPEIDX (type)];
281 	  if (t == ELF_T_NHDR && align == 8)
282 	    t = ELF_T_NHDR8;
283 	  if (t == ELF_T_VDEF || t == ELF_T_NHDR || t == ELF_T_NHDR8
284 	      || (t == ELF_T_GNUHASH && elf->class == ELFCLASS64))
285 	    entsize = 1;
286 	  else
287 	    entsize = __libelf_type_sizes[elf->class - 1][t];
288 	}
289 
290       /* We assume it is an array of bytes if it is none of the structured
291 	 sections we know of.  */
292       if (entsize == 0)
293 	entsize = 1;
294 
295       if (unlikely (size % entsize != 0))
296 	{
297 	  __libelf_seterrno (ELF_E_INVALID_DATA);
298 	  return 1;
299 	}
300 
301       /* We can use the mapped or loaded data if available.  */
302       if (elf->map_address != NULL)
303 	{
304 	  /* First see whether the information in the section header is
305 	     valid and it does not ask for too much.  Check for unsigned
306 	     overflow.  */
307 	  if (unlikely (offset > elf->maximum_size
308 	      || elf->maximum_size - offset < size))
309 	    {
310 	      /* Something is wrong.  */
311 	      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
312 	      return 1;
313 	    }
314 
315 	  scn->rawdata_base = scn->rawdata.d.d_buf
316 	    = (char *) elf->map_address + elf->start_offset + offset;
317 	}
318       else if (likely (elf->fildes != -1))
319 	{
320 	  /* First see whether the information in the section header is
321 	     valid and it does not ask for too much.  Check for unsigned
322 	     overflow.  */
323 	  if (unlikely (offset > elf->maximum_size
324 			|| elf->maximum_size - offset < size))
325 	    {
326 	      /* Something is wrong.  */
327 	      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
328 	      return 1;
329 	    }
330 
331 	  /* We have to read the data from the file.  Allocate the needed
332 	     memory.  */
333 	  scn->rawdata_base = scn->rawdata.d.d_buf = malloc (size);
334 	  if (scn->rawdata.d.d_buf == NULL)
335 	    {
336 	      __libelf_seterrno (ELF_E_NOMEM);
337 	      return 1;
338 	    }
339 
340 	  ssize_t n = pread_retry (elf->fildes, scn->rawdata.d.d_buf, size,
341 				   elf->start_offset + offset);
342 	  if (unlikely ((size_t) n != size))
343 	    {
344 	      /* Cannot read the data.  */
345 	      free (scn->rawdata.d.d_buf);
346 	      scn->rawdata_base = scn->rawdata.d.d_buf = NULL;
347 	      __libelf_seterrno (ELF_E_READ_ERROR);
348 	      return 1;
349 	    }
350 	}
351       else
352 	{
353 	  /* The file descriptor is already closed, we cannot get the data
354 	     anymore.  */
355 	  __libelf_seterrno (ELF_E_FD_DISABLED);
356 	  return 1;
357 	}
358     }
359 
360   scn->rawdata.d.d_size = size;
361 
362   /* Compressed data always has type ELF_T_CHDR regardless of the
363      section type.  */
364   if ((flags & SHF_COMPRESSED) != 0)
365     scn->rawdata.d.d_type = ELF_T_CHDR;
366   else
367     {
368       GElf_Ehdr ehdr_mem;
369       GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
370       if (unlikely (ehdr == NULL))
371 	return 1;
372       scn->rawdata.d.d_type = __libelf_data_type (ehdr, type, align);
373     }
374   scn->rawdata.d.d_off = 0;
375 
376   /* Make sure the alignment makes sense.  d_align should be aligned both
377      in the section (trivially true since d_off is zero) and in the file.
378      Unfortunately we cannot be too strict because there are ELF files
379      out there that fail this requirement.  We will try to fix those up
380      in elf_update when writing out the image.  But for very large
381      alignment values this can bloat the image considerably.  So here
382      just check and clamp the alignment value to not be bigger than the
383      actual offset of the data in the file.  Given that there is always
384      at least an ehdr this will only trigger for alignment values > 64
385      which should be uncommon.  */
386   align = align ?: 1;
387   if (type != SHT_NOBITS && align > offset)
388     {
389       /* Align the offset to the next power of two. Uses algorithm from
390          https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
391       align = offset - 1;
392       align |= align >> 1;
393       align |= align >> 2;
394       align |= align >> 4;
395       align |= align >> 8;
396       align |= align >> 16;
397       align |= align >> 32;
398       align++;
399     }
400   scn->rawdata.d.d_align = align;
401   if (elf->class == ELFCLASS32
402       || (offsetof (struct Elf, state.elf32.ehdr)
403 	  == offsetof (struct Elf, state.elf64.ehdr)))
404     scn->rawdata.d.d_version =
405       elf->state.elf32.ehdr->e_ident[EI_VERSION];
406   else
407     scn->rawdata.d.d_version =
408       elf->state.elf64.ehdr->e_ident[EI_VERSION];
409 
410   scn->rawdata.s = scn;
411 
412   scn->data_read = 1;
413 
414   /* We actually read data from the file.  At least we tried.  */
415   scn->flags |= ELF_F_FILEDATA;
416 
417   return 0;
418 }
419 
420 int
421 internal_function
__libelf_set_rawdata(Elf_Scn * scn)422 __libelf_set_rawdata (Elf_Scn *scn)
423 {
424   int result;
425 
426   if (scn == NULL)
427     return 1;
428 
429   rwlock_wrlock (scn->elf->lock);
430   result = __libelf_set_rawdata_wrlock (scn);
431   rwlock_unlock (scn->elf->lock);
432 
433   return result;
434 }
435 
436 void
437 internal_function
__libelf_set_data_list_rdlock(Elf_Scn * scn,int wrlocked)438 __libelf_set_data_list_rdlock (Elf_Scn *scn, int wrlocked)
439 {
440   if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0)
441     {
442       Elf *elf = scn->elf;
443 
444       /* Upgrade the lock to a write lock if necessary and check
445 	 nobody else already did the work.  */
446       if (!wrlocked)
447 	{
448 	  rwlock_unlock (elf->lock);
449 	  rwlock_wrlock (elf->lock);
450 	  if (scn->data_list_rear != NULL)
451 	    return;
452 	}
453 
454       /* Convert according to the version and the type.   */
455       convert_data (scn, elf->class,
456 		    (elf->class == ELFCLASS32
457 		     || (offsetof (struct Elf, state.elf32.ehdr)
458 			 == offsetof (struct Elf, state.elf64.ehdr))
459 		     ? elf->state.elf32.ehdr->e_ident[EI_DATA]
460 		     : elf->state.elf64.ehdr->e_ident[EI_DATA]),
461 		    scn->rawdata.d.d_size, scn->rawdata.d.d_type);
462     }
463   else
464     {
465       /* This is an empty or NOBITS section.  There is no buffer but
466 	 the size information etc is important.  */
467       scn->data_list.data.d = scn->rawdata.d;
468       scn->data_list.data.s = scn;
469     }
470 
471   scn->data_list_rear = &scn->data_list;
472 }
473 
474 Elf_Data *
475 internal_function
__elf_getdata_rdlock(Elf_Scn * scn,Elf_Data * data)476 __elf_getdata_rdlock (Elf_Scn *scn, Elf_Data *data)
477 {
478   Elf_Data *result = NULL;
479   Elf *elf;
480   int locked = 0;
481 
482   if (scn == NULL)
483     return NULL;
484 
485   if (unlikely (scn->elf->kind != ELF_K_ELF))
486     {
487       __libelf_seterrno (ELF_E_INVALID_HANDLE);
488       return NULL;
489     }
490 
491   /* We will need this multiple times later on.  */
492   elf = scn->elf;
493 
494   /* If `data' is not NULL this means we are not addressing the initial
495      data in the file.  But this also means this data is already read
496      (since otherwise it is not possible to have a valid `data' pointer)
497      and all the data structures are initialized as well.  In this case
498      we can simply walk the list of data records.  */
499   if (data != NULL)
500     {
501       Elf_Data_List *runp;
502 
503       /* It is not possible that if DATA is not NULL the first entry is
504 	 returned.  But this also means that there must be a first data
505 	 entry.  */
506       if (scn->data_list_rear == NULL
507 	  /* The section the reference data is for must match the section
508 	     parameter.  */
509 	  || unlikely (((Elf_Data_Scn *) data)->s != scn))
510 	{
511 	  __libelf_seterrno (ELF_E_DATA_MISMATCH);
512 	  goto out;
513 	}
514 
515       /* We start searching with the first entry.  */
516       runp = &scn->data_list;
517 
518       while (1)
519 	{
520 	  /* If `data' does not match any known record punt.  */
521 	  if (runp == NULL)
522 	    {
523 	      __libelf_seterrno (ELF_E_DATA_MISMATCH);
524 	      goto out;
525 	    }
526 
527 	  if (&runp->data.d == data)
528 	    /* Found the entry.  */
529 	    break;
530 
531 	  runp = runp->next;
532 	}
533 
534       /* Return the data for the next data record.  */
535       result = runp->next ? &runp->next->data.d : NULL;
536       goto out;
537     }
538 
539   /* If the data for this section was not yet initialized do it now.  */
540   if (scn->data_read == 0)
541     {
542       /* We cannot acquire a write lock while we are holding a read
543          lock.  Therefore give up the read lock and then get the write
544          lock.  But this means that the data could meanwhile be
545          modified, therefore start the tests again.  */
546       rwlock_unlock (elf->lock);
547       rwlock_wrlock (elf->lock);
548       locked = 1;
549 
550       /* Read the data from the file.  There is always a file (or
551 	 memory region) associated with this descriptor since
552 	 otherwise the `data_read' flag would be set.  */
553       if (scn->data_read == 0 && __libelf_set_rawdata_wrlock (scn) != 0)
554 	/* Something went wrong.  The error value is already set.  */
555 	goto out;
556     }
557 
558   /* At this point we know the raw data is available.  But it might be
559      empty in case the section has size zero (for whatever reason).
560      Now create the converted data in case this is necessary.  */
561   if (scn->data_list_rear == NULL)
562     __libelf_set_data_list_rdlock (scn, locked);
563 
564   /* Return the first data element in the list.  */
565   result = &scn->data_list.data.d;
566 
567  out:
568   return result;
569 }
570 
571 Elf_Data *
elf_getdata(Elf_Scn * scn,Elf_Data * data)572 elf_getdata (Elf_Scn *scn, Elf_Data *data)
573 {
574   Elf_Data *result;
575 
576   if (scn == NULL)
577     return NULL;
578 
579   rwlock_rdlock (scn->elf->lock);
580   result = __elf_getdata_rdlock (scn, data);
581   rwlock_unlock (scn->elf->lock);
582 
583   return result;
584 }
585 INTDEF(elf_getdata)
586