Home | History | Annotate | Download | only in libelf
      1 /* Update data structures for changes.
      2    Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 2000.
      4 
      5    This program is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation, version 2.
      8 
      9    This program 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
     12    GNU General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License
     15    along with this program; if not, write to the Free Software Foundation,
     16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
     17 
     18 #ifdef HAVE_CONFIG_H
     19 # include <config.h>
     20 #endif
     21 
     22 #include <assert.h>
     23 //#include <endian.h>
     24 #include <libelf.h>
     25 #include <stdbool.h>
     26 #include <string.h>
     27 #include <sys/param.h>
     28 
     29 #include "libelfP.h"
     30 #include "elf-knowledge.h"
     31 
     32 #ifndef LIBELFBITS
     33 # define LIBELFBITS 32
     34 #endif
     35 
     36 
     37 
     38 static int
     39 ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
     40 			       size_t shnum, int *change_bop)
     41 {
     42   /* Always write the magic bytes.  */
     43   if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
     44     {
     45       memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
     46       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
     47     }
     48 
     49   /* Always set the file class.  */
     50   update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
     51 		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
     52 
     53   /* Set the data encoding if necessary.  */
     54   if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
     55     {
     56       ehdr->e_ident[EI_DATA] =
     57 	BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
     58       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
     59     }
     60   else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
     61     {
     62       __libelf_seterrno (ELF_E_DATA_ENCODING);
     63       return 1;
     64     }
     65   else
     66     *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
     67 		    && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
     68 		   || (BYTE_ORDER == BIG_ENDIAN
     69 		       && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
     70 
     71   /* Unconditionally overwrite the ELF version.  */
     72   update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
     73 		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
     74 
     75   if (unlikely (ehdr->e_version == EV_NONE)
     76       || unlikely (ehdr->e_version >= EV_NUM))
     77     {
     78       __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
     79       return 1;
     80     }
     81 
     82   if (unlikely (shnum >= SHN_LORESERVE))
     83     {
     84       update_if_changed (ehdr->e_shnum, 0,
     85 			 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
     86     }
     87   else
     88     update_if_changed (ehdr->e_shnum, shnum,
     89 		       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
     90 
     91   if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
     92     {
     93       ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
     94       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
     95     }
     96 
     97   return 0;
     98 }
     99 
    100 
    101 off_t
    102 internal_function_def
    103 __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
    104 {
    105   ElfW2(LIBELFBITS,Ehdr) *ehdr = INTUSE(elfw2(LIBELFBITS,getehdr)) (elf);
    106   int changed = 0;
    107   int ehdr_flags = 0;
    108   off_t size;
    109 
    110   /* Set the default values.  */
    111   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
    112     return -1;
    113 
    114   /* At least the ELF header is there.  */
    115   size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
    116 
    117   /* Set the program header position.  */
    118   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
    119     {
    120       /* Only executables or shared objects have a program header.  */
    121       if (ehdr->e_type != ET_EXEC && unlikely (ehdr->e_type != ET_DYN))
    122 	{
    123 	  __libelf_seterrno (ELF_E_INVALID_PHDR);
    124 	  return -1;
    125 	}
    126 
    127       if (elf->flags & ELF_F_LAYOUT)
    128 	{
    129 	  /* The user is supposed to fill out e_phoff.  Use it and
    130 	     e_phnum to determine the maximum extend.  */
    131 	  size = MAX ((size_t) size,
    132 		      ehdr->e_phoff
    133 		      + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
    134 	}
    135       else
    136 	{
    137 	  update_if_changed (ehdr->e_phoff,
    138 			     elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
    139 			     ehdr_flags);
    140 
    141 	  /* We need no alignment here.  */
    142 	  size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum);
    143 	}
    144     }
    145 
    146   if (shnum > 0)
    147     {
    148       Elf_ScnList *list;
    149       bool first = true;
    150 
    151       assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
    152 
    153       if (shnum >= SHN_LORESERVE)
    154 	{
    155 	  /* We have to  fill in the number of sections in the header
    156 	     of the zeroth section.  */
    157 	  elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr.ELFW(e,LIBELFBITS)->sh_size
    158 	    = shnum;
    159 	  elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr_flags
    160 	    |= ELF_F_DIRTY;
    161 	}
    162 
    163 
    164       /* Go over all sections and find out how large they are.  */
    165       list = &elf->state.ELFW(elf,LIBELFBITS).scns;
    166 
    167       do
    168 	{
    169 	  size_t cnt;
    170 
    171 	  for (cnt = first == true; cnt < list->cnt; ++cnt)
    172 	    {
    173 	      Elf_Scn *scn = &list->data[cnt];
    174 	      ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
    175 	      off_t offset = 0;
    176 	      ElfW2(LIBELFBITS,Word) sh_entsize;
    177 	      ElfW2(LIBELFBITS,Word) sh_align;
    178 
    179 	      assert (shdr != NULL);
    180 	      sh_entsize = shdr->sh_entsize;
    181 	      sh_align = shdr->sh_addralign ?: 1;
    182 
    183 	      /* Set the sh_entsize value if we can reliably detect it.  */
    184 	      switch (shdr->sh_type)
    185 		{
    186 		case SHT_SYMTAB:
    187 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
    188 		  break;
    189 		case SHT_RELA:
    190 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
    191 		  break;
    192 		case SHT_GROUP:
    193 		  /* Only relocatable files can contain section groups.  */
    194 		  if (ehdr->e_type != ET_REL)
    195 		    {
    196 		      __libelf_seterrno (ELF_E_GROUP_NOT_REL);
    197 		      return -1;
    198 		    }
    199 		  /* FALLTHROUGH */
    200 		case SHT_SYMTAB_SHNDX:
    201 		  sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
    202 		  break;
    203 		case SHT_HASH:
    204 		  sh_entsize = SH_ENTSIZE_HASH (ehdr);
    205 		  break;
    206 		case SHT_DYNAMIC:
    207 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
    208 		  break;
    209 		case SHT_REL:
    210 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
    211 		  break;
    212 		case SHT_DYNSYM:
    213 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
    214 		  break;
    215 		case SHT_SUNW_move:
    216 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
    217 		  break;
    218 		case SHT_SUNW_syminfo:
    219 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
    220 		  break;
    221 		default:
    222 		  break;
    223 		}
    224 
    225 	      /* If the section header contained the wrong entry size
    226 		 correct it and mark the header as modified.  */
    227 	      update_if_changed (shdr->sh_entsize, sh_entsize,
    228 				 scn->shdr_flags);
    229 
    230 	      /* Iterate over all data blocks.  */
    231 	      if (list->data[cnt].data_list_rear != NULL)
    232 		{
    233 		  Elf_Data_List *dl = &scn->data_list;
    234 
    235 		  while (dl != NULL)
    236 		    {
    237 		      if (unlikely (dl->data.d.d_version == EV_NONE)
    238 			  || unlikely (dl->data.d.d_version >= EV_NUM))
    239 			{
    240 			  __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
    241 			  return -1;
    242 			}
    243 
    244 		      if (unlikely (! powerof2 (dl->data.d.d_align)))
    245 			{
    246 			  __libelf_seterrno (ELF_E_INVALID_ALIGN);
    247 			  return -1;
    248 			}
    249 
    250 		      sh_align = MAX (sh_align, dl->data.d.d_align);
    251 
    252 		      if (elf->flags & ELF_F_LAYOUT)
    253 			{
    254 			  /* The user specified the offset and the size.
    255 			     All we have to do is check whether this block
    256 			     fits in the size specified for the section.  */
    257 			  if (unlikely ((GElf_Word) (dl->data.d.d_off
    258 						     + dl->data.d.d_size)
    259 					> shdr->sh_size))
    260 			    {
    261 			      __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
    262 			      return -1;
    263 			    }
    264 			}
    265 		      else
    266 			{
    267 			  /* Determine the padding.  */
    268 			  offset = ((offset + dl->data.d.d_align - 1)
    269 				    & ~(dl->data.d.d_align - 1));
    270 
    271 			  update_if_changed (dl->data.d.d_off, offset,
    272 					     changed);
    273 
    274 			  offset += dl->data.d.d_size;
    275 			}
    276 
    277 		      /* Next data block.  */
    278 		      dl = dl->next;
    279 		    }
    280 		}
    281 
    282 	      if (elf->flags & ELF_F_LAYOUT)
    283 		{
    284 		  size = MAX ((GElf_Word) size,
    285 			      shdr->sh_offset
    286 			      + (shdr->sh_type != SHT_NOBITS
    287 				 ? shdr->sh_size : 0));
    288 
    289 		  /* The alignment must be a power of two.  This is a
    290 		     requirement from the ELF specification.  Additionally
    291 		     we test for the alignment of the section being large
    292 		     enough for the largest alignment required by a data
    293 		     block.  */
    294 		  if (unlikely (! powerof2 (shdr->sh_addralign))
    295 		      || unlikely (shdr->sh_addralign < sh_align))
    296 		    {
    297 		      __libelf_seterrno (ELF_E_INVALID_ALIGN);
    298 		      return -1;
    299 		    }
    300 		}
    301 	      else
    302 		{
    303 		  /* How much alignment do we need for this section.  */
    304 		  update_if_changed (shdr->sh_addralign, sh_align,
    305 				     scn->shdr_flags);
    306 
    307 		  size = (size + sh_align - 1) & ~(sh_align - 1);
    308 		  update_if_changed (shdr->sh_offset, (GElf_Word) size,
    309 				     changed);
    310 
    311 		  /* See whether the section size is correct.  */
    312 		  update_if_changed (shdr->sh_size, (GElf_Word) offset,
    313 				     changed);
    314 
    315 		  if (shdr->sh_type != SHT_NOBITS)
    316 		    size += offset;
    317 
    318 		  scn->flags |= changed;
    319 		}
    320 
    321 	      /* Check that the section size is actually a multiple of
    322 		 the entry size.  */
    323 	      if (shdr->sh_entsize != 0
    324 		  && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
    325 		  && (elf->flags & ELF_F_PERMISSIVE) == 0)
    326 		{
    327 		  __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
    328 		  return -1;
    329 		}
    330 	    }
    331 
    332 	  assert (list->next == NULL || list->cnt == list->max);
    333 
    334 	  first = false;
    335 	}
    336       while ((list = list->next) != NULL);
    337 
    338       /* Store section information.  */
    339       if (elf->flags & ELF_F_LAYOUT)
    340 	{
    341 	  /* The user is supposed to fill out e_phoff.  Use it and
    342 	     e_phnum to determine the maximum extend.  */
    343 	  size = MAX ((GElf_Word) size,
    344 		      (ehdr->e_shoff
    345 		       + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
    346 	}
    347       else
    348 	{
    349 	  /* Align for section header table.
    350 
    351 	     Yes, we use `sizeof' and not `__alignof__' since we do not
    352 	     want to be surprised by architectures with less strict
    353 	     alignment rules.  */
    354 #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
    355 	  size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
    356 
    357 	  update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
    358 	  update_if_changed (ehdr->e_shentsize,
    359 			     elf_typesize (LIBELFBITS, ELF_T_SHDR, 1),
    360 			     ehdr_flags);
    361 
    362 	  /* Account for the section header size.  */
    363 	  size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
    364 	}
    365     }
    366 
    367   elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
    368 
    369   return size;
    370 }
    371