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