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