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 : 691 : 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 [ + + ]: 691 : if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
58 : : {
59 : 279 : memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
60 : 279 : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
61 : : }
62 : :
63 : : /* Always set the file class. */
64 [ + + ]: 691 : 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 [ + + ]: 691 : if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
69 : : {
70 : 4 : ehdr->e_ident[EI_DATA] =
71 : : BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
72 : 4 : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
73 : : }
74 [ - + ]: 687 : 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 : 687 : *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
81 : : && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
82 : 687 : || (BYTE_ORDER == BIG_ENDIAN
83 : : && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
84 : :
85 : : /* Unconditionally overwrite the ELF version. */
86 [ + + ]: 691 : update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
87 : : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
88 : :
89 [ + + ]: 691 : if (unlikely (ehdr->e_version == EV_NONE))
90 : : {
91 : 4 : ehdr->e_version = EV_CURRENT;
92 : 4 : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
93 : : }
94 [ - + ]: 687 : else if (unlikely (ehdr->e_version != EV_CURRENT))
95 : : {
96 : 0 : __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
97 : 0 : return 1;
98 : : }
99 : :
100 [ + + ]: 691 : if (unlikely (shnum >= SHN_LORESERVE))
101 : : {
102 [ + + ]: 17 : update_if_changed (ehdr->e_shnum, 0,
103 : : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
104 : : }
105 : : else
106 [ + + ]: 674 : update_if_changed (ehdr->e_shnum, shnum,
107 : : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
108 : :
109 [ + + ]: 691 : if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
110 : : {
111 : 465 : ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
112 : 465 : 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 [ + + + - ]: 691 : 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 : 691 : __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
130 : : {
131 : 691 : ElfW2(LIBELFBITS,Ehdr) *ehdr;
132 : 691 : int changed = 0;
133 : 691 : int ehdr_flags = 0;
134 : :
135 : 691 : ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
136 : :
137 : : /* Set the default values. */
138 [ - + ]: 691 : if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
139 : : return -1;
140 : :
141 : : /* At least the ELF header is there. */
142 : 691 : ElfW2(LIBELFBITS,SizeWord) size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
143 : :
144 : : /* Set the program header position. */
145 [ + + ]: 691 : if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
146 : 291 : (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
147 [ + + ]: 691 : if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
148 : : {
149 : 428 : size_t phnum;
150 [ - + ]: 428 : if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
151 : 0 : return -1;
152 : :
153 [ + + ]: 428 : 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 : 363 : size = MAX (size,
158 : : ehdr->e_phoff
159 : : + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
160 : : }
161 : : else
162 : : {
163 [ + + ]: 65 : 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 : 65 : size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum);
169 : : }
170 : : }
171 : :
172 [ + + ]: 691 : if (shnum > 0)
173 : : {
174 : 676 : struct Elf_Scn *scn1 = NULL;
175 : 676 : Elf_ScnList *list;
176 : 676 : bool first = true;
177 : :
178 [ - + ]: 676 : assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
179 : :
180 [ + + ]: 676 : if (shnum >= SHN_LORESERVE)
181 : : {
182 : : /* We have to fill in the number of sections in the header
183 : : of the zeroth section. */
184 : 17 : Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
185 : :
186 [ + - ]: 17 : 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 : 676 : list = &elf->state.ELFW(elf,LIBELFBITS).scns;
192 : :
193 : : /* Find the first section. */
194 [ + + ]: 676 : if (list->cnt > 1)
195 : 672 : scn1 = &list->data[1];
196 [ + - ]: 4 : else if (list->next != NULL)
197 : 4 : scn1 = &list->next->data[0];
198 : :
199 : : /* Load the section headers if necessary. This loads the
200 : : headers for all sections. */
201 [ + + ]: 676 : if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL)
202 : 29 : (void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1);
203 : :
204 : 1653 : do
205 : : {
206 [ + + ]: 1917756 : for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
207 : : {
208 : 1916103 : Elf_Scn *scn = &list->data[cnt];
209 : 1916103 : ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
210 : 1916103 : int64_t offset = 0;
211 : :
212 [ - + ]: 1916103 : assert (shdr != NULL);
213 : 1916103 : ElfW2(LIBELFBITS,SizeWord) sh_entsize = shdr->sh_entsize;
214 : 1916103 : ElfW2(LIBELFBITS,SizeWord) sh_align = shdr->sh_addralign ?: 1;
215 [ - + ]: 1916103 : if (unlikely (! powerof2 (sh_align)))
216 : : {
217 : 0 : __libelf_seterrno (ELF_E_INVALID_ALIGN);
218 : 0 : return -1;
219 : : }
220 : :
221 : : /* Set the sh_entsize value if we can reliably detect it. */
222 [ + + + + : 1916103 : switch (shdr->sh_type)
+ + + + -
- - + ]
223 : : {
224 : 529 : case SHT_SYMTAB:
225 : 529 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
226 : 529 : break;
227 : 1076 : case SHT_RELA:
228 : 1076 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
229 : 1076 : break;
230 : 22026 : case SHT_GROUP:
231 : : /* Only relocatable files can contain section groups. */
232 [ - + ]: 22026 : if (ehdr->e_type != ET_REL)
233 : : {
234 : 0 : __libelf_seterrno (ELF_E_GROUP_NOT_REL);
235 : 0 : return -1;
236 : : }
237 : 22028 : FALLTHROUGH;
238 : : case SHT_SYMTAB_SHNDX:
239 : 22028 : sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
240 : 22028 : break;
241 : 132 : case SHT_HASH:
242 [ + + + + : 132 : sh_entsize = SH_ENTSIZE_HASH (ehdr);
+ + ]
243 : : break;
244 : 236 : case SHT_DYNAMIC:
245 : 236 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
246 : 236 : break;
247 : 214 : case SHT_REL:
248 : 214 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
249 : 214 : break;
250 : 234 : case SHT_DYNSYM:
251 : 234 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
252 : 234 : break;
253 : 0 : case SHT_SUNW_move:
254 : 0 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
255 : 0 : break;
256 : 0 : case SHT_SUNW_syminfo:
257 : 0 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
258 : 0 : break;
259 : 0 : case SHT_RELR:
260 : 0 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELR, 1);
261 : 0 : 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 [ + + ]: 1916103 : 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 [ + + ]: 1916103 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
276 : : {
277 : 492 : sh_align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS),
278 : : ELF_T_CHDR);
279 [ + + ]: 492 : update_if_changed (shdr->sh_addralign, sh_align,
280 : : scn->shdr_flags);
281 : : }
282 : :
283 [ + + ]: 1916103 : if (scn->data_read == 0
284 [ - + ]: 263680 : && __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 [ + + ]: 1916103 : if (list->data[cnt].data_list_rear != NULL)
290 : : {
291 : 1652417 : Elf_Data_List *dl = &scn->data_list;
292 : :
293 [ + + ]: 3304984 : while (dl != NULL)
294 : : {
295 : 1652567 : Elf_Data *data = &dl->data.d;
296 [ + + + + ]: 1652567 : if (dl == &scn->data_list && data->d_buf == NULL
297 [ - + ]: 67884 : && scn->rawdata.d.d_buf != NULL)
298 : 0 : data = &scn->rawdata.d;
299 : :
300 [ - + ]: 1652567 : if (unlikely (data->d_version != EV_CURRENT))
301 : : {
302 : 0 : __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
303 : 0 : return -1;
304 : : }
305 : :
306 [ - + ]: 1652567 : if (unlikely (! powerof2 (data->d_align)))
307 : : {
308 : 0 : __libelf_seterrno (ELF_E_INVALID_ALIGN);
309 : 0 : return -1;
310 : : }
311 : :
312 : 1652567 : sh_align = MAX (sh_align, data->d_align);
313 : :
314 [ + + ]: 1652567 : 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 [ - + ]: 401236 : if (unlikely ((ElfW2(LIBELFBITS,SizeWord))
320 : : (data->d_off + data->d_size)
321 : : > shdr->sh_size))
322 : : {
323 : 0 : __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
324 : 0 : return -1;
325 : : }
326 : : }
327 : : else
328 : : {
329 : : /* Determine the padding. */
330 : 1251331 : offset = ((offset + data->d_align - 1)
331 : 1251331 : & ~(data->d_align - 1));
332 : :
333 [ + + ]: 1251331 : update_if_changed (data->d_off, offset, changed);
334 : :
335 : 1251331 : offset += data->d_size;
336 : : }
337 : :
338 : : /* Next data block. */
339 : 1652567 : 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 : 263686 : offset += scn->rawdata.d.d_size;
346 : :
347 [ + + ]: 1916103 : if (elf->flags & ELF_F_LAYOUT)
348 : : {
349 [ + + ]: 401902 : 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 [ + - ]: 401902 : if (unlikely (! powerof2 (shdr->sh_addralign))
359 [ - + ]: 401902 : || unlikely ((shdr->sh_addralign ?: 1) < sh_align))
360 : : {
361 : 0 : __libelf_seterrno (ELF_E_INVALID_ALIGN);
362 : 0 : return -1;
363 : : }
364 : : }
365 : : else
366 : : {
367 : : /* How much alignment do we need for this section. */
368 [ + + ]: 1514201 : update_if_changed (shdr->sh_addralign, sh_align,
369 : : scn->shdr_flags);
370 : :
371 : 1514201 : size = (size + sh_align - 1) & ~(sh_align - 1);
372 : 1514201 : int offset_changed = 0;
373 [ + + ]: 1514201 : update_if_changed (shdr->sh_offset, size, offset_changed);
374 : 2502614 : changed |= offset_changed;
375 : :
376 [ + + ]: 988413 : 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 [ - + ]: 174 : if (__elf_getdata_rdlock (scn, NULL) == NULL)
381 : : return -1;
382 : : }
383 : :
384 : : /* See whether the section size is correct. */
385 : 1514201 : int size_changed = 0;
386 [ + + ]: 1514201 : update_if_changed (shdr->sh_size,
387 : : (ElfW2(LIBELFBITS,SizeWord)) offset,
388 : : size_changed);
389 : 1514201 : changed |= size_changed;
390 : :
391 [ + + ]: 1514201 : if (shdr->sh_type != SHT_NOBITS)
392 : 1447005 : size += offset;
393 : :
394 : 1514201 : scn->shdr_flags |= (offset_changed | size_changed);
395 : 1514201 : scn->flags |= changed;
396 : : }
397 : :
398 : : /* Check that the section size is actually a multiple of
399 : : the entry size. */
400 [ + + ]: 1916103 : if (shdr->sh_entsize != 0 && shdr->sh_entsize != 1
401 [ + - ]: 26113 : && (elf->flags & ELF_F_PERMISSIVE) == 0)
402 : : {
403 : : /* For compressed sections check the uncompressed size. */
404 : 26113 : ElfW2(LIBELFBITS,SizeWord) sh_size;
405 [ + + ]: 26113 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
406 : 26104 : sh_size = shdr->sh_size;
407 : : else
408 : : {
409 : 9 : ElfW2(LIBELFBITS,Chdr) *chdr;
410 : 9 : chdr = __elfw2(LIBELFBITS,getchdr_wrlock) (scn);
411 [ - + ]: 9 : if (unlikely (chdr == NULL))
412 : : return -1;
413 : 9 : sh_size = chdr->ch_size;
414 : : }
415 : :
416 [ - + ]: 26113 : if (unlikely (sh_size % shdr->sh_entsize != 0))
417 : : {
418 : 0 : __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
419 : 0 : return -1;
420 : : }
421 : : }
422 : : }
423 : :
424 [ + + - + ]: 1653 : assert (list->next == NULL || list->cnt == list->max);
425 : :
426 : 1653 : first = false;
427 : : }
428 [ + + ]: 1653 : while ((list = list->next) != NULL);
429 : :
430 : : /* Store section information. */
431 [ + + ]: 676 : update_if_changed (ehdr->e_shentsize,
432 : : elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), ehdr_flags);
433 [ + + ]: 676 : 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 : 381 : 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 : 295 : size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
451 : :
452 [ + + ]: 295 : update_if_changed (ehdr->e_shoff, size, elf->flags);
453 : :
454 : : /* Account for the section header size. */
455 : 295 : size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
456 : : }
457 : : }
458 : :
459 : 691 : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
460 : :
461 : 691 : return size;
462 : : }
|