1 /* ELF program property support. 2 Copyright (C) 2017-2018 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) 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 *listp = list->next; 254 return &list->property; 255 } 256 else if (type < list->property.pr_type) 257 break; 258 listp = &list->next; 259 } 260 261 return NULL; 262 } 263 264 /* Merge GNU property list *LISTP with ABFD. */ 265 266 static void 267 elf_merge_gnu_property_list (struct bfd_link_info *info, bfd *abfd, 268 elf_property_list **listp) 269 { 270 elf_property_list *p, **lastp; 271 elf_property *pr; 272 273 /* Merge each GNU property in ABFD with the one on *LISTP. */ 274 lastp = &elf_properties (abfd); 275 for (p = *lastp; p; p = p->next) 276 { 277 pr = elf_find_and_remove_property (listp, p->property.pr_type); 278 /* Pass NULL to elf_merge_gnu_properties for the property which 279 isn't on *LISTP. */ 280 elf_merge_gnu_properties (info, abfd, &p->property, pr); 281 if (p->property.pr_kind == property_remove) 282 { 283 /* Remove this property. */ 284 *lastp = p->next; 285 continue; 286 } 287 lastp = &p->next; 288 } 289 290 /* Merge the remaining properties on *LISTP with ABFD. */ 291 for (p = *listp; p != NULL; p = p->next) 292 if (elf_merge_gnu_properties (info, abfd, NULL, &p->property)) 293 { 294 if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED) 295 elf_has_no_copy_on_protected (abfd) = TRUE; 296 297 pr = _bfd_elf_get_property (abfd, p->property.pr_type, 298 p->property.pr_datasz); 299 /* It must be a new property. */ 300 if (pr->pr_kind != property_unknown) 301 abort (); 302 /* Add a new property. */ 303 *pr = p->property; 304 } 305 } 306 307 /* Set up GNU properties. Return the first relocatable ELF input with 308 GNU properties if found. Otherwise, return NULL. */ 309 310 bfd * 311 _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) 312 { 313 bfd *abfd, *first_pbfd = NULL; 314 elf_property_list *list; 315 asection *sec; 316 bfd_boolean has_properties = FALSE; 317 const struct elf_backend_data *bed 318 = get_elf_backend_data (info->output_bfd); 319 unsigned int elfclass = bed->s->elfclass; 320 int elf_machine_code = bed->elf_machine_code; 321 322 /* Find the first relocatable ELF input with GNU properties. */ 323 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 324 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour 325 && (abfd->flags & DYNAMIC) == 0 326 && elf_properties (abfd) != NULL) 327 { 328 has_properties = TRUE; 329 330 /* Ignore GNU properties from ELF objects with different machine 331 code or class. Also skip objects without a GNU_PROPERTY note 332 section. */ 333 if ((elf_machine_code 334 == get_elf_backend_data (abfd)->elf_machine_code) 335 && (elfclass 336 == get_elf_backend_data (abfd)->s->elfclass) 337 && bfd_get_section_by_name (abfd, 338 NOTE_GNU_PROPERTY_SECTION_NAME) != NULL 339 ) 340 { 341 /* Keep .note.gnu.property section in FIRST_PBFD. */ 342 first_pbfd = abfd; 343 break; 344 } 345 } 346 347 /* Do nothing if there is no .note.gnu.property section. */ 348 if (!has_properties) 349 return NULL; 350 351 /* Merge .note.gnu.property sections. */ 352 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 353 if (abfd != first_pbfd && (abfd->flags & DYNAMIC) == 0) 354 { 355 elf_property_list *null_ptr = NULL; 356 elf_property_list **listp = &null_ptr; 357 358 /* Merge .note.gnu.property section in relocatable ELF input. */ 359 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) 360 { 361 list = elf_properties (abfd); 362 363 /* Ignore GNU properties from ELF objects with different 364 machine code. */ 365 if (list != NULL 366 && (elf_machine_code 367 == get_elf_backend_data (abfd)->elf_machine_code)) 368 listp = &elf_properties (abfd); 369 } 370 else 371 list = NULL; 372 373 /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL 374 when all properties are from ELF objects with different 375 machine code or class. */ 376 if (first_pbfd != NULL) 377 elf_merge_gnu_property_list (info, first_pbfd, listp); 378 379 if (list != NULL) 380 { 381 /* Discard the .note.gnu.property section in this bfd. */ 382 sec = bfd_get_section_by_name (abfd, 383 NOTE_GNU_PROPERTY_SECTION_NAME); 384 if (sec != NULL) 385 sec->output_section = bfd_abs_section_ptr; 386 } 387 } 388 389 /* Rewrite .note.gnu.property section so that GNU properties are 390 always sorted by type even if input GNU properties aren't sorted. */ 391 if (first_pbfd != NULL) 392 { 393 unsigned int size; 394 unsigned int descsz; 395 bfd_byte *contents; 396 Elf_External_Note *e_note; 397 unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; 398 399 sec = bfd_get_section_by_name (first_pbfd, 400 NOTE_GNU_PROPERTY_SECTION_NAME); 401 BFD_ASSERT (sec != NULL); 402 403 /* Update stack size in .note.gnu.property with -z stack-size=N 404 if N > 0. */ 405 if (info->stacksize > 0) 406 { 407 elf_property *p; 408 bfd_vma stacksize = info->stacksize; 409 410 p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE, 411 align_size); 412 if (p->pr_kind == property_unknown) 413 { 414 /* Create GNU_PROPERTY_STACK_SIZE. */ 415 p->u.number = stacksize; 416 p->pr_kind = property_number; 417 } 418 else if (stacksize > p->u.number) 419 p->u.number = stacksize; 420 } 421 else if (elf_properties (first_pbfd) == NULL) 422 { 423 /* Discard .note.gnu.property section if all properties have 424 been removed. */ 425 sec->output_section = bfd_abs_section_ptr; 426 return NULL; 427 } 428 429 /* Compute the section size. */ 430 descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); 431 descsz = (descsz + 3) & -(unsigned int) 4; 432 size = descsz; 433 for (list = elf_properties (first_pbfd); 434 list != NULL; 435 list = list->next) 436 { 437 /* There are 4 byte type + 4 byte datasz for each property. */ 438 size += 4 + 4 + list->property.pr_datasz; 439 /* Align each property. */ 440 size = (size + (align_size - 1)) & ~(align_size - 1); 441 } 442 443 /* Update .note.gnu.property section now. */ 444 sec->size = size; 445 contents = (bfd_byte *) bfd_zalloc (first_pbfd, size); 446 447 e_note = (Elf_External_Note *) contents; 448 bfd_h_put_32 (first_pbfd, sizeof "GNU", &e_note->namesz); 449 bfd_h_put_32 (first_pbfd, size - descsz, &e_note->descsz); 450 bfd_h_put_32 (first_pbfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type); 451 memcpy (e_note->name, "GNU", sizeof "GNU"); 452 453 size = descsz; 454 for (list = elf_properties (first_pbfd); 455 list != NULL; 456 list = list->next) 457 { 458 /* There are 4 byte type + 4 byte datasz for each property. */ 459 bfd_h_put_32 (first_pbfd, list->property.pr_type, 460 contents + size); 461 bfd_h_put_32 (first_pbfd, list->property.pr_datasz, 462 contents + size + 4); 463 size += 4 + 4; 464 465 /* Write out property value. */ 466 switch (list->property.pr_kind) 467 { 468 case property_number: 469 switch (list->property.pr_datasz) 470 { 471 default: 472 /* Never should happen. */ 473 abort (); 474 475 case 0: 476 break; 477 478 case 4: 479 bfd_h_put_32 (first_pbfd, list->property.u.number, 480 contents + size); 481 break; 482 483 case 8: 484 bfd_h_put_64 (first_pbfd, list->property.u.number, 485 contents + size); 486 break; 487 } 488 break; 489 490 default: 491 /* Never should happen. */ 492 abort (); 493 } 494 size += list->property.pr_datasz; 495 496 /* Align each property. */ 497 size = (size + (align_size - 1)) & ~ (align_size - 1); 498 } 499 500 /* Cache the section contents for elf_link_input_bfd. */ 501 elf_section_data (sec)->this_hdr.contents = contents; 502 503 /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data 504 symbol is defined in the shared object. */ 505 if (elf_has_no_copy_on_protected (first_pbfd)) 506 info->extern_protected_data = FALSE; 507 } 508 509 return first_pbfd; 510 } 511