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 
49 
50 static int
ELFW(default_ehdr,LIBELFBITS)51 ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
52 			       size_t shnum, int *change_bop)
53 {
54   /* Always write the magic bytes.  */
55   if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
56     {
57       memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
58       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
59     }
60 
61   /* Always set the file class.  */
62   update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
63 		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
64 
65   /* Set the data encoding if necessary.  */
66   if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
67     {
68       ehdr->e_ident[EI_DATA] =
69 	BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
70       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
71     }
72   else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
73     {
74       __libelf_seterrno (ELF_E_DATA_ENCODING);
75       return 1;
76     }
77   else
78     *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
79 		    && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
80 		   || (BYTE_ORDER == BIG_ENDIAN
81 		       && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
82 
83   /* Unconditionally overwrite the ELF version.  */
84   update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
85 		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
86 
87   if (unlikely (ehdr->e_version == EV_NONE))
88     {
89       ehdr->e_version = EV_CURRENT;
90       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
91     }
92   else if (unlikely (ehdr->e_version != EV_CURRENT))
93     {
94       __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
95       return 1;
96     }
97 
98   if (unlikely (shnum >= SHN_LORESERVE))
99     {
100       update_if_changed (ehdr->e_shnum, 0,
101 			 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
102     }
103   else
104     update_if_changed (ehdr->e_shnum, shnum,
105 		       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
106 
107   if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
108     {
109       ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
110       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
111     }
112 
113   /* If phnum is zero make sure e_phoff is also zero and not some random
114      value.  That would cause trouble in update_file.  */
115   if (ehdr->e_phnum == 0 && ehdr->e_phoff != 0)
116     {
117       ehdr->e_phoff = 0;
118       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
119     }
120 
121   return 0;
122 }
123 
124 
125 off_t
126 internal_function
__elfw2(LIBELFBITS,updatenull_wrlock)127 __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
128 {
129   ElfW2(LIBELFBITS,Ehdr) *ehdr;
130   int changed = 0;
131   int ehdr_flags = 0;
132 
133   ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
134 
135   /* Set the default values.  */
136   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
137     return -1;
138 
139   /* At least the ELF header is there.  */
140   off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
141 
142   /* Set the program header position.  */
143   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
144     (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
145   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
146     {
147       size_t phnum;
148       if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
149 	return -1;
150 
151       if (elf->flags & ELF_F_LAYOUT)
152 	{
153 	  /* The user is supposed to fill out e_phoff.  Use it and
154 	     e_phnum to determine the maximum extend.  */
155 	  size = MAX ((size_t) size,
156 		      ehdr->e_phoff
157 		      + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
158 	}
159       else
160 	{
161 	  update_if_changed (ehdr->e_phoff,
162 			     elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
163 			     ehdr_flags);
164 
165 	  /* We need no alignment here.  */
166 	  size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum);
167 	}
168     }
169 
170   if (shnum > 0)
171     {
172       struct Elf_Scn *scn1 = NULL;
173       Elf_ScnList *list;
174       bool first = true;
175 
176       assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
177 
178       if (shnum >= SHN_LORESERVE)
179 	{
180 	  /* We have to  fill in the number of sections in the header
181 	     of the zeroth section.  */
182 	  Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
183 
184 	  update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
185 			     shnum, scn0->shdr_flags);
186 	}
187 
188       /* Go over all sections and find out how large they are.  */
189       list = &elf->state.ELFW(elf,LIBELFBITS).scns;
190 
191       /* Find the first section. */
192       if (list->cnt > 1)
193 	scn1 = &list->data[1];
194       else if (list->next != NULL)
195 	scn1 = &list->next->data[0];
196 
197       /* Load the section headers if necessary.  This loads the
198 	 headers for all sections.  */
199       if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL)
200 	(void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1);
201 
202       do
203 	{
204 	  for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
205 	    {
206 	      Elf_Scn *scn = &list->data[cnt];
207 	      ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
208 	      off_t offset = 0;
209 
210 	      assert (shdr != NULL);
211 	      ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize;
212 	      ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1;
213 	      if (unlikely (! powerof2 (sh_align)))
214 		{
215 		  __libelf_seterrno (ELF_E_INVALID_ALIGN);
216 		  return -1;
217 		}
218 
219 	      /* Set the sh_entsize value if we can reliably detect it.  */
220 	      switch (shdr->sh_type)
221 		{
222 		case SHT_SYMTAB:
223 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
224 		  break;
225 		case SHT_RELA:
226 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
227 		  break;
228 		case SHT_GROUP:
229 		  /* Only relocatable files can contain section groups.  */
230 		  if (ehdr->e_type != ET_REL)
231 		    {
232 		      __libelf_seterrno (ELF_E_GROUP_NOT_REL);
233 		      return -1;
234 		    }
235 		  FALLTHROUGH;
236 		case SHT_SYMTAB_SHNDX:
237 		  sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
238 		  break;
239 		case SHT_HASH:
240 		  sh_entsize = SH_ENTSIZE_HASH (ehdr);
241 		  break;
242 		case SHT_DYNAMIC:
243 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
244 		  break;
245 		case SHT_REL:
246 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
247 		  break;
248 		case SHT_DYNSYM:
249 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
250 		  break;
251 		case SHT_SUNW_move:
252 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
253 		  break;
254 		case SHT_SUNW_syminfo:
255 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
256 		  break;
257 		default:
258 		  break;
259 		}
260 
261 	      /* If the section header contained the wrong entry size
262 		 correct it and mark the header as modified.  */
263 	      update_if_changed (shdr->sh_entsize, sh_entsize,
264 				 scn->shdr_flags);
265 
266 	      if (scn->data_read == 0
267 		  && __libelf_set_rawdata_wrlock (scn) != 0)
268 		/* Something went wrong.  The error value is already set.  */
269 		return -1;
270 
271 	      /* Iterate over all data blocks.  */
272 	      if (list->data[cnt].data_list_rear != NULL)
273 		{
274 		  Elf_Data_List *dl = &scn->data_list;
275 
276 		  while (dl != NULL)
277 		    {
278 		      Elf_Data *data = &dl->data.d;
279 		      if (dl == &scn->data_list && data->d_buf == NULL
280 			  && scn->rawdata.d.d_buf != NULL)
281 			data = &scn->rawdata.d;
282 
283 		      if (unlikely (data->d_version != EV_CURRENT))
284 			{
285 			  __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
286 			  return -1;
287 			}
288 
289 		      if (unlikely (! powerof2 (data->d_align)))
290 			{
291 			  __libelf_seterrno (ELF_E_INVALID_ALIGN);
292 			  return -1;
293 			}
294 
295 		      sh_align = MAX (sh_align, data->d_align);
296 
297 		      if (elf->flags & ELF_F_LAYOUT)
298 			{
299 			  /* The user specified the offset and the size.
300 			     All we have to do is check whether this block
301 			     fits in the size specified for the section.  */
302 			  if (unlikely ((GElf_Word) (data->d_off
303 						     + data->d_size)
304 					> shdr->sh_size))
305 			    {
306 			      __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
307 			      return -1;
308 			    }
309 			}
310 		      else
311 			{
312 			  /* Determine the padding.  */
313 			  offset = ((offset + data->d_align - 1)
314 				    & ~(data->d_align - 1));
315 
316 			  update_if_changed (data->d_off, offset, changed);
317 
318 			  offset += data->d_size;
319 			}
320 
321 		      /* Next data block.  */
322 		      dl = dl->next;
323 		    }
324 		}
325 	      else
326 		/* Get the size of the section from the raw data.  If
327 		   none is available the value is zero.  */
328 		offset += scn->rawdata.d.d_size;
329 
330 	      if (elf->flags & ELF_F_LAYOUT)
331 		{
332 		  size = MAX ((GElf_Word) size,
333 			      (shdr->sh_type != SHT_NOBITS
334 			       ? shdr->sh_offset + shdr->sh_size : 0));
335 
336 		  /* The alignment must be a power of two.  This is a
337 		     requirement from the ELF specification.  Additionally
338 		     we test for the alignment of the section being large
339 		     enough for the largest alignment required by a data
340 		     block.  */
341 		  if (unlikely (! powerof2 (shdr->sh_addralign))
342 		      || unlikely ((shdr->sh_addralign ?: 1) < sh_align))
343 		    {
344 		      __libelf_seterrno (ELF_E_INVALID_ALIGN);
345 		      return -1;
346 		    }
347 		}
348 	      else
349 		{
350 		  /* How much alignment do we need for this section.  */
351 		  update_if_changed (shdr->sh_addralign, sh_align,
352 				     scn->shdr_flags);
353 
354 		  size = (size + sh_align - 1) & ~(sh_align - 1);
355 		  int offset_changed = 0;
356 		  update_if_changed (shdr->sh_offset, (GElf_Word) size,
357 				     offset_changed);
358 		  changed |= offset_changed;
359 
360 		  if (offset_changed && scn->data_list_rear == NULL)
361 		    {
362 		      /* The position of the section in the file
363 			 changed.  Create the section data list.  */
364 		      if (__elf_getdata_rdlock (scn, NULL) == NULL)
365 			return -1;
366 		    }
367 
368 		  /* See whether the section size is correct.  */
369 		  update_if_changed (shdr->sh_size, (GElf_Word) offset,
370 				     changed);
371 
372 		  if (shdr->sh_type != SHT_NOBITS)
373 		    size += offset;
374 
375 		  scn->flags |= changed;
376 		}
377 
378 	      /* Check that the section size is actually a multiple of
379 		 the entry size.  */
380 	      if (shdr->sh_entsize != 0 && shdr->sh_entsize != 1
381 		  && (elf->flags & ELF_F_PERMISSIVE) == 0)
382 		{
383 		  /* For compressed sections check the uncompressed size.  */
384 		  ElfW2(LIBELFBITS,Word) sh_size;
385 		  if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
386 		    sh_size = shdr->sh_size;
387 		  else
388 		    {
389 		      ElfW2(LIBELFBITS,Chdr) *chdr;
390 		      chdr = elfw2(LIBELFBITS,getchdr) (scn);
391 		      if (unlikely (chdr == NULL))
392 			return -1;
393 		      sh_size = chdr->ch_size;
394 		    }
395 
396 		  if (unlikely (sh_size % shdr->sh_entsize != 0))
397 		    {
398 		      __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
399 		      return -1;
400 		    }
401 		}
402 	    }
403 
404 	  assert (list->next == NULL || list->cnt == list->max);
405 
406 	  first = false;
407 	}
408       while ((list = list->next) != NULL);
409 
410       /* Store section information.  */
411       update_if_changed (ehdr->e_shentsize,
412 			 elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), ehdr_flags);
413       if (elf->flags & ELF_F_LAYOUT)
414 	{
415 	  /* The user is supposed to fill out e_shoff.  Use it and
416 	     e_shnum (or sh_size of the dummy, first section header)
417 	     to determine the maximum extend.  */
418 	  size = MAX ((GElf_Word) size,
419 		      (ehdr->e_shoff
420 		       + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
421 	}
422       else
423 	{
424 	  /* Align for section header table.
425 
426 	     Yes, we use `sizeof' and not `__alignof__' since we do not
427 	     want to be surprised by architectures with less strict
428 	     alignment rules.  */
429 #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
430 	  size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
431 
432 	  update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
433 
434 	  /* Account for the section header size.  */
435 	  size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
436 	}
437     }
438 
439   elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
440 
441   return size;
442 }
443