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