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