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