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. */
364 size_t size = dl->data.d.d_size;
365 char *converted = aligned_alloc (align, size);
366 if (converted == NULL)
367 {
368 __libelf_seterrno (ELF_E_NOMEM);
369 return 1;
370 }
371 (*fctp) (converted, dl->data.d.d_buf, size, 1);
372
373 /* And then write it to the mmapped file. */
374 memcpy (last_position, converted, size);
375 free (converted);
376 }
377
378 last_position += dl->data.d.d_size;
379 }
380 else if (dl->data.d.d_size != 0)
381 {
382 memmove (last_position, dl->data.d.d_buf,
383 dl->data.d.d_size);
384 last_position += dl->data.d.d_size;
385 }
386
387 scn_changed = true;
388 }
389 else
390 last_position += dl->data.d.d_size;
391
392 assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
393 == last_position);
394
395 dl->flags &= ~ELF_F_DIRTY;
396
397 dl = dl->next;
398 }
399 while (dl != NULL);
400 else
401 {
402 /* If the previous section (or the ELF/program
403 header) changed we might have to fill the gap. */
404 if (scn_start > last_position && previous_scn_changed)
405 fill_mmap (0, last_position, scn_start,
406 shdr_start, shdr_end);
407
408 /* We have to trust the existing section header information. */
409 last_position = scn_start + shdr->sh_size;
410 }
411
412
413 previous_scn_changed = scn_changed;
414 next:
415 scn->flags &= ~ELF_F_DIRTY;
416 }
417
418 /* Fill the gap between last section and section header table if
419 necessary. */
420 if ((elf->flags & ELF_F_DIRTY)
421 && last_position < ((char *) elf->map_address + elf->start_offset
422 + ehdr->e_shoff))
423 memset (last_position, __libelf_fill_byte,
424 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
425 - last_position);
426
427 /* Write the section header table entry if necessary. */
428 for (size_t cnt = 0; cnt < shnum; ++cnt)
429 {
430 Elf_Scn *scn = scns[cnt];
431
432 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
433 {
434 if (unlikely (change_bo))
435 (*shdr_fctp) (&shdr_dest[scn->index],
436 scn->shdr.ELFW(e,LIBELFBITS),
437 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
438 else
439 memcpy (&shdr_dest[scn->index],
440 scn->shdr.ELFW(e,LIBELFBITS),
441 sizeof (ElfW2(LIBELFBITS,Shdr)));
442
443 /* If we previously made a copy of the section header
444 entry we now have to adjust the pointer again so
445 point to new place in the mapping. */
446 if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
447 && (scn->shdr_flags & ELF_F_MALLOCED) == 0
448 && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
449 {
450 free (scn->shdr.ELFW(e,LIBELFBITS));
451 scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
452 }
453
454 scn->shdr_flags &= ~ELF_F_DIRTY;
455 }
456 }
457 free (scns);
458 }
459
460 /* That was the last part. Clear the overall flag. */
461 elf->flags &= ~ELF_F_DIRTY;
462
463 /* Make sure the content hits the disk. */
464 char *msync_start = ((char *) elf->map_address
465 + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
466 char *msync_end = ((char *) elf->map_address
467 + elf->start_offset + ehdr->e_shoff
468 + ehdr->e_shentsize * shnum);
469 (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
470
471 return 0;
472 }
473
474
475 /* Size of the buffer we use to generate the blocks of fill bytes. */
476 #define FILLBUFSIZE 4096
477
478 /* If we have to convert the section buffer contents we have to use
479 temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
480 on the stack. */
481 #define MAX_TMPBUF 32768
482
483
484 /* Helper function to write out fill bytes. */
485 static int
fill(int fd,off_t pos,size_t len,char * fillbuf,size_t * filledp)486 fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
487 {
488 size_t filled = *filledp;
489 size_t fill_len = MIN (len, FILLBUFSIZE);
490
491 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
492 {
493 /* Initialize a few more bytes. */
494 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
495 *filledp = filled = fill_len;
496 }
497
498 do
499 {
500 /* This many bytes we want to write in this round. */
501 size_t n = MIN (filled, len);
502
503 if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
504 {
505 __libelf_seterrno (ELF_E_WRITE_ERROR);
506 return 1;
507 }
508
509 pos += n;
510 len -= n;
511 }
512 while (len > 0);
513
514 return 0;
515 }
516
517
518 int
519 internal_function
__elfw2(LIBELFBITS,updatefile)520 __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
521 {
522 char fillbuf[FILLBUFSIZE];
523 size_t filled = 0;
524 bool previous_scn_changed = false;
525
526 /* We need the ELF header several times. */
527 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
528
529 /* Write out the ELF header. */
530 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
531 {
532 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
533 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
534
535 /* If the type sizes should be different at some time we have to
536 rewrite this code. */
537 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
538 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
539
540 if (unlikely (change_bo))
541 {
542 /* Today there is only one version of the ELF header. */
543 #undef fctp
544 #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
545
546 /* Write the converted ELF header in a temporary buffer. */
547 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
548
549 /* This is the buffer we want to write. */
550 out_ehdr = &tmp_ehdr;
551 }
552
553 /* Write out the ELF header. */
554 if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
555 sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
556 != sizeof (ElfW2(LIBELFBITS,Ehdr))))
557 {
558 __libelf_seterrno (ELF_E_WRITE_ERROR);
559 return 1;
560 }
561
562 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
563
564 /* We start writing sections after the ELF header only if there is
565 no program header. */
566 previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
567 }
568
569 /* If the type sizes should be different at some time we have to
570 rewrite this code. */
571 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
572 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
573
574 size_t phnum;
575 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
576 return -1;
577
578 /* Write out the program header table. */
579 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
580 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
581 & ELF_F_DIRTY))
582 {
583 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
584 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
585
586 /* Maybe the user wants a gap between the ELF header and the program
587 header. */
588 if (ehdr->e_phoff > ehdr->e_ehsize
589 && unlikely (fill (elf->fildes, ehdr->e_ehsize,
590 ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
591 != 0))
592 return 1;
593
594 if (unlikely (change_bo))
595 {
596 /* Today there is only one version of the ELF header. */
597 #undef fctp
598 #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
599
600 /* Allocate sufficient memory. */
601 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
602 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
603 if (unlikely (tmp_phdr == NULL))
604 {
605 __libelf_seterrno (ELF_E_NOMEM);
606 return 1;
607 }
608
609 /* Write the converted ELF header in a temporary buffer. */
610 (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
611 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
612
613 /* This is the buffer we want to write. */
614 out_phdr = tmp_phdr;
615 }
616
617 /* Write out the ELF header. */
618 size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
619 if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
620 phdr_size, ehdr->e_phoff)
621 != phdr_size))
622 {
623 __libelf_seterrno (ELF_E_WRITE_ERROR);
624 return 1;
625 }
626
627 /* This is a no-op we we have not allocated any memory. */
628 free (tmp_phdr);
629
630 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
631
632 /* We modified the program header. Maybe this created a gap so
633 we have to write fill bytes, if necessary. */
634 previous_scn_changed = true;
635 }
636
637 /* From now on we have to keep track of the last position to eventually
638 fill the gaps with the prescribed fill byte. */
639 off_t last_offset;
640 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
641 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
642 else
643 last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
644
645 /* Write all the sections. Well, only those which are modified. */
646 if (shnum > 0)
647 {
648 if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
649 + sizeof (ElfW2(LIBELFBITS,Shdr)))))
650 return 1;
651
652 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
653 #undef shdr_fctp
654 #define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
655
656 ElfW2(LIBELFBITS,Shdr) *shdr_data;
657 ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
658 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
659 || (elf->flags & ELF_F_DIRTY))
660 {
661 shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
662 malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
663 if (unlikely (shdr_data_mem == NULL))
664 {
665 __libelf_seterrno (ELF_E_NOMEM);
666 return -1;
667 }
668 shdr_data = shdr_data_mem;
669 }
670 else
671 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
672 int shdr_flags = elf->flags;
673
674 /* Get all sections into the array and sort them. */
675 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
676 Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
677 if (unlikely (scns == NULL))
678 {
679 free (shdr_data_mem);
680 __libelf_seterrno (ELF_E_NOMEM);
681 return -1;
682 }
683 sort_sections (scns, list);
684
685 for (size_t cnt = 0; cnt < shnum; ++cnt)
686 {
687 Elf_Scn *scn = scns[cnt];
688 if (scn->index == 0)
689 {
690 /* The dummy section header entry. It should not be
691 possible to mark this "section" as dirty. */
692 assert ((scn->flags & ELF_F_DIRTY) == 0);
693 goto next;
694 }
695
696 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
697 if (shdr->sh_type == SHT_NOBITS)
698 goto next;
699
700 off_t scn_start = elf->start_offset + shdr->sh_offset;
701 Elf_Data_List *dl = &scn->data_list;
702 bool scn_changed = false;
703
704 if (scn->data_list_rear != NULL)
705 do
706 {
707 /* If there is a gap, fill it. */
708 if (scn_start + dl->data.d.d_off > last_offset
709 && ((previous_scn_changed && dl->data.d.d_off == 0)
710 || ((scn->flags | dl->flags | elf->flags)
711 & ELF_F_DIRTY) != 0))
712 {
713 if (unlikely (fill (elf->fildes, last_offset,
714 (scn_start + dl->data.d.d_off)
715 - last_offset, fillbuf,
716 &filled) != 0))
717 {
718 fail_free:
719 free (shdr_data_mem);
720 free (scns);
721 return 1;
722 }
723 }
724
725 last_offset = scn_start + dl->data.d.d_off;
726
727 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
728 {
729 char tmpbuf[MAX_TMPBUF];
730 void *buf = dl->data.d.d_buf;
731
732 /* Let it go backward if the sections use a bogus
733 layout with overlaps. We'll overwrite the stupid
734 user's section data with the latest one, rather than
735 crashing. */
736
737 if (unlikely (change_bo))
738 {
739 #undef fctp
740 #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
741
742 buf = tmpbuf;
743 if (dl->data.d.d_size > MAX_TMPBUF)
744 {
745 buf = malloc (dl->data.d.d_size);
746 if (unlikely (buf == NULL))
747 {
748 __libelf_seterrno (ELF_E_NOMEM);
749 goto fail_free;
750 }
751 }
752
753 /* Do the real work. */
754 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
755 }
756
757 ssize_t n = pwrite_retry (elf->fildes, buf,
758 dl->data.d.d_size,
759 last_offset);
760 if (unlikely ((size_t) n != dl->data.d.d_size))
761 {
762 if (buf != dl->data.d.d_buf && buf != tmpbuf)
763 free (buf);
764
765 __libelf_seterrno (ELF_E_WRITE_ERROR);
766 goto fail_free;
767 }
768
769 if (buf != dl->data.d.d_buf && buf != tmpbuf)
770 free (buf);
771
772 scn_changed = true;
773 }
774
775 last_offset += dl->data.d.d_size;
776
777 dl->flags &= ~ELF_F_DIRTY;
778
779 dl = dl->next;
780 }
781 while (dl != NULL);
782 else
783 {
784 /* If the previous section (or the ELF/program
785 header) changed we might have to fill the gap. */
786 if (scn_start > last_offset && previous_scn_changed)
787 {
788 if (unlikely (fill (elf->fildes, last_offset,
789 scn_start - last_offset, fillbuf,
790 &filled) != 0))
791 goto fail_free;
792 }
793
794 last_offset = scn_start + shdr->sh_size;
795 }
796
797 previous_scn_changed = scn_changed;
798 next:
799 /* Collect the section header table information. */
800 if (unlikely (change_bo))
801 (*shdr_fctp) (&shdr_data[scn->index],
802 scn->shdr.ELFW(e,LIBELFBITS),
803 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
804 else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
805 || (elf->flags & ELF_F_DIRTY))
806 memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
807 sizeof (ElfW2(LIBELFBITS,Shdr)));
808
809 shdr_flags |= scn->shdr_flags;
810 scn->shdr_flags &= ~ELF_F_DIRTY;
811 }
812
813 /* Fill the gap between last section and section header table if
814 necessary. */
815 if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
816 && unlikely (fill (elf->fildes, last_offset,
817 shdr_offset - last_offset,
818 fillbuf, &filled) != 0))
819 goto fail_free;
820
821 /* Write out the section header table. */
822 if (shdr_flags & ELF_F_DIRTY
823 && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
824 sizeof (ElfW2(LIBELFBITS,Shdr))
825 * shnum, shdr_offset)
826 != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
827 {
828 __libelf_seterrno (ELF_E_WRITE_ERROR);
829 goto fail_free;
830 }
831
832 free (shdr_data_mem);
833 free (scns);
834 }
835
836 /* That was the last part. Clear the overall flag. */
837 elf->flags &= ~ELF_F_DIRTY;
838
839 return 0;
840 }
841