(root)/
glibc-2.38/
elf/
readelflib.c
       1  /* Copyright (C) 1999-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C 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; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C 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 the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <elf-read-prop.h>
      19  
      20  /* This code is a heavily simplified version of the readelf program
      21     that's part of the current binutils development version.  For architectures
      22     which need to handle both 32bit and 64bit ELF libraries,  this file is
      23     included twice for each arch size.  */
      24  
      25  /* check_ptr checks that a pointer is in the mmaped file and doesn't
      26     point outside it.  */
      27  #undef check_ptr
      28  #define check_ptr(ptr)						\
      29  do								\
      30    {								\
      31      if ((void *)(ptr) < file_contents				\
      32  	|| (void *)(ptr) > (file_contents+file_length))		\
      33        {								\
      34  	error (0, 0, _("file %s is truncated\n"), file_name);	\
      35  	return 1;						\
      36        }								\
      37    }								\
      38   while (0);
      39  
      40  /* Returns 0 if everything is ok, != 0 in case of error.  */
      41  int
      42  process_elf_file (const char *file_name, const char *lib, int *flag,
      43  		  unsigned int *isa_level, char **soname, void *file_contents,
      44  		  size_t file_length)
      45  {
      46    int i;
      47    unsigned int dynamic_addr;
      48    size_t dynamic_size;
      49    char *program_interpreter;
      50  
      51    ElfW(Ehdr) *elf_header;
      52    ElfW(Phdr) *elf_pheader, *segment;
      53    ElfW(Dyn) *dynamic_segment, *dyn_entry;
      54    char *dynamic_strings;
      55  
      56    elf_header = (ElfW(Ehdr) *) file_contents;
      57  
      58    if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
      59      {
      60        if (opt_verbose)
      61  	{
      62  	  if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
      63  	    error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
      64  	  else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
      65  	    error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
      66  	  else
      67  	    error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
      68  	}
      69        return 1;
      70      }
      71  
      72    if (elf_header->e_type != ET_DYN)
      73      {
      74        error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
      75  	     elf_header->e_type);
      76        return 1;
      77      }
      78  
      79    /* Get information from elf program header.  */
      80    elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
      81    check_ptr (elf_pheader);
      82  
      83    /* The library is an elf library.  */
      84    *flag = FLAG_ELF_LIBC6;
      85  
      86    /* The default ISA level is 0.  */
      87    *isa_level = 0;
      88  
      89    dynamic_addr = 0;
      90    dynamic_size = 0;
      91    program_interpreter = NULL;
      92    for (i = 0, segment = elf_pheader;
      93         i < elf_header->e_phnum; i++, segment++)
      94      {
      95        check_ptr (segment);
      96  
      97        switch (segment->p_type)
      98  	{
      99  	case PT_DYNAMIC:
     100  	  if (dynamic_addr)
     101  	    error (0, 0, _("more than one dynamic segment\n"));
     102  
     103  	  dynamic_addr = segment->p_offset;
     104  	  dynamic_size = segment->p_filesz;
     105  	  break;
     106  
     107  	case PT_INTERP:
     108  	  program_interpreter = (char *) (file_contents + segment->p_offset);
     109  	  check_ptr (program_interpreter);
     110  
     111  	case PT_GNU_PROPERTY:
     112  	  /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes
     113  	     in 32-bit objects and to 8 bytes in 64-bit objects.  Skip
     114  	     notes with incorrect alignment.  */
     115  	  if (segment->p_align == (__ELF_NATIVE_CLASS / 8))
     116  	    {
     117  	      const ElfW(Nhdr) *note = (const void *) (file_contents
     118  						       + segment->p_offset);
     119  	      const ElfW(Addr) size = segment->p_filesz;
     120  	      const ElfW(Addr) align = segment->p_align;
     121  
     122  	      const ElfW(Addr) start = (ElfW(Addr)) (uintptr_t) note;
     123  	      unsigned int last_type = 0;
     124  
     125  	      while ((ElfW(Addr)) (uintptr_t) (note + 1) - start < size)
     126  		{
     127  		  /* Find the NT_GNU_PROPERTY_TYPE_0 note.  */
     128  		  if (note->n_namesz == 4
     129  		      && note->n_type == NT_GNU_PROPERTY_TYPE_0
     130  		      && memcmp (note + 1, "GNU", 4) == 0)
     131  		    {
     132  		      /* Check for invalid property.  */
     133  		      if (note->n_descsz < 8
     134  			  || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
     135  			goto done;
     136  
     137  		      /* Start and end of property array.  */
     138  		      unsigned char *ptr = (unsigned char *) (note + 1) + 4;
     139  		      unsigned char *ptr_end = ptr + note->n_descsz;
     140  
     141  		      do
     142  			{
     143  			  unsigned int type = *(unsigned int *) ptr;
     144  			  unsigned int datasz = *(unsigned int *) (ptr + 4);
     145  
     146  			  /* Property type must be in ascending order.  */
     147  			  if (type < last_type)
     148  			    goto done;
     149  
     150  			  ptr += 8;
     151  			  if ((ptr + datasz) > ptr_end)
     152  			    goto done;
     153  
     154  			  last_type = type;
     155  
     156  			  /* Target specific property processing.
     157  			     Return value:
     158  			       false: Continue processing the properties.
     159  			       true : Stop processing the properties.
     160  			   */
     161  			  if (read_gnu_property (isa_level, type,
     162  						 datasz, ptr))
     163  			    goto done;
     164  
     165  			  /* Check the next property item.  */
     166  			  ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
     167  			}
     168  		      while ((ptr_end - ptr) >= 8);
     169  
     170  		      /* Only handle one NT_GNU_PROPERTY_TYPE_0.  */
     171  		      goto done;
     172  		    }
     173  
     174  		  note = ((const void *) note
     175  			  + ELF_NOTE_NEXT_OFFSET (note->n_namesz,
     176  						  note->n_descsz,
     177  						  align));
     178  		}
     179  	    }
     180  done:
     181  	  break;
     182  
     183  	default:
     184  	  break;
     185  	}
     186  
     187      }
     188  
     189    /* Now we can read the dynamic sections.  */
     190    if (dynamic_size == 0)
     191      return 1;
     192  
     193    dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
     194    check_ptr (dynamic_segment);
     195  
     196    /* Find the string table.  */
     197    dynamic_strings = NULL;
     198    for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
     199         ++dyn_entry)
     200      {
     201        check_ptr (dyn_entry);
     202        if (dyn_entry->d_tag == DT_STRTAB)
     203  	{
     204  	  /* Find the file offset of the segment containing the dynamic
     205  	     string table.  */
     206  	  ElfW(Off) loadoff = -1;
     207  	  for (i = 0, segment = elf_pheader;
     208  	       i < elf_header->e_phnum; i++, segment++)
     209  	    {
     210  	      if (segment->p_type == PT_LOAD
     211  		  && dyn_entry->d_un.d_val >= segment->p_vaddr
     212  		  && (dyn_entry->d_un.d_val - segment->p_vaddr
     213  		      < segment->p_filesz))
     214  		{
     215  		  loadoff = segment->p_vaddr - segment->p_offset;
     216  		  break;
     217  		}
     218  	    }
     219  	  if (loadoff == (ElfW(Off)) -1)
     220  	    {
     221  	      /* Very strange. */
     222  	      loadoff = 0;
     223  	    }
     224  
     225  	  dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val
     226  				      - loadoff);
     227  	  check_ptr (dynamic_strings);
     228  	  break;
     229  	}
     230      }
     231  
     232    if (dynamic_strings == NULL)
     233      return 1;
     234  
     235    /* Now read the DT_SONAME entries.  */
     236    for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
     237         ++dyn_entry)
     238      {
     239        if (dyn_entry->d_tag == DT_SONAME)
     240  	{
     241  	  char *name = dynamic_strings + dyn_entry->d_un.d_val;
     242  	  check_ptr (name);
     243            *soname = xstrdup (name);
     244            return 0;
     245  	}
     246      }
     247  
     248    return 0;
     249  }