Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'objtool_urgent_for_v5.18_rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool fixes from Borislav Petkov:
"A bunch of objtool fixes to improve unwinding, sibling call detection,
fallthrough detection and relocation handling of weak symbols when the
toolchain strips section symbols"

* tag 'objtool_urgent_for_v5.18_rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
objtool: Fix code relocs vs weak symbols
objtool: Fix type of reloc::addend
objtool: Fix function fallthrough detection for vmlinux
objtool: Fix sibling call detection in alternatives
objtool: Don't set 'jump_dest' for sibling calls
x86/uaccess: Don't jump between functions

+265 -99
+52 -35
arch/x86/lib/copy_user_64.S
··· 53 53 SYM_FUNC_START(copy_user_generic_unrolled) 54 54 ASM_STAC 55 55 cmpl $8,%edx 56 - jb 20f /* less then 8 bytes, go to byte copy loop */ 56 + jb .Lcopy_user_short_string_bytes 57 57 ALIGN_DESTINATION 58 58 movl %edx,%ecx 59 59 andl $63,%edx 60 60 shrl $6,%ecx 61 - jz .L_copy_short_string 61 + jz copy_user_short_string 62 62 1: movq (%rsi),%r8 63 63 2: movq 1*8(%rsi),%r9 64 64 3: movq 2*8(%rsi),%r10 ··· 79 79 leaq 64(%rdi),%rdi 80 80 decl %ecx 81 81 jnz 1b 82 - .L_copy_short_string: 83 - movl %edx,%ecx 84 - andl $7,%edx 85 - shrl $3,%ecx 86 - jz 20f 87 - 18: movq (%rsi),%r8 88 - 19: movq %r8,(%rdi) 89 - leaq 8(%rsi),%rsi 90 - leaq 8(%rdi),%rdi 91 - decl %ecx 92 - jnz 18b 93 - 20: andl %edx,%edx 94 - jz 23f 95 - movl %edx,%ecx 96 - 21: movb (%rsi),%al 97 - 22: movb %al,(%rdi) 98 - incq %rsi 99 - incq %rdi 100 - decl %ecx 101 - jnz 21b 102 - 23: xor %eax,%eax 103 - ASM_CLAC 104 - RET 82 + jmp copy_user_short_string 105 83 106 84 30: shll $6,%ecx 107 85 addl %ecx,%edx 108 - jmp 60f 109 - 40: leal (%rdx,%rcx,8),%edx 110 - jmp 60f 111 - 50: movl %ecx,%edx 112 - 60: jmp .Lcopy_user_handle_tail /* ecx is zerorest also */ 86 + jmp .Lcopy_user_handle_tail 113 87 114 88 _ASM_EXTABLE_CPY(1b, 30b) 115 89 _ASM_EXTABLE_CPY(2b, 30b) ··· 101 127 _ASM_EXTABLE_CPY(14b, 30b) 102 128 _ASM_EXTABLE_CPY(15b, 30b) 103 129 _ASM_EXTABLE_CPY(16b, 30b) 104 - _ASM_EXTABLE_CPY(18b, 40b) 105 - _ASM_EXTABLE_CPY(19b, 40b) 106 - _ASM_EXTABLE_CPY(21b, 50b) 107 - _ASM_EXTABLE_CPY(22b, 50b) 108 130 SYM_FUNC_END(copy_user_generic_unrolled) 109 131 EXPORT_SYMBOL(copy_user_generic_unrolled) 110 132 ··· 161 191 SYM_FUNC_START(copy_user_enhanced_fast_string) 162 192 ASM_STAC 163 193 /* CPUs without FSRM should avoid rep movsb for short copies */ 164 - ALTERNATIVE "cmpl $64, %edx; jb .L_copy_short_string", "", X86_FEATURE_FSRM 194 + ALTERNATIVE "cmpl $64, %edx; jb copy_user_short_string", "", X86_FEATURE_FSRM 165 195 movl %edx,%ecx 166 196 1: rep movsb 167 197 xorl %eax,%eax ··· 212 242 jmp .Lcopy_user_handle_tail 213 243 214 244 SYM_CODE_END(.Lcopy_user_handle_tail) 245 + 246 + /* 247 + * Finish memcpy of less than 64 bytes. #AC should already be set. 248 + * 249 + * Input: 250 + * rdi destination 251 + * rsi source 252 + * rdx count (< 64) 253 + * 254 + * Output: 255 + * eax uncopied bytes or 0 if successful. 256 + */ 257 + SYM_CODE_START_LOCAL(copy_user_short_string) 258 + movl %edx,%ecx 259 + andl $7,%edx 260 + shrl $3,%ecx 261 + jz .Lcopy_user_short_string_bytes 262 + 18: movq (%rsi),%r8 263 + 19: movq %r8,(%rdi) 264 + leaq 8(%rsi),%rsi 265 + leaq 8(%rdi),%rdi 266 + decl %ecx 267 + jnz 18b 268 + .Lcopy_user_short_string_bytes: 269 + andl %edx,%edx 270 + jz 23f 271 + movl %edx,%ecx 272 + 21: movb (%rsi),%al 273 + 22: movb %al,(%rdi) 274 + incq %rsi 275 + incq %rdi 276 + decl %ecx 277 + jnz 21b 278 + 23: xor %eax,%eax 279 + ASM_CLAC 280 + RET 281 + 282 + 40: leal (%rdx,%rcx,8),%edx 283 + jmp 60f 284 + 50: movl %ecx,%edx /* ecx is zerorest also */ 285 + 60: jmp .Lcopy_user_handle_tail 286 + 287 + _ASM_EXTABLE_CPY(18b, 40b) 288 + _ASM_EXTABLE_CPY(19b, 40b) 289 + _ASM_EXTABLE_CPY(21b, 50b) 290 + _ASM_EXTABLE_CPY(22b, 50b) 291 + SYM_CODE_END(copy_user_short_string) 215 292 216 293 /* 217 294 * copy_user_nocache - Uncached memory copy with exception handling
+44 -37
tools/objtool/check.c
··· 559 559 else if (reloc->addend == reloc->sym->sec->sh.sh_size) { 560 560 insn = find_last_insn(file, reloc->sym->sec); 561 561 if (!insn) { 562 - WARN("can't find unreachable insn at %s+0x%x", 562 + WARN("can't find unreachable insn at %s+0x%lx", 563 563 reloc->sym->sec->name, reloc->addend); 564 564 return -1; 565 565 } 566 566 } else { 567 - WARN("can't find unreachable insn at %s+0x%x", 567 + WARN("can't find unreachable insn at %s+0x%lx", 568 568 reloc->sym->sec->name, reloc->addend); 569 569 return -1; 570 570 } ··· 594 594 else if (reloc->addend == reloc->sym->sec->sh.sh_size) { 595 595 insn = find_last_insn(file, reloc->sym->sec); 596 596 if (!insn) { 597 - WARN("can't find reachable insn at %s+0x%x", 597 + WARN("can't find reachable insn at %s+0x%lx", 598 598 reloc->sym->sec->name, reloc->addend); 599 599 return -1; 600 600 } 601 601 } else { 602 - WARN("can't find reachable insn at %s+0x%x", 602 + WARN("can't find reachable insn at %s+0x%lx", 603 603 reloc->sym->sec->name, reloc->addend); 604 604 return -1; 605 605 } ··· 1271 1271 */ 1272 1272 static int add_jump_destinations(struct objtool_file *file) 1273 1273 { 1274 - struct instruction *insn; 1274 + struct instruction *insn, *jump_dest; 1275 1275 struct reloc *reloc; 1276 1276 struct section *dest_sec; 1277 1277 unsigned long dest_off; 1278 1278 1279 1279 for_each_insn(file, insn) { 1280 + if (insn->jump_dest) { 1281 + /* 1282 + * handle_group_alt() may have previously set 1283 + * 'jump_dest' for some alternatives. 1284 + */ 1285 + continue; 1286 + } 1280 1287 if (!is_static_jump(insn)) 1281 1288 continue; 1282 1289 ··· 1298 1291 add_retpoline_call(file, insn); 1299 1292 continue; 1300 1293 } else if (insn->func) { 1301 - /* internal or external sibling call (with reloc) */ 1294 + /* 1295 + * External sibling call or internal sibling call with 1296 + * STT_FUNC reloc. 1297 + */ 1302 1298 add_call_dest(file, insn, reloc->sym, true); 1303 1299 continue; 1304 1300 } else if (reloc->sym->sec->idx) { ··· 1313 1303 continue; 1314 1304 } 1315 1305 1316 - insn->jump_dest = find_insn(file, dest_sec, dest_off); 1317 - if (!insn->jump_dest) { 1318 - 1319 - /* 1320 - * This is a special case where an alt instruction 1321 - * jumps past the end of the section. These are 1322 - * handled later in handle_group_alt(). 1323 - */ 1324 - if (!strcmp(insn->sec->name, ".altinstr_replacement")) 1325 - continue; 1326 - 1306 + jump_dest = find_insn(file, dest_sec, dest_off); 1307 + if (!jump_dest) { 1327 1308 WARN_FUNC("can't find jump dest instruction at %s+0x%lx", 1328 1309 insn->sec, insn->offset, dest_sec->name, 1329 1310 dest_off); ··· 1324 1323 /* 1325 1324 * Cross-function jump. 1326 1325 */ 1327 - if (insn->func && insn->jump_dest->func && 1328 - insn->func != insn->jump_dest->func) { 1326 + if (insn->func && jump_dest->func && 1327 + insn->func != jump_dest->func) { 1329 1328 1330 1329 /* 1331 1330 * For GCC 8+, create parent/child links for any cold ··· 1343 1342 * subfunction is through a jump table. 1344 1343 */ 1345 1344 if (!strstr(insn->func->name, ".cold") && 1346 - strstr(insn->jump_dest->func->name, ".cold")) { 1347 - insn->func->cfunc = insn->jump_dest->func; 1348 - insn->jump_dest->func->pfunc = insn->func; 1345 + strstr(jump_dest->func->name, ".cold")) { 1346 + insn->func->cfunc = jump_dest->func; 1347 + jump_dest->func->pfunc = insn->func; 1349 1348 1350 - } else if (!same_function(insn, insn->jump_dest) && 1351 - is_first_func_insn(file, insn->jump_dest)) { 1352 - /* internal sibling call (without reloc) */ 1353 - add_call_dest(file, insn, insn->jump_dest->func, true); 1349 + } else if (!same_function(insn, jump_dest) && 1350 + is_first_func_insn(file, jump_dest)) { 1351 + /* 1352 + * Internal sibling call without reloc or with 1353 + * STT_SECTION reloc. 1354 + */ 1355 + add_call_dest(file, insn, jump_dest->func, true); 1356 + continue; 1354 1357 } 1355 1358 } 1359 + 1360 + insn->jump_dest = jump_dest; 1356 1361 } 1357 1362 1358 1363 return 0; ··· 1547 1540 continue; 1548 1541 1549 1542 dest_off = arch_jump_destination(insn); 1550 - if (dest_off == special_alt->new_off + special_alt->new_len) 1543 + if (dest_off == special_alt->new_off + special_alt->new_len) { 1551 1544 insn->jump_dest = next_insn_same_sec(file, last_orig_insn); 1552 - 1553 - if (!insn->jump_dest) { 1554 - WARN_FUNC("can't find alternative jump destination", 1555 - insn->sec, insn->offset); 1556 - return -1; 1545 + if (!insn->jump_dest) { 1546 + WARN_FUNC("can't find alternative jump destination", 1547 + insn->sec, insn->offset); 1548 + return -1; 1549 + } 1557 1550 } 1558 1551 } 1559 1552 ··· 2252 2245 return ret; 2253 2246 2254 2247 /* 2255 - * Must be before add_special_section_alts() as that depends on 2256 - * jump_dest being set. 2248 + * Must be before add_jump_destinations(), which depends on 'func' 2249 + * being set for alternatives, to enable proper sibling call detection. 2257 2250 */ 2258 - ret = add_jump_destinations(file); 2251 + ret = add_special_section_alts(file); 2259 2252 if (ret) 2260 2253 return ret; 2261 2254 2262 - ret = add_special_section_alts(file); 2255 + ret = add_jump_destinations(file); 2263 2256 if (ret) 2264 2257 return ret; 2265 2258 ··· 3310 3303 while (1) { 3311 3304 next_insn = next_insn_to_validate(file, insn); 3312 3305 3313 - if (file->c_file && func && insn->func && func != insn->func->pfunc) { 3306 + if (func && insn->func && func != insn->func->pfunc) { 3314 3307 WARN("%s() falls through to next function %s()", 3315 3308 func->name, insn->func->name); 3316 3309 return 1;
+166 -23
tools/objtool/elf.c
··· 546 546 int reltype); 547 547 548 548 int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, 549 - unsigned int type, struct symbol *sym, int addend) 549 + unsigned int type, struct symbol *sym, long addend) 550 550 { 551 551 struct reloc *reloc; 552 552 ··· 575 575 return 0; 576 576 } 577 577 578 + /* 579 + * Ensure that any reloc section containing references to @sym is marked 580 + * changed such that it will get re-generated in elf_rebuild_reloc_sections() 581 + * with the new symbol index. 582 + */ 583 + static void elf_dirty_reloc_sym(struct elf *elf, struct symbol *sym) 584 + { 585 + struct section *sec; 586 + 587 + list_for_each_entry(sec, &elf->sections, list) { 588 + struct reloc *reloc; 589 + 590 + if (sec->changed) 591 + continue; 592 + 593 + list_for_each_entry(reloc, &sec->reloc_list, list) { 594 + if (reloc->sym == sym) { 595 + sec->changed = true; 596 + break; 597 + } 598 + } 599 + } 600 + } 601 + 602 + /* 603 + * Move the first global symbol, as per sh_info, into a new, higher symbol 604 + * index. This fees up the shndx for a new local symbol. 605 + */ 606 + static int elf_move_global_symbol(struct elf *elf, struct section *symtab, 607 + struct section *symtab_shndx) 608 + { 609 + Elf_Data *data, *shndx_data = NULL; 610 + Elf32_Word first_non_local; 611 + struct symbol *sym; 612 + Elf_Scn *s; 613 + 614 + first_non_local = symtab->sh.sh_info; 615 + 616 + sym = find_symbol_by_index(elf, first_non_local); 617 + if (!sym) { 618 + WARN("no non-local symbols !?"); 619 + return first_non_local; 620 + } 621 + 622 + s = elf_getscn(elf->elf, symtab->idx); 623 + if (!s) { 624 + WARN_ELF("elf_getscn"); 625 + return -1; 626 + } 627 + 628 + data = elf_newdata(s); 629 + if (!data) { 630 + WARN_ELF("elf_newdata"); 631 + return -1; 632 + } 633 + 634 + data->d_buf = &sym->sym; 635 + data->d_size = sizeof(sym->sym); 636 + data->d_align = 1; 637 + data->d_type = ELF_T_SYM; 638 + 639 + sym->idx = symtab->sh.sh_size / sizeof(sym->sym); 640 + elf_dirty_reloc_sym(elf, sym); 641 + 642 + symtab->sh.sh_info += 1; 643 + symtab->sh.sh_size += data->d_size; 644 + symtab->changed = true; 645 + 646 + if (symtab_shndx) { 647 + s = elf_getscn(elf->elf, symtab_shndx->idx); 648 + if (!s) { 649 + WARN_ELF("elf_getscn"); 650 + return -1; 651 + } 652 + 653 + shndx_data = elf_newdata(s); 654 + if (!shndx_data) { 655 + WARN_ELF("elf_newshndx_data"); 656 + return -1; 657 + } 658 + 659 + shndx_data->d_buf = &sym->sec->idx; 660 + shndx_data->d_size = sizeof(Elf32_Word); 661 + shndx_data->d_align = 4; 662 + shndx_data->d_type = ELF_T_WORD; 663 + 664 + symtab_shndx->sh.sh_size += 4; 665 + symtab_shndx->changed = true; 666 + } 667 + 668 + return first_non_local; 669 + } 670 + 671 + static struct symbol * 672 + elf_create_section_symbol(struct elf *elf, struct section *sec) 673 + { 674 + struct section *symtab, *symtab_shndx; 675 + Elf_Data *shndx_data = NULL; 676 + struct symbol *sym; 677 + Elf32_Word shndx; 678 + 679 + symtab = find_section_by_name(elf, ".symtab"); 680 + if (symtab) { 681 + symtab_shndx = find_section_by_name(elf, ".symtab_shndx"); 682 + if (symtab_shndx) 683 + shndx_data = symtab_shndx->data; 684 + } else { 685 + WARN("no .symtab"); 686 + return NULL; 687 + } 688 + 689 + sym = malloc(sizeof(*sym)); 690 + if (!sym) { 691 + perror("malloc"); 692 + return NULL; 693 + } 694 + memset(sym, 0, sizeof(*sym)); 695 + 696 + sym->idx = elf_move_global_symbol(elf, symtab, symtab_shndx); 697 + if (sym->idx < 0) { 698 + WARN("elf_move_global_symbol"); 699 + return NULL; 700 + } 701 + 702 + sym->name = sec->name; 703 + sym->sec = sec; 704 + 705 + // st_name 0 706 + sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); 707 + // st_other 0 708 + // st_value 0 709 + // st_size 0 710 + shndx = sec->idx; 711 + if (shndx >= SHN_UNDEF && shndx < SHN_LORESERVE) { 712 + sym->sym.st_shndx = shndx; 713 + if (!shndx_data) 714 + shndx = 0; 715 + } else { 716 + sym->sym.st_shndx = SHN_XINDEX; 717 + if (!shndx_data) { 718 + WARN("no .symtab_shndx"); 719 + return NULL; 720 + } 721 + } 722 + 723 + if (!gelf_update_symshndx(symtab->data, shndx_data, sym->idx, &sym->sym, shndx)) { 724 + WARN_ELF("gelf_update_symshndx"); 725 + return NULL; 726 + } 727 + 728 + elf_add_symbol(elf, sym); 729 + 730 + return sym; 731 + } 732 + 578 733 int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, 579 734 unsigned long offset, unsigned int type, 580 735 struct section *insn_sec, unsigned long insn_off) 581 736 { 582 - struct symbol *sym; 583 - int addend; 737 + struct symbol *sym = insn_sec->sym; 738 + int addend = insn_off; 584 739 585 - if (insn_sec->sym) { 586 - sym = insn_sec->sym; 587 - addend = insn_off; 588 - 589 - } else { 740 + if (!sym) { 590 741 /* 591 - * The Clang assembler strips section symbols, so we have to 592 - * reference the function symbol instead: 742 + * Due to how weak functions work, we must use section based 743 + * relocations. Symbol based relocations would result in the 744 + * weak and non-weak function annotations being overlaid on the 745 + * non-weak function after linking. 593 746 */ 594 - sym = find_symbol_containing(insn_sec, insn_off); 595 - if (!sym) { 596 - /* 597 - * Hack alert. This happens when we need to reference 598 - * the NOP pad insn immediately after the function. 599 - */ 600 - sym = find_symbol_containing(insn_sec, insn_off - 1); 601 - } 602 - 603 - if (!sym) { 604 - WARN("can't find symbol containing %s+0x%lx", insn_sec->name, insn_off); 747 + sym = elf_create_section_symbol(elf, insn_sec); 748 + if (!sym) 605 749 return -1; 606 - } 607 750 608 - addend = insn_off - sym->offset; 751 + insn_sec->sym = sym; 609 752 } 610 753 611 754 return elf_add_reloc(elf, sec, offset, type, sym, addend);
+2 -2
tools/objtool/include/objtool/elf.h
··· 73 73 struct symbol *sym; 74 74 unsigned long offset; 75 75 unsigned int type; 76 - int addend; 76 + long addend; 77 77 int idx; 78 78 bool jump_table_start; 79 79 }; ··· 135 135 struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr); 136 136 137 137 int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, 138 - unsigned int type, struct symbol *sym, int addend); 138 + unsigned int type, struct symbol *sym, long addend); 139 139 int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, 140 140 unsigned long offset, unsigned int type, 141 141 struct section *insn_sec, unsigned long insn_off);
+1 -1
tools/objtool/include/objtool/objtool.h
··· 27 27 struct list_head static_call_list; 28 28 struct list_head mcount_loc_list; 29 29 struct list_head endbr_list; 30 - bool ignore_unreachables, c_file, hints, rodata; 30 + bool ignore_unreachables, hints, rodata; 31 31 32 32 unsigned int nr_endbr; 33 33 unsigned int nr_endbr_int;
-1
tools/objtool/objtool.c
··· 129 129 INIT_LIST_HEAD(&file.static_call_list); 130 130 INIT_LIST_HEAD(&file.mcount_loc_list); 131 131 INIT_LIST_HEAD(&file.endbr_list); 132 - file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment"); 133 132 file.ignore_unreachables = no_unreachable; 134 133 file.hints = false; 135 134