• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
71 static int
ELFW(default_ehdr,LIBELFBITS)72 ELFW(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 
134 off_t
135 internal_function
__elfw2(LIBELFBITS,updatenull_wrlock)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