Line data Source code
1 : /* Write changed data structures.
2 : Copyright (C) 2000-2010, 2014, 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 <errno.h>
36 : #include <libelf.h>
37 : #include <stdbool.h>
38 : #include <stdlib.h>
39 : #include <string.h>
40 : #include <unistd.h>
41 : #include <sys/mman.h>
42 :
43 : #include <system.h>
44 : #include "libelfP.h"
45 :
46 :
47 : #ifndef LIBELFBITS
48 : # define LIBELFBITS 32
49 : #endif
50 :
51 :
52 : static int
53 25199387 : compare_sections (const void *a, const void *b)
54 : {
55 25199387 : const Elf_Scn **scna = (const Elf_Scn **) a;
56 25199387 : const Elf_Scn **scnb = (const Elf_Scn **) b;
57 :
58 50398774 : if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
59 25199387 : < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
60 : return -1;
61 :
62 4211 : if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
63 : > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
64 : return 1;
65 :
66 7668 : if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
67 3834 : < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
68 : return -1;
69 :
70 2053 : if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
71 : > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
72 : return 1;
73 :
74 353 : if ((*scna)->index < (*scnb)->index)
75 : return -1;
76 :
77 0 : if ((*scna)->index > (*scnb)->index)
78 : return 1;
79 :
80 0 : return 0;
81 : }
82 :
83 :
84 : /* Insert the sections in the list into the provided array and sort
85 : them according to their start offsets. For sections with equal
86 : start offsets, the size is used; for sections with equal start
87 : offsets and sizes, the section index is used. Sorting by size
88 : ensures that zero-length sections are processed first, which
89 : is what we want since they do not advance our file writing position. */
90 : static void
91 458 : sort_sections (Elf_Scn **scns, Elf_ScnList *list)
92 : {
93 458 : Elf_Scn **scnp = scns;
94 : do
95 3093437 : for (size_t cnt = 0; cnt < list->cnt; ++cnt)
96 3092114 : *scnp++ = &list->data[cnt];
97 1323 : while ((list = list->next) != NULL);
98 :
99 458 : qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
100 458 : }
101 :
102 :
103 : static inline void
104 714 : fill_mmap (size_t offset, char *last_position, char *scn_start,
105 : char *const shdr_start, char *const shdr_end)
106 : {
107 714 : size_t written = 0;
108 :
109 714 : if (last_position < shdr_start)
110 : {
111 712 : written = MIN (scn_start + offset - last_position,
112 : shdr_start - last_position);
113 :
114 712 : memset (last_position, __libelf_fill_byte, written);
115 : }
116 :
117 714 : if (last_position + written != scn_start + offset
118 8 : && shdr_end < scn_start + offset)
119 : {
120 0 : char *fill_start = MAX (shdr_end, scn_start);
121 0 : memset (fill_start, __libelf_fill_byte,
122 0 : scn_start + offset - fill_start);
123 : }
124 714 : }
125 :
126 : int
127 : internal_function
128 187 : __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
129 : {
130 187 : bool previous_scn_changed = false;
131 :
132 : /* We need the ELF header several times. */
133 187 : ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
134 :
135 : /* Write out the ELF header. */
136 187 : if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
137 : {
138 : /* If the type sizes should be different at some time we have to
139 : rewrite this code. */
140 185 : assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
141 : == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
142 :
143 185 : if (unlikely (change_bo))
144 : {
145 : /* Today there is only one version of the ELF header. */
146 : #if EV_NUM != 2
147 : xfct_t fctp;
148 : fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
149 : #else
150 : # undef fctp
151 : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
152 : #endif
153 :
154 : /* Do the real work. */
155 56 : (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
156 : sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
157 : }
158 129 : else if (elf->map_address + elf->start_offset != ehdr)
159 122 : memcpy (elf->map_address + elf->start_offset, ehdr,
160 : sizeof (ElfW2(LIBELFBITS,Ehdr)));
161 :
162 185 : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
163 :
164 : /* We start writing sections after the ELF header only if there is
165 : no program header. */
166 185 : previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
167 : }
168 :
169 : size_t phnum;
170 187 : if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
171 : return -1;
172 :
173 : /* Write out the program header table. */
174 187 : if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
175 152 : && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
176 76 : & ELF_F_DIRTY))
177 : {
178 : /* If the type sizes should be different at some time we have to
179 : rewrite this code. */
180 76 : assert (sizeof (ElfW2(LIBELFBITS,Phdr))
181 : == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
182 :
183 : /* Maybe the user wants a gap between the ELF header and the program
184 : header. */
185 76 : if (ehdr->e_phoff > ehdr->e_ehsize)
186 0 : memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
187 0 : __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
188 :
189 76 : if (unlikely (change_bo))
190 : {
191 : /* Today there is only one version of the ELF header. */
192 : #if EV_NUM != 2
193 : xfct_t fctp;
194 : fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
195 : #else
196 : # undef fctp
197 : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
198 : #endif
199 :
200 : /* Do the real work. */
201 28 : (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
202 14 : elf->state.ELFW(elf,LIBELFBITS).phdr,
203 : sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
204 : }
205 : else
206 124 : memmove (elf->map_address + elf->start_offset + ehdr->e_phoff,
207 62 : elf->state.ELFW(elf,LIBELFBITS).phdr,
208 : sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
209 :
210 76 : elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
211 :
212 : /* We modified the program header. Maybe this created a gap so
213 : we have to write fill bytes, if necessary. */
214 76 : previous_scn_changed = true;
215 : }
216 :
217 : /* From now on we have to keep track of the last position to eventually
218 : fill the gaps with the prescribed fill byte. */
219 374 : char *last_position = ((char *) elf->map_address + elf->start_offset
220 187 : + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
221 : ehdr->e_phoff)
222 187 : + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
223 :
224 : /* Write all the sections. Well, only those which are modified. */
225 187 : if (shnum > 0)
226 : {
227 183 : if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
228 : return 1;
229 :
230 183 : Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
231 183 : Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
232 183 : if (unlikely (scns == NULL))
233 : {
234 0 : __libelf_seterrno (ELF_E_NOMEM);
235 0 : return -1;
236 : }
237 183 : char *const shdr_start = ((char *) elf->map_address + elf->start_offset
238 183 : + ehdr->e_shoff);
239 183 : char *const shdr_end = shdr_start + shnum * ehdr->e_shentsize;
240 :
241 : #if EV_NUM != 2
242 : xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
243 : #else
244 : # undef shdr_fctp
245 : # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
246 : #endif
247 : #define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
248 :
249 : /* Get all sections into the array and sort them. */
250 183 : sort_sections (scns, list);
251 :
252 : /* We possibly have to copy the section header data because moving
253 : the sections might overwrite the data. */
254 792321 : for (size_t cnt = 0; cnt < shnum; ++cnt)
255 : {
256 792138 : Elf_Scn *scn = scns[cnt];
257 :
258 792138 : if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
259 792028 : && (scn->shdr_flags & ELF_F_MALLOCED) == 0
260 105 : && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
261 : {
262 99 : assert ((char *) elf->map_address + elf->start_offset
263 : < (char *) scn->shdr.ELFW(e,LIBELFBITS));
264 99 : assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
265 : < ((char *) elf->map_address + elf->start_offset
266 : + elf->maximum_size));
267 :
268 99 : void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
269 99 : if (unlikely (p == NULL))
270 : {
271 0 : free (scns);
272 0 : __libelf_seterrno (ELF_E_NOMEM);
273 0 : return -1;
274 : }
275 : scn->shdr.ELFW(e,LIBELFBITS)
276 198 : = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
277 : sizeof (ElfW2(LIBELFBITS,Shdr)));
278 : }
279 :
280 : /* If the file is mmaped and the original position of the
281 : section in the file is lower than the new position we
282 : need to save the section content since otherwise it is
283 : overwritten before it can be copied. If there are
284 : multiple data segments in the list only the first can be
285 : from the file. */
286 1584276 : if (((char *) elf->map_address + elf->start_offset
287 792138 : <= (char *) scn->data_list.data.d.d_buf)
288 524704 : && ((char *) scn->data_list.data.d.d_buf
289 : < ((char *) elf->map_address + elf->start_offset
290 524704 : + elf->maximum_size))
291 30 : && (((char *) elf->map_address + elf->start_offset
292 30 : + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
293 : > (char *) scn->data_list.data.d.d_buf))
294 : {
295 1 : void *p = malloc (scn->data_list.data.d.d_size);
296 1 : if (unlikely (p == NULL))
297 : {
298 0 : free (scns);
299 0 : __libelf_seterrno (ELF_E_NOMEM);
300 0 : return -1;
301 : }
302 1 : scn->data_list.data.d.d_buf = scn->data_base
303 2 : = memcpy (p, scn->data_list.data.d.d_buf,
304 : scn->data_list.data.d.d_size);
305 : }
306 : }
307 :
308 : /* Iterate over all the section in the order in which they
309 : appear in the output file. */
310 792138 : for (size_t cnt = 0; cnt < shnum; ++cnt)
311 : {
312 792138 : Elf_Scn *scn = scns[cnt];
313 792138 : if (scn->index == 0)
314 : {
315 : /* The dummy section header entry. It should not be
316 : possible to mark this "section" as dirty. */
317 183 : assert ((scn->flags & ELF_F_DIRTY) == 0);
318 183 : continue;
319 : }
320 :
321 791955 : ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
322 791955 : if (shdr->sh_type == SHT_NOBITS)
323 : goto next;
324 :
325 1581798 : char *scn_start = ((char *) elf->map_address
326 790899 : + elf->start_offset + shdr->sh_offset);
327 790899 : Elf_Data_List *dl = &scn->data_list;
328 790899 : bool scn_changed = false;
329 :
330 790899 : if (scn->data_list_rear != NULL)
331 : do
332 : {
333 790779 : assert (dl->data.d.d_off >= 0);
334 790779 : assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
335 790779 : assert (dl->data.d.d_size <= (shdr->sh_size
336 : - (GElf_Off) dl->data.d.d_off));
337 :
338 : /* If there is a gap, fill it. */
339 790779 : if (scn_start + dl->data.d.d_off > last_position
340 711 : && (dl->data.d.d_off == 0
341 0 : || ((scn->flags | dl->flags | elf->flags)
342 0 : & ELF_F_DIRTY) != 0))
343 : {
344 711 : fill_mmap (dl->data.d.d_off, last_position, scn_start,
345 : shdr_start, shdr_end);
346 : }
347 :
348 790779 : last_position = scn_start + dl->data.d.d_off;
349 :
350 790779 : if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
351 : {
352 : /* Let it go backward if the sections use a bogus
353 : layout with overlaps. We'll overwrite the stupid
354 : user's section data with the latest one, rather than
355 : crashing. */
356 :
357 790771 : if (unlikely (change_bo))
358 : {
359 : #if EV_NUM != 2
360 : xfct_t fctp;
361 : fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
362 : #else
363 : # undef fctp
364 : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
365 : #endif
366 :
367 : /* Do the real work. */
368 262903 : (*fctp) (last_position, dl->data.d.d_buf,
369 : dl->data.d.d_size, 1);
370 :
371 262903 : last_position += dl->data.d.d_size;
372 : }
373 527868 : else if (dl->data.d.d_size != 0)
374 : {
375 1055620 : memmove (last_position, dl->data.d.d_buf,
376 : dl->data.d.d_size);
377 527810 : last_position += dl->data.d.d_size;
378 : }
379 :
380 : scn_changed = true;
381 : }
382 : else
383 8 : last_position += dl->data.d.d_size;
384 :
385 790779 : assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
386 : == last_position);
387 :
388 790779 : dl->flags &= ~ELF_F_DIRTY;
389 :
390 790779 : dl = dl->next;
391 : }
392 790779 : while (dl != NULL);
393 : else
394 : {
395 : /* If the previous section (or the ELF/program
396 : header) changed we might have to fill the gap. */
397 148 : if (scn_start > last_position && previous_scn_changed)
398 3 : fill_mmap (0, last_position, scn_start,
399 : shdr_start, shdr_end);
400 :
401 : /* We have to trust the existing section header information. */
402 148 : last_position = scn_start + shdr->sh_size;
403 : }
404 :
405 :
406 : previous_scn_changed = scn_changed;
407 793011 : next:
408 791955 : scn->flags &= ~ELF_F_DIRTY;
409 : }
410 :
411 : /* Fill the gap between last section and section header table if
412 : necessary. */
413 183 : if ((elf->flags & ELF_F_DIRTY)
414 362 : && last_position < ((char *) elf->map_address + elf->start_offset
415 181 : + ehdr->e_shoff))
416 152 : memset (last_position, __libelf_fill_byte,
417 : (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
418 152 : - last_position);
419 :
420 : /* Write the section header table entry if necessary. */
421 792138 : for (size_t cnt = 0; cnt < shnum; ++cnt)
422 : {
423 792138 : Elf_Scn *scn = scns[cnt];
424 :
425 792138 : if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
426 : {
427 792126 : if (unlikely (change_bo))
428 526388 : (*shdr_fctp) (&shdr_dest[scn->index],
429 263194 : scn->shdr.ELFW(e,LIBELFBITS),
430 : sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
431 : else
432 528932 : memcpy (&shdr_dest[scn->index],
433 528932 : scn->shdr.ELFW(e,LIBELFBITS),
434 : sizeof (ElfW2(LIBELFBITS,Shdr)));
435 :
436 : /* If we previously made a copy of the section header
437 : entry we now have to adjust the pointer again so
438 : point to new place in the mapping. */
439 792126 : if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
440 792022 : && (scn->shdr_flags & ELF_F_MALLOCED) == 0
441 99 : && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
442 : {
443 99 : free (scn->shdr.ELFW(e,LIBELFBITS));
444 99 : scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
445 : }
446 :
447 792126 : scn->shdr_flags &= ~ELF_F_DIRTY;
448 : }
449 : }
450 183 : free (scns);
451 : }
452 :
453 : /* That was the last part. Clear the overall flag. */
454 187 : elf->flags &= ~ELF_F_DIRTY;
455 :
456 : /* Make sure the content hits the disk. */
457 374 : char *msync_start = ((char *) elf->map_address
458 187 : + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
459 374 : char *msync_end = ((char *) elf->map_address
460 187 : + elf->start_offset + ehdr->e_shoff
461 187 : + ehdr->e_shentsize * shnum);
462 187 : (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
463 :
464 187 : return 0;
465 : }
466 :
467 :
468 : /* Size of the buffer we use to generate the blocks of fill bytes. */
469 : #define FILLBUFSIZE 4096
470 :
471 : /* If we have to convert the section buffer contents we have to use
472 : temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
473 : on the stack. */
474 : #define MAX_TMPBUF 32768
475 :
476 :
477 : /* Helper function to write out fill bytes. */
478 : static int
479 1553 : fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
480 : {
481 1553 : size_t filled = *filledp;
482 1553 : size_t fill_len = MIN (len, FILLBUFSIZE);
483 :
484 1553 : if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
485 : {
486 : /* Initialize a few more bytes. */
487 1180 : memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
488 590 : *filledp = filled = fill_len;
489 : }
490 :
491 : do
492 : {
493 : /* This many bytes we want to write in this round. */
494 1884 : size_t n = MIN (filled, len);
495 :
496 1884 : if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
497 : {
498 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
499 0 : return 1;
500 : }
501 :
502 1884 : pos += n;
503 1884 : len -= n;
504 : }
505 1884 : while (len > 0);
506 :
507 : return 0;
508 : }
509 :
510 :
511 : int
512 : internal_function
513 281 : __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
514 : {
515 : char fillbuf[FILLBUFSIZE];
516 281 : size_t filled = 0;
517 281 : bool previous_scn_changed = false;
518 :
519 : /* We need the ELF header several times. */
520 281 : ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
521 :
522 : /* Write out the ELF header. */
523 281 : if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
524 : {
525 : ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
526 279 : ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
527 :
528 : /* If the type sizes should be different at some time we have to
529 : rewrite this code. */
530 279 : assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
531 : == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
532 :
533 279 : if (unlikely (change_bo))
534 : {
535 : /* Today there is only one version of the ELF header. */
536 : #if EV_NUM != 2
537 : xfct_t fctp;
538 : fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
539 : #else
540 : # undef fctp
541 : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
542 : #endif
543 :
544 : /* Write the converted ELF header in a temporary buffer. */
545 111 : (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
546 :
547 : /* This is the buffer we want to write. */
548 111 : out_ehdr = &tmp_ehdr;
549 : }
550 :
551 : /* Write out the ELF header. */
552 279 : if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
553 : sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
554 : != sizeof (ElfW2(LIBELFBITS,Ehdr))))
555 : {
556 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
557 0 : return 1;
558 : }
559 :
560 279 : elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
561 :
562 : /* We start writing sections after the ELF header only if there is
563 : no program header. */
564 279 : previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
565 : }
566 :
567 : /* If the type sizes should be different at some time we have to
568 : rewrite this code. */
569 281 : assert (sizeof (ElfW2(LIBELFBITS,Phdr))
570 : == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
571 :
572 : size_t phnum;
573 281 : if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
574 : return -1;
575 :
576 : /* Write out the program header table. */
577 281 : if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
578 422 : && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
579 211 : & ELF_F_DIRTY))
580 : {
581 211 : ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
582 211 : ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
583 :
584 : /* Maybe the user wants a gap between the ELF header and the program
585 : header. */
586 211 : if (ehdr->e_phoff > ehdr->e_ehsize
587 0 : && unlikely (fill (elf->fildes, ehdr->e_ehsize,
588 : ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
589 : != 0))
590 : return 1;
591 :
592 211 : if (unlikely (change_bo))
593 : {
594 : /* Today there is only one version of the ELF header. */
595 : #if EV_NUM != 2
596 : xfct_t fctp;
597 : fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
598 : #else
599 : # undef fctp
600 : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
601 : #endif
602 :
603 : /* Allocate sufficient memory. */
604 85 : tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
605 85 : malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
606 85 : if (unlikely (tmp_phdr == NULL))
607 : {
608 0 : __libelf_seterrno (ELF_E_NOMEM);
609 0 : return 1;
610 : }
611 :
612 : /* Write the converted ELF header in a temporary buffer. */
613 85 : (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
614 : sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
615 :
616 : /* This is the buffer we want to write. */
617 85 : out_phdr = tmp_phdr;
618 : }
619 :
620 : /* Write out the ELF header. */
621 211 : size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
622 211 : if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
623 : phdr_size, ehdr->e_phoff)
624 : != phdr_size))
625 : {
626 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
627 0 : return 1;
628 : }
629 :
630 : /* This is a no-op we we have not allocated any memory. */
631 211 : free (tmp_phdr);
632 :
633 211 : elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
634 :
635 : /* We modified the program header. Maybe this created a gap so
636 : we have to write fill bytes, if necessary. */
637 211 : previous_scn_changed = true;
638 : }
639 :
640 : /* From now on we have to keep track of the last position to eventually
641 : fill the gaps with the prescribed fill byte. */
642 : off_t last_offset;
643 281 : if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
644 70 : last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
645 : else
646 211 : last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
647 :
648 : /* Write all the sections. Well, only those which are modified. */
649 281 : if (shnum > 0)
650 : {
651 275 : if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
652 : + sizeof (ElfW2(LIBELFBITS,Shdr)))))
653 : return 1;
654 :
655 275 : off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
656 : #if EV_NUM != 2
657 : xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
658 : #else
659 : # undef shdr_fctp
660 : # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
661 : #endif
662 :
663 : ElfW2(LIBELFBITS,Shdr) *shdr_data;
664 275 : ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
665 275 : if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
666 20 : || (elf->flags & ELF_F_DIRTY))
667 : {
668 270 : shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
669 270 : malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
670 270 : if (unlikely (shdr_data_mem == NULL))
671 : {
672 0 : __libelf_seterrno (ELF_E_NOMEM);
673 0 : return -1;
674 : }
675 : shdr_data = shdr_data_mem;
676 : }
677 : else
678 : shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
679 275 : int shdr_flags = elf->flags;
680 :
681 : /* Get all sections into the array and sort them. */
682 275 : Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
683 275 : Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
684 275 : if (unlikely (scns == NULL))
685 : {
686 0 : free (shdr_data_mem);
687 0 : __libelf_seterrno (ELF_E_NOMEM);
688 0 : return -1;
689 : }
690 275 : sort_sections (scns, list);
691 :
692 2300251 : for (size_t cnt = 0; cnt < shnum; ++cnt)
693 : {
694 2299976 : Elf_Scn *scn = scns[cnt];
695 2299976 : if (scn->index == 0)
696 : {
697 : /* The dummy section header entry. It should not be
698 : possible to mark this "section" as dirty. */
699 275 : assert ((scn->flags & ELF_F_DIRTY) == 0);
700 : goto next;
701 : }
702 :
703 2299701 : ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
704 2299701 : if (shdr->sh_type == SHT_NOBITS)
705 : goto next;
706 :
707 2299291 : off_t scn_start = elf->start_offset + shdr->sh_offset;
708 2299291 : Elf_Data_List *dl = &scn->data_list;
709 2299291 : bool scn_changed = false;
710 :
711 2299291 : if (scn->data_list_rear != NULL)
712 : do
713 : {
714 : /* If there is a gap, fill it. */
715 1774546 : if (scn_start + dl->data.d.d_off > last_offset
716 1329 : && ((previous_scn_changed && dl->data.d.d_off == 0)
717 18 : || ((scn->flags | dl->flags | elf->flags)
718 9 : & ELF_F_DIRTY) != 0))
719 : {
720 1325 : if (unlikely (fill (elf->fildes, last_offset,
721 : (scn_start + dl->data.d.d_off)
722 : - last_offset, fillbuf,
723 : &filled) != 0))
724 : {
725 0 : fail_free:
726 0 : free (shdr_data_mem);
727 0 : free (scns);
728 0 : return 1;
729 : }
730 : }
731 :
732 1774546 : last_offset = scn_start + dl->data.d.d_off;
733 :
734 1774546 : if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
735 : {
736 : char tmpbuf[MAX_TMPBUF];
737 1774538 : void *buf = dl->data.d.d_buf;
738 :
739 : /* Let it go backward if the sections use a bogus
740 : layout with overlaps. We'll overwrite the stupid
741 : user's section data with the latest one, rather than
742 : crashing. */
743 :
744 1774538 : if (unlikely (change_bo))
745 : {
746 : #if EV_NUM != 2
747 : xfct_t fctp;
748 : fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
749 : #else
750 : # undef fctp
751 : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
752 : #endif
753 :
754 788152 : buf = tmpbuf;
755 788152 : if (dl->data.d.d_size > MAX_TMPBUF)
756 : {
757 5 : buf = malloc (dl->data.d.d_size);
758 5 : if (unlikely (buf == NULL))
759 : {
760 0 : __libelf_seterrno (ELF_E_NOMEM);
761 0 : goto fail_free;
762 : }
763 : }
764 :
765 : /* Do the real work. */
766 788152 : (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
767 : }
768 :
769 1774538 : ssize_t n = pwrite_retry (elf->fildes, buf,
770 : dl->data.d.d_size,
771 : last_offset);
772 1774538 : if (unlikely ((size_t) n != dl->data.d.d_size))
773 : {
774 0 : if (buf != dl->data.d.d_buf && buf != tmpbuf)
775 0 : free (buf);
776 :
777 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
778 0 : goto fail_free;
779 : }
780 :
781 1774538 : if (buf != dl->data.d.d_buf && buf != tmpbuf)
782 5 : free (buf);
783 :
784 1774538 : scn_changed = true;
785 : }
786 :
787 1774546 : last_offset += dl->data.d.d_size;
788 :
789 1774546 : dl->flags &= ~ELF_F_DIRTY;
790 :
791 1774546 : dl = dl->next;
792 : }
793 1774546 : while (dl != NULL);
794 : else
795 : {
796 : /* If the previous section (or the ELF/program
797 : header) changed we might have to fill the gap. */
798 524771 : if (scn_start > last_offset && previous_scn_changed)
799 : {
800 6 : if (unlikely (fill (elf->fildes, last_offset,
801 : scn_start - last_offset, fillbuf,
802 : &filled) != 0))
803 : goto fail_free;
804 : }
805 :
806 524771 : last_offset = scn_start + shdr->sh_size;
807 : }
808 :
809 : previous_scn_changed = scn_changed;
810 2300386 : next:
811 : /* Collect the section header table information. */
812 2299976 : if (unlikely (change_bo))
813 2101480 : (*shdr_fctp) (&shdr_data[scn->index],
814 1050740 : scn->shdr.ELFW(e,LIBELFBITS),
815 : sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
816 1249236 : else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
817 918018 : || (elf->flags & ELF_F_DIRTY))
818 1249081 : memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
819 : sizeof (ElfW2(LIBELFBITS,Shdr)));
820 :
821 2299976 : shdr_flags |= scn->shdr_flags;
822 2299976 : scn->shdr_flags &= ~ELF_F_DIRTY;
823 : }
824 :
825 : /* Fill the gap between last section and section header table if
826 : necessary. */
827 275 : if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
828 222 : && unlikely (fill (elf->fildes, last_offset,
829 : shdr_offset - last_offset,
830 : fillbuf, &filled) != 0))
831 : goto fail_free;
832 :
833 : /* Write out the section header table. */
834 275 : if (shdr_flags & ELF_F_DIRTY
835 273 : && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
836 : sizeof (ElfW2(LIBELFBITS,Shdr))
837 : * shnum, shdr_offset)
838 : != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
839 : {
840 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
841 0 : goto fail_free;
842 : }
843 :
844 275 : free (shdr_data_mem);
845 275 : free (scns);
846 : }
847 :
848 : /* That was the last part. Clear the overall flag. */
849 281 : elf->flags &= ~ELF_F_DIRTY;
850 :
851 281 : return 0;
852 : }
|