1/* Update data structures for changes.
2   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
3   This file is part of Red Hat elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
6   Red Hat elfutils is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 2 of the License.
9
10   Red Hat elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License along
16   with Red Hat elfutils; if not, write to the Free Software Foundation,
17   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18
19   In addition, as a special exception, Red Hat, Inc. gives You the
20   additional right to link the code of Red Hat elfutils with code licensed
21   under any Open Source Initiative certified open source license
22   (http://www.opensource.org/licenses/index.php) which requires the
23   distribution of source code with any binary distribution and to
24   distribute linked combinations of the two.  Non-GPL Code permitted under
25   this exception must only link to the code of Red Hat elfutils through
26   those well defined interfaces identified in the file named EXCEPTION
27   found in the source code files (the "Approved Interfaces").  The files
28   of Non-GPL Code may instantiate templates or use macros or inline
29   functions from the Approved Interfaces without causing the resulting
30   work to be covered by the GNU General Public License.  Only Red Hat,
31   Inc. may make changes or additions to the list of Approved Interfaces.
32   Red Hat's grant of this exception is conditioned upon your not adding
33   any new exceptions.  If you wish to add a new Approved Interface or
34   exception, please contact Red Hat.  You must obey the GNU General Public
35   License in all respects for all of the Red Hat elfutils code and other
36   code used in conjunction with Red Hat elfutils except the Non-GPL Code
37   covered by this exception.  If you modify this file, you may extend this
38   exception to your version of the file, but you are not obligated to do
39   so.  If you do not wish to provide this exception without modification,
40   you must delete this exception statement from your version and license
41   this file solely under the GPL without exception.
42
43   Red Hat elfutils is an included package of the Open Invention Network.
44   An included package of the Open Invention Network is a package for which
45   Open Invention Network licensees cross-license their patents.  No patent
46   license is granted, either expressly or impliedly, by designation as an
47   included package.  Should you wish to participate in the Open Invention
48   Network licensing program, please visit www.openinventionnetwork.com
49   <http://www.openinventionnetwork.com>.  */
50
51#ifdef HAVE_CONFIG_H
52# include <config.h>
53#endif
54
55#include <assert.h>
56#include <endian.h>
57#include <libelf.h>
58#include <stdbool.h>
59#include <string.h>
60#include <sys/param.h>
61
62#include "libelfP.h"
63#include "elf-knowledge.h"
64
65#ifndef LIBELFBITS
66# define LIBELFBITS 32
67#endif
68
69
70
71static int
72ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
73			       size_t shnum, int *change_bop)
74{
75  /* Always write the magic bytes.  */
76  if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
77    {
78      memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
79      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
80    }
81
82  /* Always set the file class.  */
83  update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
84		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
85
86  /* Set the data encoding if necessary.  */
87  if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
88    {
89      ehdr->e_ident[EI_DATA] =
90	BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
91      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
92    }
93  else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
94    {
95      __libelf_seterrno (ELF_E_DATA_ENCODING);
96      return 1;
97    }
98  else
99    *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
100		    && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
101		   || (BYTE_ORDER == BIG_ENDIAN
102		       && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
103
104  /* Unconditionally overwrite the ELF version.  */
105  update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
106		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
107
108  if (unlikely (ehdr->e_version == EV_NONE)
109      || unlikely (ehdr->e_version >= EV_NUM))
110    {
111      __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
112      return 1;
113    }
114
115  if (unlikely (shnum >= SHN_LORESERVE))
116    {
117      update_if_changed (ehdr->e_shnum, 0,
118			 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
119    }
120  else
121    update_if_changed (ehdr->e_shnum, shnum,
122		       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
123
124  if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
125    {
126      ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
127      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
128    }
129
130  return 0;
131}
132
133
134off_t
135internal_function
136__elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
137{
138  ElfW2(LIBELFBITS,Ehdr) *ehdr;
139  int changed = 0;
140  int ehdr_flags = 0;
141
142  ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
143
144  /* Set the default values.  */
145  if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
146    return -1;
147
148  /* At least the ELF header is there.  */
149  off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
150
151  /* Set the program header position.  */
152  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL
153      && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN
154	  || ehdr->e_type == ET_CORE))
155    (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
156  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
157    {
158      /* Only executables, shared objects, and core files have a program
159	 header.  */
160      if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
161	  && unlikely (ehdr->e_type != ET_CORE))
162	{
163	  __libelf_seterrno (ELF_E_INVALID_PHDR);
164	  return -1;
165	}
166
167      if (elf->flags & ELF_F_LAYOUT)
168	{
169	  /* The user is supposed to fill out e_phoff.  Use it and
170	     e_phnum to determine the maximum extend.  */
171	  size = MAX ((size_t) size,
172		      ehdr->e_phoff
173		      + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
174	}
175      else
176	{
177	  update_if_changed (ehdr->e_phoff,
178			     elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
179			     ehdr_flags);
180
181	  /* We need no alignment here.  */
182	  size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum);
183	}
184    }
185
186  if (shnum > 0)
187    {
188      Elf_ScnList *list;
189      bool first = true;
190
191      assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
192
193      if (shnum >= SHN_LORESERVE)
194	{
195	  /* We have to  fill in the number of sections in the header
196	     of the zeroth section.  */
197	  Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
198
199	  update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
200			     shnum, scn0->shdr_flags);
201	}
202
203      /* Go over all sections and find out how large they are.  */
204      list = &elf->state.ELFW(elf,LIBELFBITS).scns;
205
206      /* Load the section headers if necessary.  This loads the
207	 headers for all sections.  */
208      if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL)
209	(void) __elfw2(LIBELFBITS,getshdr_wrlock) (&list->data[1]);
210
211      do
212	{
213	  for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
214	    {
215	      Elf_Scn *scn = &list->data[cnt];
216	      ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
217	      off_t offset = 0;
218
219	      assert (shdr != NULL);
220	      ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize;
221	      ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1;
222
223	      /* Set the sh_entsize value if we can reliably detect it.  */
224	      switch (shdr->sh_type)
225		{
226		case SHT_SYMTAB:
227		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
228		  break;
229		case SHT_RELA:
230		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
231		  break;
232		case SHT_GROUP:
233		  /* Only relocatable files can contain section groups.  */
234		  if (ehdr->e_type != ET_REL)
235		    {
236		      __libelf_seterrno (ELF_E_GROUP_NOT_REL);
237		      return -1;
238		    }
239		  /* FALLTHROUGH */
240		case SHT_SYMTAB_SHNDX:
241		  sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
242		  break;
243		case SHT_HASH:
244		  sh_entsize = SH_ENTSIZE_HASH (ehdr);
245		  break;
246		case SHT_DYNAMIC:
247		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
248		  break;
249		case SHT_REL:
250		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
251		  break;
252		case SHT_DYNSYM:
253		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
254		  break;
255		case SHT_SUNW_move:
256		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
257		  break;
258		case SHT_SUNW_syminfo:
259		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
260		  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	      update_if_changed (shdr->sh_entsize, sh_entsize,
268				 scn->shdr_flags);
269
270	      if (scn->data_read == 0
271		  && __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	      if (list->data[cnt].data_list_rear != NULL)
277		{
278		  Elf_Data_List *dl = &scn->data_list;
279
280		  while (dl != NULL)
281		    {
282		      Elf_Data *data = &dl->data.d;
283		      if (dl == &scn->data_list && data->d_buf == NULL
284			  && scn->rawdata.d.d_buf != NULL)
285			data = &scn->rawdata.d;
286
287		      if (unlikely (data->d_version == EV_NONE)
288			  || unlikely (data->d_version >= EV_NUM))
289			{
290			  __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
291			  return -1;
292			}
293
294		      if (unlikely (! powerof2 (data->d_align)))
295			{
296			  __libelf_seterrno (ELF_E_INVALID_ALIGN);
297			  return -1;
298			}
299
300		      sh_align = MAX (sh_align, data->d_align);
301
302		      if (elf->flags & ELF_F_LAYOUT)
303			{
304			  /* The user specified the offset and the size.
305			     All we have to do is check whether this block
306			     fits in the size specified for the section.  */
307			  if (unlikely ((GElf_Word) (data->d_off
308						     + data->d_size)
309					> shdr->sh_size))
310			    {
311			      __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
312			      return -1;
313			    }
314			}
315		      else
316			{
317			  /* Determine the padding.  */
318			  offset = ((offset + data->d_align - 1)
319				    & ~(data->d_align - 1));
320
321			  update_if_changed (data->d_off, offset, changed);
322
323			  offset += data->d_size;
324			}
325
326		      /* Next data block.  */
327		      dl = dl->next;
328		    }
329		}
330	      else
331		/* Get the size of the section from the raw data.  If
332		   none is available the value is zero.  */
333		offset += scn->rawdata.d.d_size;
334
335	      if (elf->flags & ELF_F_LAYOUT)
336		{
337		  size = MAX ((GElf_Word) size,
338			      shdr->sh_offset
339			      + (shdr->sh_type != SHT_NOBITS
340				 ? shdr->sh_size : 0));
341
342		  /* The alignment must be a power of two.  This is a
343		     requirement from the ELF specification.  Additionally
344		     we test for the alignment of the section being large
345		     enough for the largest alignment required by a data
346		     block.  */
347		  if (unlikely (! powerof2 (shdr->sh_addralign))
348		      || unlikely (shdr->sh_addralign < sh_align))
349		    {
350		      __libelf_seterrno (ELF_E_INVALID_ALIGN);
351		      return -1;
352		    }
353		}
354	      else
355		{
356		  /* How much alignment do we need for this section.  */
357		  update_if_changed (shdr->sh_addralign, sh_align,
358				     scn->shdr_flags);
359
360		  size = (size + sh_align - 1) & ~(sh_align - 1);
361		  int offset_changed = 0;
362		  update_if_changed (shdr->sh_offset, (GElf_Word) size,
363				     offset_changed);
364		  changed |= offset_changed;
365
366		  if (offset_changed && scn->data_list_rear == NULL)
367		    {
368		      /* The position of the section in the file
369			 changed.  Create the section data list.  */
370		      if (__elf_getdata_rdlock (scn, NULL) == NULL)
371			return -1;
372		    }
373
374		  /* See whether the section size is correct.  */
375		  update_if_changed (shdr->sh_size, (GElf_Word) offset,
376				     changed);
377
378		  if (shdr->sh_type != SHT_NOBITS)
379		    size += offset;
380
381		  scn->flags |= changed;
382		}
383
384	      /* Check that the section size is actually a multiple of
385		 the entry size.  */
386	      if (shdr->sh_entsize != 0
387		  && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
388		  && (elf->flags & ELF_F_PERMISSIVE) == 0)
389		{
390		  __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
391		  return -1;
392		}
393	    }
394
395	  assert (list->next == NULL || list->cnt == list->max);
396
397	  first = false;
398	}
399      while ((list = list->next) != NULL);
400
401      /* Store section information.  */
402      if (elf->flags & ELF_F_LAYOUT)
403	{
404	  /* The user is supposed to fill out e_phoff.  Use it and
405	     e_phnum to determine the maximum extend.  */
406	  size = MAX ((GElf_Word) size,
407		      (ehdr->e_shoff
408		       + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
409	}
410      else
411	{
412	  /* Align for section header table.
413
414	     Yes, we use `sizeof' and not `__alignof__' since we do not
415	     want to be surprised by architectures with less strict
416	     alignment rules.  */
417#define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
418	  size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
419
420	  update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
421	  update_if_changed (ehdr->e_shentsize,
422			     elf_typesize (LIBELFBITS, ELF_T_SHDR, 1),
423			     ehdr_flags);
424
425	  /* Account for the section header size.  */
426	  size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
427	}
428    }
429
430  elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
431
432  return size;
433}
434