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