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