1 /* ELF program property support. 2 Copyright (C) 2017-2019 Free Software Foundation, Inc. 3 4 This file is part of BFD, the Binary File Descriptor library. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21 /* GNU program property draft is at: 22 23 https://github.com/hjl-tools/linux-abi/wiki/property-draft.pdf 24 */ 25 26 #include "sysdep.h" 27 #include "bfd.h" 28 #include "libbfd.h" 29 #include "elf-bfd.h" 30 31 /* Get a property, allocate a new one if needed. */ 32 33 elf_property * 34 _bfd_elf_get_property (bfd *abfd, unsigned int type, unsigned int datasz) 35 { 36 elf_property_list *p, **lastp; 37 38 if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) 39 { 40 /* Never should happen. */ 41 abort (); 42 } 43 44 /* Keep the property list in order of type. */ 45 lastp = &elf_properties (abfd); 46 for (p = *lastp; p; p = p->next) 47 { 48 /* Reuse the existing entry. */ 49 if (type == p->property.pr_type) 50 { 51 if (datasz > p->property.pr_datasz) 52 { 53 /* This can happen when mixing 32-bit and 64-bit objects. */ 54 p->property.pr_datasz = datasz; 55 } 56 return &p->property; 57 } 58 else if (type < p->property.pr_type) 59 break; 60 lastp = &p->next; 61 } 62 p = (elf_property_list *) bfd_alloc (abfd, sizeof (*p)); 63 if (p == NULL) 64 { 65 _bfd_error_handler (_("%pB: out of memory in _bfd_elf_get_property"), 66 abfd); 67 _exit (EXIT_FAILURE); 68 } 69 memset (p, 0, sizeof (*p)); 70 p->property.pr_type = type; 71 p->property.pr_datasz = datasz; 72 p->next = *lastp; 73 *lastp = p; 74 return &p->property; 75 } 76 77 /* Parse GNU properties. */ 78 79 bfd_boolean 80 _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note) 81 { 82 const struct elf_backend_data *bed = get_elf_backend_data (abfd); 83 unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; 84 bfd_byte *ptr = (bfd_byte *) note->descdata; 85 bfd_byte *ptr_end = ptr + note->descsz; 86 87 if (note->descsz < 8 || (note->descsz % align_size) != 0) 88 { 89 bad_size: 90 _bfd_error_handler 91 (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx"), 92 abfd, note->type, note->descsz); 93 return FALSE; 94 } 95 96 while (ptr != ptr_end) 97 { 98 unsigned int type; 99 unsigned int datasz; 100 elf_property *prop; 101 102 if ((size_t) (ptr_end - ptr) < 8) 103 goto bad_size; 104 105 type = bfd_h_get_32 (abfd, ptr); 106 datasz = bfd_h_get_32 (abfd, ptr + 4); 107 ptr += 8; 108 109 if (datasz > (size_t) (ptr_end - ptr)) 110 { 111 _bfd_error_handler 112 (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x"), 113 abfd, note->type, type, datasz); 114 /* Clear all properties. */ 115 elf_properties (abfd) = NULL; 116 return FALSE; 117 } 118 119 if (type >= GNU_PROPERTY_LOPROC) 120 { 121 if (bed->elf_machine_code == EM_NONE) 122 { 123 /* Ignore processor-specific properties with generic ELF 124 target vector. They should be handled by the matching 125 ELF target vector. */ 126 goto next; 127 } 128 else if (type < GNU_PROPERTY_LOUSER 129 && bed->parse_gnu_properties) 130 { 131 enum elf_property_kind kind 132 = bed->parse_gnu_properties (abfd, type, ptr, datasz); 133 if (kind == property_corrupt) 134 { 135 /* Clear all properties. */ 136 elf_properties (abfd) = NULL; 137 return FALSE; 138 } 139 else if (kind != property_ignored) 140 goto next; 141 } 142 } 143 else 144 { 145 switch (type) 146 { 147 case GNU_PROPERTY_STACK_SIZE: 148 if (datasz != align_size) 149 { 150 _bfd_error_handler 151 (_("warning: %pB: corrupt stack size: 0x%x"), 152 abfd, datasz); 153 /* Clear all properties. */ 154 elf_properties (abfd) = NULL; 155 return FALSE; 156 } 157 prop = _bfd_elf_get_property (abfd, type, datasz); 158 if (datasz == 8) 159 prop->u.number = bfd_h_get_64 (abfd, ptr); 160 else 161 prop->u.number = bfd_h_get_32 (abfd, ptr); 162 prop->pr_kind = property_number; 163 goto next; 164 165 case GNU_PROPERTY_NO_COPY_ON_PROTECTED: 166 if (datasz != 0) 167 { 168 _bfd_error_handler 169 (_("warning: %pB: corrupt no copy on protected size: 0x%x"), 170 abfd, datasz); 171 /* Clear all properties. */ 172 elf_properties (abfd) = NULL; 173 return FALSE; 174 } 175 prop = _bfd_elf_get_property (abfd, type, datasz); 176 elf_has_no_copy_on_protected (abfd) = TRUE; 177 prop->pr_kind = property_number; 178 goto next; 179 180 default: 181 break; 182 } 183 } 184 185 _bfd_error_handler 186 (_("warning: %pB: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x"), 187 abfd, note->type, type); 188 189 next: 190 ptr += (datasz + (align_size - 1)) & ~ (align_size - 1); 191 } 192 193 return TRUE; 194 } 195 196 /* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE 197 if APROP is updated. Otherwise, return TRUE if BPROP should be merged 198 with ABFD. */ 199 200 static bfd_boolean 201 elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, 202 elf_property *aprop, elf_property *bprop) 203 { 204 const struct elf_backend_data *bed = get_elf_backend_data (abfd); 205 unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; 206 207 if (bed->merge_gnu_properties != NULL 208 && pr_type >= GNU_PROPERTY_LOPROC 209 && pr_type < GNU_PROPERTY_LOUSER) 210 return bed->merge_gnu_properties (info, abfd, aprop, bprop); 211 212 switch (pr_type) 213 { 214 case GNU_PROPERTY_STACK_SIZE: 215 if (aprop != NULL && bprop != NULL) 216 { 217 if (bprop->u.number > aprop->u.number) 218 { 219 aprop->u.number = bprop->u.number; 220 return TRUE; 221 } 222 break; 223 } 224 /* FALLTHROUGH */ 225 226 case GNU_PROPERTY_NO_COPY_ON_PROTECTED: 227 /* Return TRUE if APROP is NULL to indicate that BPROP should 228 be added to ABFD. */ 229 return aprop == NULL; 230 231 default: 232 /* Never should happen. */ 233 abort (); 234 } 235 236 return FALSE; 237 } 238 239 /* Return the property of TYPE on *LISTP and remove it from *LISTP. 240 Return NULL if not found. */ 241 242 static elf_property * 243 elf_find_and_remove_property (elf_property_list **listp, 244 unsigned int type, bfd_boolean remove) 245 { 246 elf_property_list *list; 247 248 for (list = *listp; list; list = list->next) 249 { 250 if (type == list->property.pr_type) 251 { 252 /* Remove this property. */ 253 if (remove) 254 *listp = list->next; 255 return &list->property; 256 } 257 else if (type < list->property.pr_type) 258 break; 259 listp = &list->next; 260 } 261 262 return NULL; 263 } 264 265 /* Merge GNU property list *LISTP in ABFD with FIRST_PBFD. */ 266 267 static void 268 elf_merge_gnu_property_list (struct bfd_link_info *info, bfd *first_pbfd, 269 bfd *abfd, elf_property_list **listp) 270 { 271 elf_property_list *p, **lastp; 272 elf_property *pr; 273 bfd_boolean number_p; 274 bfd_vma number = 0; 275 276 /* Merge each GNU property in FIRST_PBFD with the one on *LISTP. */ 277 lastp = &elf_properties (first_pbfd); 278 for (p = *lastp; p; p = p->next) 279 if (p->property.pr_kind != property_remove) 280 { 281 if (p->property.pr_kind == property_number) 282 { 283 number_p = TRUE; 284 number = p->property.u.number; 285 } 286 else 287 number_p = FALSE; 288 pr = elf_find_and_remove_property (listp, p->property.pr_type, 289 TRUE); 290 /* Pass NULL to elf_merge_gnu_properties for the property which 291 isn't on *LISTP. */ 292 elf_merge_gnu_properties (info, first_pbfd, &p->property, pr); 293 if (p->property.pr_kind == property_remove) 294 { 295 if (info->has_map_file) 296 { 297 if (number_p) 298 { 299 if (pr != NULL) 300 info->callbacks->minfo 301 (_("Removed property %W to merge %pB (0x%v) " 302 "and %pB (0x%v)\n"), 303 (bfd_vma) p->property.pr_type, first_pbfd, 304 number, abfd, pr->u.number); 305 else 306 info->callbacks->minfo 307 (_("Removed property %W to merge %pB (0x%v) " 308 "and %pB (not found)\n"), 309 (bfd_vma) p->property.pr_type, first_pbfd, 310 number, abfd); 311 } 312 else 313 { 314 if (pr != NULL) 315 info->callbacks->minfo 316 (_("Removed property %W to merge %pB and %pB\n"), 317 (bfd_vma) p->property.pr_type, first_pbfd, abfd); 318 else 319 info->callbacks->minfo 320 (_("Removed property %W to merge %pB and %pB " 321 "(not found)\n"), 322 (bfd_vma) p->property.pr_type, first_pbfd, abfd); 323 } 324 } 325 else 326 { 327 /* Remove this property. */ 328 *lastp = p->next; 329 continue; 330 } 331 } 332 else if (number_p) 333 { 334 if (pr != NULL) 335 { 336 if (p->property.u.number != number 337 || p->property.u.number != pr->u.number) 338 info->callbacks->minfo 339 (_("Updated property %W (0x%v) to merge %pB (0x%v) " 340 "and %pB (0x%v)\n"), 341 (bfd_vma) p->property.pr_type, p->property.u.number, 342 first_pbfd, number, abfd, pr->u.number); 343 } 344 else 345 { 346 if (p->property.u.number != number) 347 info->callbacks->minfo 348 (_("Updated property %W (%v) to merge %pB (0x%v) " 349 "and %pB (not found)\n"), 350 (bfd_vma) p->property.pr_type, p->property.u.number, 351 first_pbfd, number, abfd); 352 } 353 } 354 lastp = &p->next; 355 } 356 357 /* Merge the remaining properties on *LISTP with FIRST_PBFD. */ 358 for (p = *listp; p != NULL; p = p->next) 359 { 360 if (p->property.pr_kind == property_number) 361 { 362 number_p = TRUE; 363 number = p->property.u.number; 364 } 365 else 366 number_p = FALSE; 367 368 if (elf_merge_gnu_properties (info, first_pbfd, NULL, &p->property)) 369 { 370 if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED) 371 elf_has_no_copy_on_protected (first_pbfd) = TRUE; 372 373 pr = _bfd_elf_get_property (first_pbfd, p->property.pr_type, 374 p->property.pr_datasz); 375 /* It must be a new property. */ 376 if (pr->pr_kind != property_unknown) 377 abort (); 378 /* Add a new property. */ 379 *pr = p->property; 380 } 381 else 382 { 383 pr = elf_find_and_remove_property (&elf_properties (first_pbfd), 384 p->property.pr_type, 385 FALSE); 386 if (pr == NULL) 387 { 388 if (number_p) 389 info->callbacks->minfo 390 (_("Removed property %W to merge %pB (not found) and " 391 "%pB (0x%v)\n"), 392 (bfd_vma) p->property.pr_type, first_pbfd, abfd, 393 number); 394 else 395 info->callbacks->minfo 396 (_("Removed property %W to merge %pB and %pB\n"), 397 (bfd_vma) p->property.pr_type, first_pbfd, abfd); 398 } 399 else if (pr->pr_kind != property_remove) 400 abort (); 401 } 402 } 403 } 404 405 /* Get GNU property section size. */ 406 407 static bfd_size_type 408 elf_get_gnu_property_section_size (elf_property_list *list, 409 unsigned int align_size) 410 { 411 bfd_size_type size; 412 unsigned int descsz; 413 414 /* Compute the output section size. */ 415 descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); 416 descsz = (descsz + 3) & -(unsigned int) 4; 417 size = descsz; 418 for (; list != NULL; list = list->next) 419 { 420 unsigned int datasz; 421 /* Check if this property should be skipped. */ 422 if (list->property.pr_kind == property_remove) 423 continue; 424 /* There are 4 byte type + 4 byte datasz for each property. */ 425 if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE) 426 datasz = align_size; 427 else 428 datasz = list->property.pr_datasz; 429 size += 4 + 4 + datasz; 430 /* Align each property. */ 431 size = (size + (align_size - 1)) & ~(align_size - 1); 432 } 433 434 return size; 435 } 436 437 /* Write GNU properties. */ 438 439 static void 440 elf_write_gnu_properties (bfd *abfd, bfd_byte *contents, 441 elf_property_list *list, unsigned int size, 442 unsigned int align_size) 443 { 444 unsigned int descsz; 445 unsigned int datasz; 446 Elf_External_Note *e_note; 447 448 e_note = (Elf_External_Note *) contents; 449 descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); 450 descsz = (descsz + 3) & -(unsigned int) 4; 451 bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); 452 bfd_h_put_32 (abfd, size - descsz, &e_note->descsz); 453 bfd_h_put_32 (abfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type); 454 memcpy (e_note->name, "GNU", sizeof "GNU"); 455 456 size = descsz; 457 for (; list != NULL; list = list->next) 458 { 459 /* Check if this property should be skipped. */ 460 if (list->property.pr_kind == property_remove) 461 continue; 462 /* There are 4 byte type + 4 byte datasz for each property. */ 463 if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE) 464 datasz = align_size; 465 else 466 datasz = list->property.pr_datasz; 467 bfd_h_put_32 (abfd, list->property.pr_type, contents + size); 468 bfd_h_put_32 (abfd, datasz, contents + size + 4); 469 size += 4 + 4; 470 471 /* Write out property value. */ 472 switch (list->property.pr_kind) 473 { 474 case property_number: 475 switch (datasz) 476 { 477 default: 478 /* Never should happen. */ 479 abort (); 480 481 case 0: 482 break; 483 484 case 4: 485 bfd_h_put_32 (abfd, list->property.u.number, 486 contents + size); 487 break; 488 489 case 8: 490 bfd_h_put_64 (abfd, list->property.u.number, 491 contents + size); 492 break; 493 } 494 break; 495 496 default: 497 /* Never should happen. */ 498 abort (); 499 } 500 size += datasz; 501 502 /* Align each property. */ 503 size = (size + (align_size - 1)) & ~ (align_size - 1); 504 } 505 } 506 507 /* Set up GNU properties. Return the first relocatable ELF input with 508 GNU properties if found. Otherwise, return NULL. */ 509 510 bfd * 511 _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) 512 { 513 bfd *abfd, *first_pbfd = NULL; 514 elf_property_list *list; 515 asection *sec; 516 bfd_boolean has_properties = FALSE; 517 const struct elf_backend_data *bed 518 = get_elf_backend_data (info->output_bfd); 519 unsigned int elfclass = bed->s->elfclass; 520 int elf_machine_code = bed->elf_machine_code; 521 522 /* Find the first relocatable ELF input with GNU properties. */ 523 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 524 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour 525 && (abfd->flags & DYNAMIC) == 0 526 && elf_properties (abfd) != NULL) 527 { 528 has_properties = TRUE; 529 530 /* Ignore GNU properties from ELF objects with different machine 531 code or class. Also skip objects without a GNU_PROPERTY note 532 section. */ 533 if ((elf_machine_code 534 == get_elf_backend_data (abfd)->elf_machine_code) 535 && (elfclass 536 == get_elf_backend_data (abfd)->s->elfclass) 537 && bfd_get_section_by_name (abfd, 538 NOTE_GNU_PROPERTY_SECTION_NAME) != NULL 539 ) 540 { 541 /* Keep .note.gnu.property section in FIRST_PBFD. */ 542 first_pbfd = abfd; 543 break; 544 } 545 } 546 547 /* Do nothing if there is no .note.gnu.property section. */ 548 if (!has_properties) 549 return NULL; 550 551 /* Merge .note.gnu.property sections. */ 552 info->callbacks->minfo (_("\n")); 553 info->callbacks->minfo (_("Merging program properties\n")); 554 info->callbacks->minfo (_("\n")); 555 556 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 557 if (abfd != first_pbfd 558 && (abfd->flags & (DYNAMIC | BFD_PLUGIN)) == 0) 559 { 560 elf_property_list *null_ptr = NULL; 561 elf_property_list **listp = &null_ptr; 562 563 /* Merge .note.gnu.property section in relocatable ELF input. */ 564 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) 565 { 566 list = elf_properties (abfd); 567 568 /* Ignore GNU properties from ELF objects with different 569 machine code. */ 570 if (list != NULL 571 && (elf_machine_code 572 == get_elf_backend_data (abfd)->elf_machine_code)) 573 listp = &elf_properties (abfd); 574 } 575 else 576 list = NULL; 577 578 /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL 579 when all properties are from ELF objects with different 580 machine code or class. */ 581 if (first_pbfd != NULL) 582 elf_merge_gnu_property_list (info, first_pbfd, abfd, listp); 583 584 if (list != NULL) 585 { 586 /* Discard the .note.gnu.property section in this bfd. */ 587 sec = bfd_get_section_by_name (abfd, 588 NOTE_GNU_PROPERTY_SECTION_NAME); 589 if (sec != NULL) 590 sec->output_section = bfd_abs_section_ptr; 591 } 592 } 593 594 /* Rewrite .note.gnu.property section so that GNU properties are 595 always sorted by type even if input GNU properties aren't sorted. */ 596 if (first_pbfd != NULL) 597 { 598 bfd_size_type size; 599 bfd_byte *contents; 600 unsigned int align_size = elfclass == ELFCLASS64 ? 8 : 4; 601 602 sec = bfd_get_section_by_name (first_pbfd, 603 NOTE_GNU_PROPERTY_SECTION_NAME); 604 BFD_ASSERT (sec != NULL); 605 606 /* Update stack size in .note.gnu.property with -z stack-size=N 607 if N > 0. */ 608 if (info->stacksize > 0) 609 { 610 elf_property *p; 611 bfd_vma stacksize = info->stacksize; 612 613 p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE, 614 align_size); 615 if (p->pr_kind == property_unknown) 616 { 617 /* Create GNU_PROPERTY_STACK_SIZE. */ 618 p->u.number = stacksize; 619 p->pr_kind = property_number; 620 } 621 else if (stacksize > p->u.number) 622 p->u.number = stacksize; 623 } 624 else if (elf_properties (first_pbfd) == NULL) 625 { 626 /* Discard .note.gnu.property section if all properties have 627 been removed. */ 628 sec->output_section = bfd_abs_section_ptr; 629 return NULL; 630 } 631 632 /* Fix up GNU properties. */ 633 if (bed->fixup_gnu_properties) 634 bed->fixup_gnu_properties (info, &elf_properties (first_pbfd)); 635 636 if (elf_properties (first_pbfd) == NULL) 637 { 638 /* Discard .note.gnu.property section if all properties have 639 been removed. */ 640 sec->output_section = bfd_abs_section_ptr; 641 return NULL; 642 } 643 644 /* Compute the section size. */ 645 list = elf_properties (first_pbfd); 646 size = elf_get_gnu_property_section_size (list, align_size); 647 648 /* Update .note.gnu.property section now. */ 649 sec->size = size; 650 contents = (bfd_byte *) bfd_zalloc (first_pbfd, size); 651 652 elf_write_gnu_properties (first_pbfd, contents, list, size, 653 align_size); 654 655 /* Cache the section contents for elf_link_input_bfd. */ 656 elf_section_data (sec)->this_hdr.contents = contents; 657 658 /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data 659 symbol is defined in the shared object. */ 660 if (elf_has_no_copy_on_protected (first_pbfd)) 661 info->extern_protected_data = FALSE; 662 } 663 664 return first_pbfd; 665 } 666 667 /* Convert GNU property size. */ 668 669 bfd_size_type 670 _bfd_elf_convert_gnu_property_size (bfd *ibfd, bfd *obfd) 671 { 672 unsigned int align_size; 673 const struct elf_backend_data *bed; 674 elf_property_list *list = elf_properties (ibfd); 675 676 bed = get_elf_backend_data (obfd); 677 align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; 678 679 /* Get the output .note.gnu.property section size. */ 680 return elf_get_gnu_property_section_size (list, align_size); 681 } 682 683 /* Convert GNU properties. */ 684 685 bfd_boolean 686 _bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec, 687 bfd *obfd, bfd_byte **ptr, 688 bfd_size_type *ptr_size) 689 { 690 unsigned int size; 691 bfd_byte *contents; 692 unsigned int align_shift; 693 const struct elf_backend_data *bed; 694 elf_property_list *list = elf_properties (ibfd); 695 696 bed = get_elf_backend_data (obfd); 697 align_shift = bed->s->elfclass == ELFCLASS64 ? 3 : 2; 698 699 /* Get the output .note.gnu.property section size. */ 700 size = bfd_get_section_size (isec->output_section); 701 702 /* Update the output .note.gnu.property section alignment. */ 703 bfd_set_section_alignment (obfd, isec->output_section, align_shift); 704 705 if (size > bfd_get_section_size (isec)) 706 { 707 contents = (bfd_byte *) bfd_malloc (size); 708 free (*ptr); 709 *ptr = contents; 710 } 711 else 712 contents = *ptr; 713 714 *ptr_size = size; 715 716 /* Generate the output .note.gnu.property section. */ 717 elf_write_gnu_properties (ibfd, contents, list, size, 1 << align_shift); 718 719 return TRUE; 720 } 721