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