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