LCOV - code coverage report
Current view: top level - libelf - elf32_updatenull.c (source / functions) Hit Total Coverage
Test: elfutils-0.177 Lines: 122 173 70.5 %
Date: 2019-08-14 14:28:26 Functions: 2 4 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Update data structures for changes.
       2             :    Copyright (C) 2000-2010, 2015, 2016 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             :    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
       5             : 
       6             :    This file is free software; you can redistribute it and/or modify
       7             :    it under the terms of either
       8             : 
       9             :      * the GNU Lesser General Public License as published by the Free
      10             :        Software Foundation; either version 3 of the License, or (at
      11             :        your option) any later version
      12             : 
      13             :    or
      14             : 
      15             :      * the GNU General Public License as published by the Free
      16             :        Software Foundation; either version 2 of the License, or (at
      17             :        your option) any later version
      18             : 
      19             :    or both in parallel, as here.
      20             : 
      21             :    elfutils is distributed in the hope that it will be useful, but
      22             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      24             :    General Public License for more details.
      25             : 
      26             :    You should have received copies of the GNU General Public License and
      27             :    the GNU Lesser General Public License along with this program.  If
      28             :    not, see <http://www.gnu.org/licenses/>.  */
      29             : 
      30             : #ifdef HAVE_CONFIG_H
      31             : # include <config.h>
      32             : #endif
      33             : 
      34             : #include <assert.h>
      35             : #include <endian.h>
      36             : #include <libelf.h>
      37             : #include <stdbool.h>
      38             : #include <string.h>
      39             : 
      40             : #include <system.h>
      41             : #include "libelfP.h"
      42             : #include "elf-knowledge.h"
      43             : 
      44             : #ifndef LIBELFBITS
      45             : # define LIBELFBITS 32
      46             : #endif
      47             : 
      48             : /* Some fields contain 32/64 sizes.  We cannot use Elf32/64_Word for those,
      49             :    since those are both 32bits.  Elf32/64_Xword is always 64bits.  */
      50             : #define Elf32_SizeWord Elf32_Word
      51             : #define Elf64_SizeWord Elf64_Xword
      52             : 
      53             : 
      54             : static int
      55           0 : ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
      56             :                                size_t shnum, int *change_bop)
      57             : {
      58             :   /* Always write the magic bytes.  */
      59           0 :   if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
      60             :     {
      61           0 :       memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
      62           0 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
      63             :     }
      64             : 
      65             :   /* Always set the file class.  */
      66           0 :   update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
      67             :                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
      68             : 
      69             :   /* Set the data encoding if necessary.  */
      70           0 :   if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
      71             :     {
      72           0 :       ehdr->e_ident[EI_DATA] =
      73             :         BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
      74           0 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
      75             :     }
      76           0 :   else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
      77             :     {
      78           0 :       __libelf_seterrno (ELF_E_DATA_ENCODING);
      79           0 :       return 1;
      80             :     }
      81             :   else
      82           0 :     *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
      83             :                     && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
      84           0 :                    || (BYTE_ORDER == BIG_ENDIAN
      85             :                        && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
      86             : 
      87             :   /* Unconditionally overwrite the ELF version.  */
      88           0 :   update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
      89             :                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
      90             : 
      91           0 :   if (unlikely (ehdr->e_version == EV_NONE))
      92             :     {
      93           0 :       ehdr->e_version = EV_CURRENT;
      94           0 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
      95             :     }
      96           0 :   else if (unlikely (ehdr->e_version != EV_CURRENT))
      97             :     {
      98           0 :       __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
      99           0 :       return 1;
     100             :     }
     101             : 
     102           0 :   if (unlikely (shnum >= SHN_LORESERVE))
     103             :     {
     104           0 :       update_if_changed (ehdr->e_shnum, 0,
     105             :                          elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
     106             :     }
     107             :   else
     108           0 :     update_if_changed (ehdr->e_shnum, shnum,
     109             :                        elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
     110             : 
     111           0 :   if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
     112             :     {
     113           0 :       ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
     114           0 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
     115             :     }
     116             : 
     117             :   /* If phnum is zero make sure e_phoff is also zero and not some random
     118             :      value.  That would cause trouble in update_file.  */
     119           0 :   if (ehdr->e_phnum == 0 && ehdr->e_phoff != 0)
     120             :     {
     121           0 :       ehdr->e_phoff = 0;
     122           0 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
     123             :     }
     124             : 
     125             :   return 0;
     126             : }
     127             : 
     128             : 
     129             : int64_t
     130             : internal_function
     131         595 : __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
     132             : {
     133         595 :   ElfW2(LIBELFBITS,Ehdr) *ehdr;
     134         595 :   int changed = 0;
     135         595 :   int ehdr_flags = 0;
     136             : 
     137         595 :   ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
     138             : 
     139             :   /* Set the default values.  */
     140         595 :   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
     141             :     return -1;
     142             : 
     143             :   /* At least the ELF header is there.  */
     144         595 :   ElfW2(LIBELFBITS,SizeWord) size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
     145             : 
     146             :   /* Set the program header position.  */
     147         595 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
     148         292 :     (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
     149         595 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
     150             :     {
     151         334 :       size_t phnum;
     152         334 :       if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
     153           0 :         return -1;
     154             : 
     155         334 :       if (elf->flags & ELF_F_LAYOUT)
     156             :         {
     157             :           /* The user is supposed to fill out e_phoff.  Use it and
     158             :              e_phnum to determine the maximum extend.  */
     159         278 :           size = MAX (size,
     160             :                       ehdr->e_phoff
     161             :                       + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
     162             :         }
     163             :       else
     164             :         {
     165          56 :           update_if_changed (ehdr->e_phoff,
     166             :                              elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
     167             :                              ehdr_flags);
     168             : 
     169             :           /* We need no alignment here.  */
     170          56 :           size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum);
     171             :         }
     172             :     }
     173             : 
     174         595 :   if (shnum > 0)
     175             :     {
     176         580 :       struct Elf_Scn *scn1 = NULL;
     177         580 :       Elf_ScnList *list;
     178         580 :       bool first = true;
     179             : 
     180         580 :       assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
     181             : 
     182         580 :       if (shnum >= SHN_LORESERVE)
     183             :         {
     184             :           /* We have to  fill in the number of sections in the header
     185             :              of the zeroth section.  */
     186          41 :           Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
     187             : 
     188          41 :           update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
     189             :                              shnum, scn0->shdr_flags);
     190             :         }
     191             : 
     192             :       /* Go over all sections and find out how large they are.  */
     193         580 :       list = &elf->state.ELFW(elf,LIBELFBITS).scns;
     194             : 
     195             :       /* Find the first section. */
     196         580 :       if (list->cnt > 1)
     197         576 :         scn1 = &list->data[1];
     198           4 :       else if (list->next != NULL)
     199           4 :         scn1 = &list->next->data[0];
     200             : 
     201             :       /* Load the section headers if necessary.  This loads the
     202             :          headers for all sections.  */
     203         580 :       if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL)
     204          19 :         (void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1);
     205             : 
     206        1532 :       do
     207             :         {
     208     3226234 :           for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
     209             :             {
     210     3224702 :               Elf_Scn *scn = &list->data[cnt];
     211     3224702 :               ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
     212     3224702 :               int64_t offset = 0;
     213             : 
     214     3224702 :               assert (shdr != NULL);
     215     3224702 :               ElfW2(LIBELFBITS,SizeWord) sh_entsize = shdr->sh_entsize;
     216     3224702 :               ElfW2(LIBELFBITS,SizeWord) sh_align = shdr->sh_addralign ?: 1;
     217     3224702 :               if (unlikely (! powerof2 (sh_align)))
     218             :                 {
     219           0 :                   __libelf_seterrno (ELF_E_INVALID_ALIGN);
     220           0 :                   return -1;
     221             :                 }
     222             : 
     223             :               /* Set the sh_entsize value if we can reliably detect it.  */
     224     3224702 :               switch (shdr->sh_type)
     225             :                 {
     226         453 :                 case SHT_SYMTAB:
     227         453 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
     228         453 :                   break;
     229        1023 :                 case SHT_RELA:
     230        1023 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
     231        1023 :                   break;
     232       22026 :                 case SHT_GROUP:
     233             :                   /* Only relocatable files can contain section groups.  */
     234       22026 :                   if (ehdr->e_type != ET_REL)
     235             :                     {
     236           0 :                       __libelf_seterrno (ELF_E_GROUP_NOT_REL);
     237           0 :                       return -1;
     238             :                     }
     239       22028 :                   FALLTHROUGH;
     240             :                 case SHT_SYMTAB_SHNDX:
     241       22028 :                   sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
     242       22028 :                   break;
     243         115 :                 case SHT_HASH:
     244         115 :                   sh_entsize = SH_ENTSIZE_HASH (ehdr);
     245             :                   break;
     246         200 :                 case SHT_DYNAMIC:
     247         200 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
     248         200 :                   break;
     249         194 :                 case SHT_REL:
     250         194 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
     251         194 :                   break;
     252         198 :                 case SHT_DYNSYM:
     253         198 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
     254         198 :                   break;
     255           0 :                 case SHT_SUNW_move:
     256           0 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
     257           0 :                   break;
     258           0 :                 case SHT_SUNW_syminfo:
     259           0 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
     260           0 :                   break;
     261             :                 default:
     262             :                   break;
     263             :                 }
     264             : 
     265             :               /* If the section header contained the wrong entry size
     266             :                  correct it and mark the header as modified.  */
     267     3224702 :               update_if_changed (shdr->sh_entsize, sh_entsize,
     268             :                                  scn->shdr_flags);
     269             : 
     270     3224702 :               if (scn->data_read == 0
     271      525588 :                   && __libelf_set_rawdata_wrlock (scn) != 0)
     272             :                 /* Something went wrong.  The error value is already set.  */
     273             :                 return -1;
     274             : 
     275             :               /* Iterate over all data blocks.  */
     276     3224702 :               if (list->data[cnt].data_list_rear != NULL)
     277             :                 {
     278     2699108 :                   Elf_Data_List *dl = &scn->data_list;
     279             : 
     280     5398366 :                   while (dl != NULL)
     281             :                     {
     282     2699258 :                       Elf_Data *data = &dl->data.d;
     283     2699258 :                       if (dl == &scn->data_list && data->d_buf == NULL
     284       67511 :                           && scn->rawdata.d.d_buf != NULL)
     285           0 :                         data = &scn->rawdata.d;
     286             : 
     287     2699258 :                       if (unlikely (data->d_version != EV_CURRENT))
     288             :                         {
     289           0 :                           __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
     290           0 :                           return -1;
     291             :                         }
     292             : 
     293     2699258 :                       if (unlikely (! powerof2 (data->d_align)))
     294             :                         {
     295           0 :                           __libelf_seterrno (ELF_E_INVALID_ALIGN);
     296           0 :                           return -1;
     297             :                         }
     298             : 
     299     2699258 :                       sh_align = MAX (sh_align, data->d_align);
     300             : 
     301     2699258 :                       if (elf->flags & ELF_F_LAYOUT)
     302             :                         {
     303             :                           /* The user specified the offset and the size.
     304             :                              All we have to do is check whether this block
     305             :                              fits in the size specified for the section.  */
     306      662040 :                           if (unlikely ((ElfW2(LIBELFBITS,SizeWord))
     307             :                                         (data->d_off + data->d_size)
     308             :                                         > shdr->sh_size))
     309             :                             {
     310           0 :                               __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
     311           0 :                               return -1;
     312             :                             }
     313             :                         }
     314             :                       else
     315             :                         {
     316             :                           /* Determine the padding.  */
     317     4074436 :                           offset = ((offset + data->d_align - 1)
     318     2037218 :                                     & ~(data->d_align - 1));
     319             : 
     320     2037218 :                           update_if_changed (data->d_off, offset, changed);
     321             : 
     322     2037218 :                           offset += data->d_size;
     323             :                         }
     324             : 
     325             :                       /* Next data block.  */
     326     2699258 :                       dl = dl->next;
     327             :                     }
     328             :                 }
     329             :               else
     330             :                 /* Get the size of the section from the raw data.  If
     331             :                    none is available the value is zero.  */
     332      525594 :                 offset += scn->rawdata.d.d_size;
     333             : 
     334     3224702 :               if (elf->flags & ELF_F_LAYOUT)
     335             :                 {
     336      662451 :                   size = MAX (size,
     337             :                               (shdr->sh_type != SHT_NOBITS
     338             :                                ? shdr->sh_offset + shdr->sh_size : 0));
     339             : 
     340             :                   /* The alignment must be a power of two.  This is a
     341             :                      requirement from the ELF specification.  Additionally
     342             :                      we test for the alignment of the section being large
     343             :                      enough for the largest alignment required by a data
     344             :                      block.  */
     345      662451 :                   if (unlikely (! powerof2 (shdr->sh_addralign))
     346      662453 :                       || unlikely ((shdr->sh_addralign ?: 1) < sh_align))
     347             :                     {
     348           0 :                       __libelf_seterrno (ELF_E_INVALID_ALIGN);
     349           0 :                       return -1;
     350             :                     }
     351             :                 }
     352             :               else
     353             :                 {
     354             :                   /* How much alignment do we need for this section.  */
     355     2562251 :                   update_if_changed (shdr->sh_addralign, sh_align,
     356             :                                      scn->shdr_flags);
     357             : 
     358     2562251 :                   size = (size + sh_align - 1) & ~(sh_align - 1);
     359     2562251 :                   int offset_changed = 0;
     360     2562251 :                   update_if_changed (shdr->sh_offset, size, offset_changed);
     361     1512182 :                   changed |= offset_changed;
     362             : 
     363     1512182 :                   if (offset_changed && scn->data_list_rear == NULL)
     364             :                     {
     365             :                       /* The position of the section in the file
     366             :                          changed.  Create the section data list.  */
     367         175 :                       if (__elf_getdata_rdlock (scn, NULL) == NULL)
     368             :                         return -1;
     369             :                     }
     370             : 
     371             :                   /* See whether the section size is correct.  */
     372     2562251 :                   int size_changed = 0;
     373     2562251 :                   update_if_changed (shdr->sh_size,
     374             :                                      (ElfW2(LIBELFBITS,SizeWord)) offset,
     375             :                                      size_changed);
     376     2562251 :                   changed |= size_changed;
     377             : 
     378     2562251 :                   if (shdr->sh_type != SHT_NOBITS)
     379     2495356 :                     size += offset;
     380             : 
     381     2562251 :                   scn->shdr_flags |= (offset_changed | size_changed);
     382     2562251 :                   scn->flags |= changed;
     383             :                 }
     384             : 
     385             :               /* Check that the section size is actually a multiple of
     386             :                  the entry size.  */
     387     3224702 :               if (shdr->sh_entsize != 0 && shdr->sh_entsize != 1
     388       25558 :                   && (elf->flags & ELF_F_PERMISSIVE) == 0)
     389             :                 {
     390             :                   /* For compressed sections check the uncompressed size.  */
     391       25558 :                   ElfW2(LIBELFBITS,SizeWord) sh_size;
     392       25558 :                   if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
     393       25547 :                     sh_size = shdr->sh_size;
     394             :                   else
     395             :                     {
     396          11 :                       ElfW2(LIBELFBITS,Chdr) *chdr;
     397          11 :                       chdr = elfw2(LIBELFBITS,getchdr) (scn);
     398          11 :                       if (unlikely (chdr == NULL))
     399             :                         return -1;
     400          11 :                       sh_size = chdr->ch_size;
     401             :                     }
     402             : 
     403       25558 :                   if (unlikely (sh_size % shdr->sh_entsize != 0))
     404             :                     {
     405           0 :                       __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
     406           0 :                       return -1;
     407             :                     }
     408             :                 }
     409             :             }
     410             : 
     411        1532 :           assert (list->next == NULL || list->cnt == list->max);
     412             : 
     413        1532 :           first = false;
     414             :         }
     415        1532 :       while ((list = list->next) != NULL);
     416             : 
     417             :       /* Store section information.  */
     418         580 :       update_if_changed (ehdr->e_shentsize,
     419             :                          elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), ehdr_flags);
     420         580 :       if (elf->flags & ELF_F_LAYOUT)
     421             :         {
     422             :           /* The user is supposed to fill out e_shoff.  Use it and
     423             :              e_shnum (or sh_size of the dummy, first section header)
     424             :              to determine the maximum extend.  */
     425         297 :           size = MAX (size,
     426             :                       (ehdr->e_shoff
     427             :                        + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
     428             :         }
     429             :       else
     430             :         {
     431             :           /* Align for section header table.
     432             : 
     433             :              Yes, we use `sizeof' and not `__alignof__' since we do not
     434             :              want to be surprised by architectures with less strict
     435             :              alignment rules.  */
     436             : #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
     437         283 :           size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
     438             : 
     439         283 :           update_if_changed (ehdr->e_shoff, size, elf->flags);
     440             : 
     441             :           /* Account for the section header size.  */
     442         283 :           size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
     443             :         }
     444             :     }
     445             : 
     446         595 :   elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
     447             : 
     448         595 :   return size;
     449             : }

Generated by: LCOV version 1.13