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 : 700 : 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 [ + + ]: 700 : 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 [ + + ]: 700 : 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 [ + + ]: 700 : 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 [ - + ]: 696 : 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 : 696 : *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
81 : : && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
82 : 696 : || (BYTE_ORDER == BIG_ENDIAN
83 : : && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
84 : :
85 : : /* Unconditionally overwrite the ELF version. */
86 [ + + ]: 700 : update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
87 : : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
88 : :
89 [ + + ]: 700 : 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 [ - + ]: 696 : else if (unlikely (ehdr->e_version != EV_CURRENT))
95 : : {
96 : 0 : __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
97 : 0 : return 1;
98 : : }
99 : :
100 [ + + ]: 700 : 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 [ + + ]: 683 : update_if_changed (ehdr->e_shnum, shnum,
107 : : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
108 : :
109 [ + + ]: 700 : if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
110 : : {
111 : 469 : ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
112 : 469 : 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 [ + + + - ]: 700 : 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 : 700 : __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
130 : : {
131 : 700 : ElfW2(LIBELFBITS,Ehdr) *ehdr;
132 : 700 : int changed = 0;
133 : 700 : int ehdr_flags = 0;
134 : :
135 : 700 : ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
136 : :
137 : : /* Set the default values. */
138 [ - + ]: 700 : if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
139 : : return -1;
140 : :
141 : : /* At least the ELF header is there. */
142 : 700 : ElfW2(LIBELFBITS,SizeWord) size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
143 : :
144 : : /* Set the program header position. */
145 [ + + ]: 700 : if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
146 : 296 : (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
147 [ + + ]: 700 : if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
148 : : {
149 : 433 : size_t phnum;
150 [ - + ]: 433 : if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
151 : 0 : return -1;
152 : :
153 [ + + ]: 433 : 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 : 366 : size = MAX (size,
158 : : ehdr->e_phoff
159 : : + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
160 : : }
161 : : else
162 : : {
163 [ + + ]: 67 : 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 : 67 : size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum);
169 : : }
170 : : }
171 : :
172 [ + + ]: 700 : if (shnum > 0)
173 : : {
174 : 685 : struct Elf_Scn *scn1 = NULL;
175 : 685 : Elf_ScnList *list;
176 : 685 : bool first = true;
177 : :
178 [ - + ]: 685 : assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
179 : :
180 [ + + ]: 685 : 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 : 685 : list = &elf->state.ELFW(elf,LIBELFBITS).scns;
192 : :
193 : : /* Find the first section. */
194 [ + + ]: 685 : if (list->cnt > 1)
195 : 681 : 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 [ + + ]: 685 : if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL)
202 : 30 : (void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1);
203 : :
204 : 1668 : do
205 : : {
206 [ + + ]: 1917951 : for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
207 : : {
208 : 1916283 : Elf_Scn *scn = &list->data[cnt];
209 : 1916283 : ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
210 : 1916283 : int64_t offset = 0;
211 : :
212 [ - + ]: 1916283 : assert (shdr != NULL);
213 : 1916283 : ElfW2(LIBELFBITS,SizeWord) sh_entsize = shdr->sh_entsize;
214 : 1916283 : ElfW2(LIBELFBITS,SizeWord) sh_align = shdr->sh_addralign ?: 1;
215 [ - + ]: 1916283 : 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 [ + + + + : 1916283 : switch (shdr->sh_type)
+ + + + -
- + ]
223 : : {
224 : 535 : case SHT_SYMTAB:
225 : 535 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
226 : 535 : break;
227 : 1087 : case SHT_RELA:
228 : 1087 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
229 : 1087 : 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 : 136 : case SHT_HASH:
242 [ + + + + : 136 : sh_entsize = SH_ENTSIZE_HASH (ehdr);
+ + ]
243 : : break;
244 : 240 : case SHT_DYNAMIC:
245 : 240 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
246 : 240 : break;
247 : 214 : case SHT_REL:
248 : 214 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
249 : 214 : break;
250 : 238 : case SHT_DYNSYM:
251 : 238 : sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
252 : 238 : 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 : : default:
260 : : break;
261 : : }
262 : :
263 : : /* If the section header contained the wrong entry size
264 : : correct it and mark the header as modified. */
265 [ + + ]: 1916283 : update_if_changed (shdr->sh_entsize, sh_entsize,
266 : : scn->shdr_flags);
267 : :
268 : : /* Likewise for the alignment of a compressed section.
269 : : For a SHF_COMPRESSED section set the correct
270 : : sh_addralign value, which must match the d_align of
271 : : the data (see __libelf_set_rawdata in elf_getdata.c). */
272 [ + + ]: 1916283 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
273 : : {
274 : 492 : sh_align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS),
275 : : ELF_T_CHDR);
276 [ + + ]: 492 : update_if_changed (shdr->sh_addralign, sh_align,
277 : : scn->shdr_flags);
278 : : }
279 : :
280 [ + + ]: 1916283 : if (scn->data_read == 0
281 [ - + ]: 263738 : && __libelf_set_rawdata_wrlock (scn) != 0)
282 : : /* Something went wrong. The error value is already set. */
283 : : return -1;
284 : :
285 : : /* Iterate over all data blocks. */
286 [ + + ]: 1916283 : if (list->data[cnt].data_list_rear != NULL)
287 : : {
288 : 1652539 : Elf_Data_List *dl = &scn->data_list;
289 : :
290 [ + + ]: 3305228 : while (dl != NULL)
291 : : {
292 : 1652689 : Elf_Data *data = &dl->data.d;
293 [ + + + + ]: 1652689 : if (dl == &scn->data_list && data->d_buf == NULL
294 [ - + ]: 67917 : && scn->rawdata.d.d_buf != NULL)
295 : 0 : data = &scn->rawdata.d;
296 : :
297 [ - + ]: 1652689 : if (unlikely (data->d_version != EV_CURRENT))
298 : : {
299 : 0 : __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
300 : 0 : return -1;
301 : : }
302 : :
303 [ - + ]: 1652689 : if (unlikely (! powerof2 (data->d_align)))
304 : : {
305 : 0 : __libelf_seterrno (ELF_E_INVALID_ALIGN);
306 : 0 : return -1;
307 : : }
308 : :
309 : 1652689 : sh_align = MAX (sh_align, data->d_align);
310 : :
311 [ + + ]: 1652689 : if (elf->flags & ELF_F_LAYOUT)
312 : : {
313 : : /* The user specified the offset and the size.
314 : : All we have to do is check whether this block
315 : : fits in the size specified for the section. */
316 [ - + ]: 401302 : if (unlikely ((ElfW2(LIBELFBITS,SizeWord))
317 : : (data->d_off + data->d_size)
318 : : > shdr->sh_size))
319 : : {
320 : 0 : __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
321 : 0 : return -1;
322 : : }
323 : : }
324 : : else
325 : : {
326 : : /* Determine the padding. */
327 : 1251387 : offset = ((offset + data->d_align - 1)
328 : 1251387 : & ~(data->d_align - 1));
329 : :
330 [ + + ]: 1251387 : update_if_changed (data->d_off, offset, changed);
331 : :
332 : 1251387 : offset += data->d_size;
333 : : }
334 : :
335 : : /* Next data block. */
336 : 1652689 : dl = dl->next;
337 : : }
338 : : }
339 : : else
340 : : /* Get the size of the section from the raw data. If
341 : : none is available the value is zero. */
342 : 263744 : offset += scn->rawdata.d.d_size;
343 : :
344 [ + + ]: 1916283 : if (elf->flags & ELF_F_LAYOUT)
345 : : {
346 [ + + ]: 401994 : size = MAX (size,
347 : : (shdr->sh_type != SHT_NOBITS
348 : : ? shdr->sh_offset + shdr->sh_size : 0));
349 : :
350 : : /* The alignment must be a power of two. This is a
351 : : requirement from the ELF specification. Additionally
352 : : we test for the alignment of the section being large
353 : : enough for the largest alignment required by a data
354 : : block. */
355 [ + - ]: 401994 : if (unlikely (! powerof2 (shdr->sh_addralign))
356 [ - + ]: 401994 : || unlikely ((shdr->sh_addralign ?: 1) < sh_align))
357 : : {
358 : 0 : __libelf_seterrno (ELF_E_INVALID_ALIGN);
359 : 0 : return -1;
360 : : }
361 : : }
362 : : else
363 : : {
364 : : /* How much alignment do we need for this section. */
365 [ + + ]: 1514289 : update_if_changed (shdr->sh_addralign, sh_align,
366 : : scn->shdr_flags);
367 : :
368 : 1514289 : size = (size + sh_align - 1) & ~(sh_align - 1);
369 : 1514289 : int offset_changed = 0;
370 [ + + ]: 1514289 : update_if_changed (shdr->sh_offset, size, offset_changed);
371 : 2502762 : changed |= offset_changed;
372 : :
373 [ + + ]: 988473 : if (offset_changed && scn->data_list_rear == NULL)
374 : : {
375 : : /* The position of the section in the file
376 : : changed. Create the section data list. */
377 [ - + ]: 180 : if (__elf_getdata_rdlock (scn, NULL) == NULL)
378 : : return -1;
379 : : }
380 : :
381 : : /* See whether the section size is correct. */
382 : 1514289 : int size_changed = 0;
383 [ + + ]: 1514289 : update_if_changed (shdr->sh_size,
384 : : (ElfW2(LIBELFBITS,SizeWord)) offset,
385 : : size_changed);
386 : 1514289 : changed |= size_changed;
387 : :
388 [ + + ]: 1514289 : if (shdr->sh_type != SHT_NOBITS)
389 : 1447061 : size += offset;
390 : :
391 : 1514289 : scn->shdr_flags |= (offset_changed | size_changed);
392 : 1514289 : scn->flags |= changed;
393 : : }
394 : :
395 : : /* Check that the section size is actually a multiple of
396 : : the entry size. */
397 [ + + ]: 1916283 : if (shdr->sh_entsize != 0 && shdr->sh_entsize != 1
398 [ + - ]: 26164 : && (elf->flags & ELF_F_PERMISSIVE) == 0)
399 : : {
400 : : /* For compressed sections check the uncompressed size. */
401 : 26164 : ElfW2(LIBELFBITS,SizeWord) sh_size;
402 [ + + ]: 26164 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
403 : 26155 : sh_size = shdr->sh_size;
404 : : else
405 : : {
406 : 9 : ElfW2(LIBELFBITS,Chdr) *chdr;
407 : 9 : chdr = elfw2(LIBELFBITS,getchdr) (scn);
408 [ - + ]: 9 : if (unlikely (chdr == NULL))
409 : : return -1;
410 : 9 : sh_size = chdr->ch_size;
411 : : }
412 : :
413 [ - + ]: 26164 : if (unlikely (sh_size % shdr->sh_entsize != 0))
414 : : {
415 : 0 : __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
416 : 0 : return -1;
417 : : }
418 : : }
419 : : }
420 : :
421 [ + + - + ]: 1668 : assert (list->next == NULL || list->cnt == list->max);
422 : :
423 : 1668 : first = false;
424 : : }
425 [ + + ]: 1668 : while ((list = list->next) != NULL);
426 : :
427 : : /* Store section information. */
428 [ + + ]: 685 : update_if_changed (ehdr->e_shentsize,
429 : : elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), ehdr_flags);
430 [ + + ]: 685 : if (elf->flags & ELF_F_LAYOUT)
431 : : {
432 : : /* The user is supposed to fill out e_shoff. Use it and
433 : : e_shnum (or sh_size of the dummy, first section header)
434 : : to determine the maximum extend. */
435 : 385 : size = MAX (size,
436 : : (ehdr->e_shoff
437 : : + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
438 : : }
439 : : else
440 : : {
441 : : /* Align for section header table.
442 : :
443 : : Yes, we use `sizeof' and not `__alignof__' since we do not
444 : : want to be surprised by architectures with less strict
445 : : alignment rules. */
446 : : #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
447 : 300 : size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
448 : :
449 [ + + ]: 300 : update_if_changed (ehdr->e_shoff, size, elf->flags);
450 : :
451 : : /* Account for the section header size. */
452 : 300 : size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
453 : : }
454 : : }
455 : :
456 : 700 : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
457 : :
458 : 700 : return size;
459 : : }
|