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.

objtool: Add base objtool support for livepatch modules

In preparation for klp-build, enable "classic" objtool to work on
livepatch modules:

- Avoid duplicate symbol/section warnings for prefix symbols and the
.static_call_sites and __mcount_loc sections which may have already
been extracted by klp diff.

- Add __klp_funcs to the IBT function pointer section whitelist.

- Prevent KLP symbols from getting incorrectly classified as cold
subfunctions.

Acked-by: Petr Mladek <pmladek@suse.com>
Tested-by: Joe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

+53 -7
+47 -5
tools/objtool/check.c
··· 3 3 * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> 4 4 */ 5 5 6 + #define _GNU_SOURCE /* memmem() */ 6 7 #include <string.h> 7 8 #include <stdlib.h> 8 9 #include <inttypes.h> ··· 612 611 return 0; 613 612 } 614 613 614 + static bool is_livepatch_module(struct objtool_file *file) 615 + { 616 + struct section *sec; 617 + 618 + if (!opts.module) 619 + return false; 620 + 621 + sec = find_section_by_name(file->elf, ".modinfo"); 622 + if (!sec) 623 + return false; 624 + 625 + return memmem(sec->data->d_buf, sec_size(sec), "\0livepatch=Y", 12); 626 + } 627 + 615 628 static int create_static_call_sections(struct objtool_file *file) 616 629 { 617 630 struct static_call_site *site; ··· 637 622 638 623 sec = find_section_by_name(file->elf, ".static_call_sites"); 639 624 if (sec) { 640 - WARN("file already has .static_call_sites section, skipping"); 625 + /* 626 + * Livepatch modules may have already extracted the static call 627 + * site entries to take advantage of vmlinux static call 628 + * privileges. 629 + */ 630 + if (!file->klp) 631 + WARN("file already has .static_call_sites section, skipping"); 632 + 641 633 return 0; 642 634 } 643 635 ··· 688 666 689 667 key_sym = find_symbol_by_name(file->elf, tmp); 690 668 if (!key_sym) { 691 - if (!opts.module) { 669 + if (!opts.module || file->klp) { 692 670 ERROR("static_call: can't find static_call_key symbol: %s", tmp); 693 671 return -1; 694 672 } ··· 907 885 908 886 sec = find_section_by_name(file->elf, "__mcount_loc"); 909 887 if (sec) { 910 - WARN("file already has __mcount_loc section, skipping"); 888 + /* 889 + * Livepatch modules have already extracted their __mcount_loc 890 + * entries to cover the !CONFIG_FTRACE_MCOUNT_USE_OBJTOOL case. 891 + */ 892 + if (!file->klp) 893 + WARN("file already has __mcount_loc section, skipping"); 894 + 911 895 return 0; 912 896 } 913 897 ··· 2597 2569 2598 2570 static int decode_sections(struct objtool_file *file) 2599 2571 { 2572 + file->klp = is_livepatch_module(file); 2573 + 2600 2574 mark_rodata(file); 2601 2575 2602 2576 if (init_pv_ops(file)) ··· 4274 4244 * - compiler cloned functions (*.cold, *.part0, etc) 4275 4245 * - asm functions created with inline asm or without SYM_FUNC_START() 4276 4246 * 4247 + * Also, the function may already have a prefix from a previous objtool run 4248 + * (livepatch extracted functions, or manually running objtool multiple times). 4249 + * 4277 4250 * So return 0 if the NOPs are missing or the function already has a prefix 4278 4251 * symbol. 4279 4252 */ ··· 4298 4265 4299 4266 if (snprintf_check(name, SYM_NAME_LEN, "__pfx_%s", func->name)) 4300 4267 return -1; 4268 + 4269 + if (file->klp) { 4270 + struct symbol *pfx; 4271 + 4272 + pfx = find_symbol_by_offset(func->sec, func->offset - opts.prefix); 4273 + if (pfx && is_prefix_func(pfx) && !strcmp(pfx->name, name)) 4274 + return 0; 4275 + } 4301 4276 4302 4277 insn = find_insn(file, func->sec, func->offset); 4303 4278 if (!insn) { ··· 4659 4618 !strncmp(sec->name, ".debug", 6) || 4660 4619 !strcmp(sec->name, ".altinstructions") || 4661 4620 !strcmp(sec->name, ".ibt_endbr_seal") || 4621 + !strcmp(sec->name, ".kcfi_traps") || 4662 4622 !strcmp(sec->name, ".orc_unwind_ip") || 4663 4623 !strcmp(sec->name, ".retpoline_sites") || 4664 4624 !strcmp(sec->name, ".smp_locks") || ··· 4669 4627 !strcmp(sec->name, "__bug_table") || 4670 4628 !strcmp(sec->name, "__ex_table") || 4671 4629 !strcmp(sec->name, "__jump_table") || 4630 + !strcmp(sec->name, "__klp_funcs") || 4672 4631 !strcmp(sec->name, "__mcount_loc") || 4673 - !strcmp(sec->name, ".kcfi_traps") || 4674 4632 !strcmp(sec->name, ".llvm.call-graph-profile") || 4675 4633 !strcmp(sec->name, ".llvm_bb_addr_map") || 4676 4634 !strcmp(sec->name, "__tracepoints") || 4677 - strstr(sec->name, "__patchable_function_entries")) 4635 + !strcmp(sec->name, "__patchable_function_entries")) 4678 4636 continue; 4679 4637 4680 4638 for_each_reloc(sec->rsec, reloc)
+4 -1
tools/objtool/elf.c
··· 499 499 strstarts(sym->name, "__pi___cfi_"))) 500 500 sym->prefix = 1; 501 501 502 - if (is_func_sym(sym) && strstr(sym->name, ".cold")) 502 + if (strstarts(sym->name, ".klp.sym")) 503 + sym->klp = 1; 504 + 505 + if (!sym->klp && is_func_sym(sym) && strstr(sym->name, ".cold")) 503 506 sym->cold = 1; 504 507 sym->pfunc = sym->cfunc = sym; 505 508
+1
tools/objtool/include/objtool/elf.h
··· 88 88 u8 debug_checksum : 1; 89 89 u8 changed : 1; 90 90 u8 included : 1; 91 + u8 klp : 1; 91 92 struct list_head pv_target; 92 93 struct reloc *relocs; 93 94 struct section *group_sec;
+1 -1
tools/objtool/include/objtool/objtool.h
··· 28 28 struct list_head mcount_loc_list; 29 29 struct list_head endbr_list; 30 30 struct list_head call_list; 31 - bool ignore_unreachables, hints, rodata; 31 + bool ignore_unreachables, hints, rodata, klp; 32 32 33 33 unsigned int nr_endbr; 34 34 unsigned int nr_endbr_int;