blob: 7ac99510568b6b13d1f751a13975cc19710c933a [file] [log] [blame]
Brian Silverman86497922018-02-10 19:28:39 -05001/* Write changed data structures.
2 Copyright (C) 2000-2010, 2014, 2015, 2016 Red Hat, Inc.
3 This file is part of elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
8
9 * the GNU Lesser General Public License as published by the Free
10 Software Foundation; either version 3 of the License, or (at
11 your option) any later version
12
13 or
14
15 * the GNU General Public License as published by the Free
16 Software Foundation; either version 2 of the License, or (at
17 your option) any later version
18
19 or both in parallel, as here.
20
21 elfutils is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
25
26 You should have received copies of the GNU General Public License and
27 the GNU Lesser General Public License along with this program. If
28 not, see <http://www.gnu.org/licenses/>. */
29
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <assert.h>
35#include <errno.h>
36#include <libelf.h>
37#include <stdbool.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include <sys/mman.h>
42
43#include <system.h>
44#include "libelfP.h"
45
46
47#ifndef LIBELFBITS
48# define LIBELFBITS 32
49#endif
50
51
52static int
53compare_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. */
90static void
91sort_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
103static inline void
104fill_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
126int
127internal_function
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#if EV_NUM != 2
147 xfct_t fctp;
148 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
149#else
150# undef fctp
151# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
152#endif
153
154 /* Do the real work. */
155 (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
156 sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
157 }
158 else if (elf->map_address + elf->start_offset != ehdr)
159 memcpy (elf->map_address + elf->start_offset, ehdr,
160 sizeof (ElfW2(LIBELFBITS,Ehdr)));
161
162 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
163
164 /* We start writing sections after the ELF header only if there is
165 no program header. */
166 previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
167 }
168
169 size_t phnum;
170 if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
171 return -1;
172
173 /* Write out the program header table. */
174 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
175 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
176 & ELF_F_DIRTY))
177 {
178 /* If the type sizes should be different at some time we have to
179 rewrite this code. */
180 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
181 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
182
183 /* Maybe the user wants a gap between the ELF header and the program
184 header. */
185 if (ehdr->e_phoff > ehdr->e_ehsize)
186 memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
187 __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
188
189 if (unlikely (change_bo))
190 {
191 /* Today there is only one version of the ELF header. */
192#if EV_NUM != 2
193 xfct_t fctp;
194 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
195#else
196# undef fctp
197# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
198#endif
199
200 /* Do the real work. */
201 (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
202 elf->state.ELFW(elf,LIBELFBITS).phdr,
203 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
204 }
205 else
206 memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
207 elf->state.ELFW(elf,LIBELFBITS).phdr,
208 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
209
210 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
211
212 /* We modified the program header. Maybe this created a gap so
213 we have to write fill bytes, if necessary. */
214 previous_scn_changed = true;
215 }
216
217 /* From now on we have to keep track of the last position to eventually
218 fill the gaps with the prescribed fill byte. */
219 char *last_position = ((char *) elf->map_address + elf->start_offset
220 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
221 ehdr->e_phoff)
222 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
223
224 /* Write all the sections. Well, only those which are modified. */
225 if (shnum > 0)
226 {
227 if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
228 return 1;
229
230 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
231 Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
232 if (unlikely (scns == NULL))
233 {
234 __libelf_seterrno (ELF_E_NOMEM);
235 return -1;
236 }
237 char *const shdr_start = ((char *) elf->map_address + elf->start_offset
238 + ehdr->e_shoff);
239 char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
240
241#if EV_NUM != 2
242 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
243#else
244# undef shdr_fctp
245# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
246#endif
247#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
248
249 /* Get all sections into the array and sort them. */
250 sort_sections (scns, list);
251
252 /* We possibly have to copy the section header data because moving
253 the sections might overwrite the data. */
254 for (size_t cnt = 0; cnt < shnum; ++cnt)
255 {
256 Elf_Scn *scn = scns[cnt];
257
258 if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
259 && (scn->shdr_flags & ELF_F_MALLOCED) == 0
260 && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
261 {
262 assert ((char *) elf->map_address + elf->start_offset
263 < (char *) scn->shdr.ELFW(e,LIBELFBITS));
264 assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
265 < ((char *) elf->map_address + elf->start_offset
266 + elf->maximum_size));
267
268 void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
269 if (unlikely (p == NULL))
270 {
271 free (scns);
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 free (scns);
299 __libelf_seterrno (ELF_E_NOMEM);
300 return -1;
301 }
302 scn->data_list.data.d.d_buf = scn->data_base
303 = memcpy (p, scn->data_list.data.d.d_buf,
304 scn->data_list.data.d.d_size);
305 }
306 }
307
308 /* Iterate over all the section in the order in which they
309 appear in the output file. */
310 for (size_t cnt = 0; cnt < shnum; ++cnt)
311 {
312 Elf_Scn *scn = scns[cnt];
313 if (scn->index == 0)
314 {
315 /* The dummy section header entry. It should not be
316 possible to mark this "section" as dirty. */
317 assert ((scn->flags & ELF_F_DIRTY) == 0);
318 continue;
319 }
320
321 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
322 if (shdr->sh_type == SHT_NOBITS)
323 goto next;
324
325 char *scn_start = ((char *) elf->map_address
326 + elf->start_offset + shdr->sh_offset);
327 Elf_Data_List *dl = &scn->data_list;
328 bool scn_changed = false;
329
330 if (scn->data_list_rear != NULL)
331 do
332 {
333 assert (dl->data.d.d_off >= 0);
334 assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
335 assert (dl->data.d.d_size <= (shdr->sh_size
336 - (GElf_Off) dl->data.d.d_off));
337
338 /* If there is a gap, fill it. */
339 if (scn_start + dl->data.d.d_off > last_position
340 && (dl->data.d.d_off == 0
341 || ((scn->flags | dl->flags | elf->flags)
342 & ELF_F_DIRTY) != 0))
343 {
344 fill_mmap (dl->data.d.d_off, last_position, scn_start,
345 shdr_start, shdr_end);
346 }
347
348 last_position = scn_start + dl->data.d.d_off;
349
350 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
351 {
352 /* Let it go backward if the sections use a bogus
353 layout with overlaps. We'll overwrite the stupid
354 user's section data with the latest one, rather than
355 crashing. */
356
357 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. */
476static int
477fill (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
509int
510internal_function
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 last_offset = scn_start + dl->data.d.d_off;
731
732 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
733 {
734 char tmpbuf[MAX_TMPBUF];
735 void *buf = dl->data.d.d_buf;
736
737 /* Let it go backward if the sections use a bogus
738 layout with overlaps. We'll overwrite the stupid
739 user's section data with the latest one, rather than
740 crashing. */
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}