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