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 (at) 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 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 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 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 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 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 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