1 /* ELF program property support. 2 Copyright (C) 2017-2020 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, bfd *bbfd, 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, bbfd, 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 if RM is 240 true. 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 rm) 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 (rm) 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, abfd, &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 326 /* Remove this property. */ 327 *lastp = p->next; 328 continue; 329 } 330 else if (number_p) 331 { 332 if (pr != NULL) 333 { 334 if (p->property.u.number != number 335 || p->property.u.number != pr->u.number) 336 info->callbacks->minfo 337 (_("Updated property %W (0x%v) to merge %pB (0x%v) " 338 "and %pB (0x%v)\n"), 339 (bfd_vma) p->property.pr_type, p->property.u.number, 340 first_pbfd, number, abfd, pr->u.number); 341 } 342 else 343 { 344 if (p->property.u.number != number) 345 info->callbacks->minfo 346 (_("Updated property %W (%v) to merge %pB (0x%v) " 347 "and %pB (not found)\n"), 348 (bfd_vma) p->property.pr_type, p->property.u.number, 349 first_pbfd, number, abfd); 350 } 351 } 352 lastp = &p->next; 353 } 354 355 /* Merge the remaining properties on *LISTP with FIRST_PBFD. */ 356 for (p = *listp; p != NULL; p = p->next) 357 { 358 if (p->property.pr_kind == property_number) 359 { 360 number_p = TRUE; 361 number = p->property.u.number; 362 } 363 else 364 number_p = FALSE; 365 366 if (elf_merge_gnu_properties (info, first_pbfd, abfd, NULL, &p->property)) 367 { 368 if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED) 369 elf_has_no_copy_on_protected (first_pbfd) = TRUE; 370 371 pr = _bfd_elf_get_property (first_pbfd, p->property.pr_type, 372 p->property.pr_datasz); 373 /* It must be a new property. */ 374 if (pr->pr_kind != property_unknown) 375 abort (); 376 /* Add a new property. */ 377 *pr = p->property; 378 } 379 else 380 { 381 pr = elf_find_and_remove_property (&elf_properties (first_pbfd), 382 p->property.pr_type, 383 FALSE); 384 if (pr == NULL) 385 { 386 if (number_p) 387 info->callbacks->minfo 388 (_("Removed property %W to merge %pB (not found) and " 389 "%pB (0x%v)\n"), 390 (bfd_vma) p->property.pr_type, first_pbfd, abfd, 391 number); 392 else 393 info->callbacks->minfo 394 (_("Removed property %W to merge %pB and %pB\n"), 395 (bfd_vma) p->property.pr_type, first_pbfd, abfd); 396 } 397 else if (pr->pr_kind != property_remove) 398 abort (); 399 } 400 } 401 } 402 403 /* Get GNU property section size. */ 404 405 static bfd_size_type 406 elf_get_gnu_property_section_size (elf_property_list *list, 407 unsigned int align_size) 408 { 409 bfd_size_type size; 410 unsigned int descsz; 411 412 /* Compute the output section size. */ 413 descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); 414 descsz = (descsz + 3) & -(unsigned int) 4; 415 size = descsz; 416 for (; list != NULL; list = list->next) 417 { 418 unsigned int datasz; 419 /* Check if this property should be skipped. */ 420 if (list->property.pr_kind == property_remove) 421 continue; 422 /* There are 4 byte type + 4 byte datasz for each property. */ 423 if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE) 424 datasz = align_size; 425 else 426 datasz = list->property.pr_datasz; 427 size += 4 + 4 + datasz; 428 /* Align each property. */ 429 size = (size + (align_size - 1)) & ~(align_size - 1); 430 } 431 432 return size; 433 } 434 435 /* Write GNU properties. */ 436 437 static void 438 elf_write_gnu_properties (bfd *abfd, bfd_byte *contents, 439 elf_property_list *list, unsigned int size, 440 unsigned int align_size) 441 { 442 unsigned int descsz; 443 unsigned int datasz; 444 Elf_External_Note *e_note; 445 446 e_note = (Elf_External_Note *) contents; 447 descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); 448 descsz = (descsz + 3) & -(unsigned int) 4; 449 bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); 450 bfd_h_put_32 (abfd, size - descsz, &e_note->descsz); 451 bfd_h_put_32 (abfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type); 452 memcpy (e_note->name, "GNU", sizeof "GNU"); 453 454 size = descsz; 455 for (; list != NULL; list = list->next) 456 { 457 /* Check if this property should be skipped. */ 458 if (list->property.pr_kind == property_remove) 459 continue; 460 /* There are 4 byte type + 4 byte datasz for each property. */ 461 if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE) 462 datasz = align_size; 463 else 464 datasz = list->property.pr_datasz; 465 bfd_h_put_32 (abfd, list->property.pr_type, contents + size); 466 bfd_h_put_32 (abfd, datasz, contents + size + 4); 467 size += 4 + 4; 468 469 /* Write out property value. */ 470 switch (list->property.pr_kind) 471 { 472 case property_number: 473 switch (datasz) 474 { 475 default: 476 /* Never should happen. */ 477 abort (); 478 479 case 0: 480 break; 481 482 case 4: 483 bfd_h_put_32 (abfd, list->property.u.number, 484 contents + size); 485 break; 486 487 case 8: 488 bfd_h_put_64 (abfd, list->property.u.number, 489 contents + size); 490 break; 491 } 492 break; 493 494 default: 495 /* Never should happen. */ 496 abort (); 497 } 498 size += datasz; 499 500 /* Align each property. */ 501 size = (size + (align_size - 1)) & ~ (align_size - 1); 502 } 503 } 504 505 /* Set up GNU properties. Return the first relocatable ELF input with 506 GNU properties if found. Otherwise, return NULL. */ 507 508 bfd * 509 _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) 510 { 511 bfd *abfd, *first_pbfd = NULL; 512 elf_property_list *list; 513 asection *sec; 514 bfd_boolean has_properties = FALSE; 515 const struct elf_backend_data *bed 516 = get_elf_backend_data (info->output_bfd); 517 unsigned int elfclass = bed->s->elfclass; 518 int elf_machine_code = bed->elf_machine_code; 519 520 /* Find the first relocatable ELF input with GNU properties. */ 521 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 522 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour 523 && (abfd->flags & DYNAMIC) == 0 524 && elf_properties (abfd) != NULL) 525 { 526 has_properties = TRUE; 527 528 /* Ignore GNU properties from ELF objects with different machine 529 code or class. Also skip objects without a GNU_PROPERTY note 530 section. */ 531 if ((elf_machine_code 532 == get_elf_backend_data (abfd)->elf_machine_code) 533 && (elfclass 534 == get_elf_backend_data (abfd)->s->elfclass) 535 && bfd_get_section_by_name (abfd, 536 NOTE_GNU_PROPERTY_SECTION_NAME) != NULL 537 ) 538 { 539 /* Keep .note.gnu.property section in FIRST_PBFD. */ 540 first_pbfd = abfd; 541 break; 542 } 543 } 544 545 /* Do nothing if there is no .note.gnu.property section. */ 546 if (!has_properties) 547 return NULL; 548 549 /* Merge .note.gnu.property sections. */ 550 info->callbacks->minfo (_("\n")); 551 info->callbacks->minfo (_("Merging program properties\n")); 552 info->callbacks->minfo (_("\n")); 553 554 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 555 if (abfd != first_pbfd 556 && (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0) 557 { 558 elf_property_list *null_ptr = NULL; 559 elf_property_list **listp = &null_ptr; 560 561 /* Merge .note.gnu.property section in relocatable ELF input. */ 562 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) 563 { 564 list = elf_properties (abfd); 565 566 /* Ignore GNU properties from ELF objects with different 567 machine code. */ 568 if (list != NULL 569 && (elf_machine_code 570 == get_elf_backend_data (abfd)->elf_machine_code)) 571 listp = &elf_properties (abfd); 572 } 573 else 574 list = NULL; 575 576 /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL 577 when all properties are from ELF objects with different 578 machine code or class. */ 579 if (first_pbfd != NULL) 580 elf_merge_gnu_property_list (info, first_pbfd, abfd, listp); 581 582 if (list != NULL) 583 { 584 /* Discard the .note.gnu.property section in this bfd. */ 585 sec = bfd_get_section_by_name (abfd, 586 NOTE_GNU_PROPERTY_SECTION_NAME); 587 if (sec != NULL) 588 sec->output_section = bfd_abs_section_ptr; 589 } 590 } 591 592 /* Rewrite .note.gnu.property section so that GNU properties are 593 always sorted by type even if input GNU properties aren't sorted. */ 594 if (first_pbfd != NULL) 595 { 596 bfd_size_type size; 597 bfd_byte *contents; 598 unsigned int align_size = elfclass == ELFCLASS64 ? 8 : 4; 599 600 sec = bfd_get_section_by_name (first_pbfd, 601 NOTE_GNU_PROPERTY_SECTION_NAME); 602 BFD_ASSERT (sec != NULL); 603 604 /* Update stack size in .note.gnu.property with -z stack-size=N 605 if N > 0. */ 606 if (info->stacksize > 0) 607 { 608 elf_property *p; 609 bfd_vma stacksize = info->stacksize; 610 611 p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE, 612 align_size); 613 if (p->pr_kind == property_unknown) 614 { 615 /* Create GNU_PROPERTY_STACK_SIZE. */ 616 p->u.number = stacksize; 617 p->pr_kind = property_number; 618 } 619 else if (stacksize > p->u.number) 620 p->u.number = stacksize; 621 } 622 else if (elf_properties (first_pbfd) == NULL) 623 { 624 /* Discard .note.gnu.property section if all properties have 625 been removed. */ 626 sec->output_section = bfd_abs_section_ptr; 627 return NULL; 628 } 629 630 /* Fix up GNU properties. */ 631 if (bed->fixup_gnu_properties) 632 bed->fixup_gnu_properties (info, &elf_properties (first_pbfd)); 633 634 if (elf_properties (first_pbfd) == NULL) 635 { 636 /* Discard .note.gnu.property section if all properties have 637 been removed. */ 638 sec->output_section = bfd_abs_section_ptr; 639 return NULL; 640 } 641 642 /* Compute the section size. */ 643 list = elf_properties (first_pbfd); 644 size = elf_get_gnu_property_section_size (list, align_size); 645 646 /* Update .note.gnu.property section now. */ 647 sec->size = size; 648 contents = (bfd_byte *) bfd_zalloc (first_pbfd, size); 649 650 elf_write_gnu_properties (first_pbfd, contents, list, size, 651 align_size); 652 653 /* Cache the section contents for elf_link_input_bfd. */ 654 elf_section_data (sec)->this_hdr.contents = contents; 655 656 /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data 657 symbol is defined in the shared object. */ 658 if (elf_has_no_copy_on_protected (first_pbfd)) 659 info->extern_protected_data = FALSE; 660 } 661 662 return first_pbfd; 663 } 664 665 /* Convert GNU property size. */ 666 667 bfd_size_type 668 _bfd_elf_convert_gnu_property_size (bfd *ibfd, bfd *obfd) 669 { 670 unsigned int align_size; 671 const struct elf_backend_data *bed; 672 elf_property_list *list = elf_properties (ibfd); 673 674 bed = get_elf_backend_data (obfd); 675 align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; 676 677 /* Get the output .note.gnu.property section size. */ 678 return elf_get_gnu_property_section_size (list, align_size); 679 } 680 681 /* Convert GNU properties. */ 682 683 bfd_boolean 684 _bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec, 685 bfd *obfd, bfd_byte **ptr, 686 bfd_size_type *ptr_size) 687 { 688 unsigned int size; 689 bfd_byte *contents; 690 unsigned int align_shift; 691 const struct elf_backend_data *bed; 692 elf_property_list *list = elf_properties (ibfd); 693 694 bed = get_elf_backend_data (obfd); 695 align_shift = bed->s->elfclass == ELFCLASS64 ? 3 : 2; 696 697 /* Get the output .note.gnu.property section size. */ 698 size = bfd_section_size (isec->output_section); 699 700 /* Update the output .note.gnu.property section alignment. */ 701 bfd_set_section_alignment (isec->output_section, align_shift); 702 703 if (size > bfd_section_size (isec)) 704 { 705 contents = (bfd_byte *) bfd_malloc (size); 706 if (contents == NULL) 707 return FALSE; 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