History

objtool/klp: Extricate checksum calculation from validate_branch()

In preparation for porting the checksum code to other arches, make its functionality independent from the CFG reverse engineering code. Move it into a standalone calculate_checksums() function which iterates all functions and instructions directly, rather than being called inline from do_validate_branch(). Since checksum_update_insn() is no longer called during CFG traversal, it needs to manually iterate the alternatives.

Josh Poimboeuf committed 7 months ago

Commit 30cae581 parent 6282e9f2 files · +80 −32Browse files

Unified · Split

2 files
  1. tools/objtool/check.c +79 −27
  2. tools/objtool/include/objtool/checksum.h +1 −5
tools/objtool/check.c+79−27
@@ -1350,10 +1350,7 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i · 1349 unmodified lines
1350{1350{
1351 struct reloc *reloc;1351 struct reloc *reloc;
1352 1352
1353 if (insn->no_reloc)1353 if (!file || insn->no_reloc || insn->fake)
1354 return NULL;
1355
1356 if (!file)
1357 return NULL;1354 return NULL;
1358 1355
1359 reloc = find_reloc_by_dest_range(file->elf, insn->sec,1356 reloc = find_reloc_by_dest_range(file->elf, insn->sec,
@@ -2622,9 +2619,17 @@ static void mark_holes(struct objtool_file *file) · 1262 unmodified lines
2622 2619
2623static bool validate_branch_enabled(void)2620static bool validate_branch_enabled(void)
2624{2621{
2625 return opts.stackval ||2622 return opts.stackval ||
2626 opts.orc ||2623 opts.orc ||
2627 opts.uaccess ||2624 opts.uaccess;
2625}
2626
2627static bool alts_needed(void)
2628{
2629 return validate_branch_enabled() ||
2630 opts.noinstr ||
2631 opts.hack_jump_label ||
2632 opts.disas ||
2628 opts.checksum;2633 opts.checksum;
2629}2634}
2630 2635
@@ -2658,7 +2663,7 @@ static int decode_sections(struct objtool_file *file) · 27 unmodified lines
2658 * Must be before add_jump_destinations(), which depends on 'func'2663 * Must be before add_jump_destinations(), which depends on 'func'
2659 * being set for alternatives, to enable proper sibling call detection.2664 * being set for alternatives, to enable proper sibling call detection.
2660 */2665 */
2661 if (validate_branch_enabled() || opts.noinstr || opts.hack_jump_label || opts.disas) {2666 if (alts_needed()) {
2662 if (add_special_section_alts(file))2667 if (add_special_section_alts(file))
2663 return -1;2668 return -1;
2664 }2669 }
@@ -3654,6 +3659,7 @@ static bool skip_alt_group(struct instruction *insn) · 989 unmodified lines
3654 return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC;3659 return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC;
3655}3660}
3656 3661
3662#ifdef BUILD_KLP
3657static int checksum_debug_init(struct objtool_file *file)3663static int checksum_debug_init(struct objtool_file *file)
3658{3664{
3659 char *dup, *s;3665 char *dup, *s;
@@ -3701,8 +3707,10 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 41 unmodified lines
3701 struct instruction *insn)3707 struct instruction *insn)
3702{3708{
3703 struct reloc *reloc = insn_reloc(file, insn);3709 struct reloc *reloc = insn_reloc(file, insn);
3710 struct alternative *alt;
3704 unsigned long offset;3711 unsigned long offset;
3705 struct symbol *sym;3712 struct symbol *sym;
3713 static bool in_alt;
3706 3714
3707 if (insn->fake)3715 if (insn->fake)
3708 return;3716 return;
@@ -3715,7 +3723,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 6 unmodified lines
3715 if (call_dest)3723 if (call_dest)
3716 checksum_update(func, insn, call_dest->demangled_name,3724 checksum_update(func, insn, call_dest->demangled_name,
3717 strlen(call_dest->demangled_name));3725 strlen(call_dest->demangled_name));
3718 return;3726 goto alts;
3719 }3727 }
3720 3728
3721 sym = reloc->sym;3729 sym = reloc->sym;
@@ -3726,21 +3734,78 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 4 unmodified lines
3726 3734
3727 str = sym->sec->data->d_buf + sym->offset + offset;3735 str = sym->sec->data->d_buf + sym->offset + offset;
3728 checksum_update(func, insn, str, strlen(str));3736 checksum_update(func, insn, str, strlen(str));
3729 return;3737 goto alts;
3730 }3738 }
3731 3739
3732 if (is_sec_sym(sym)) {3740 if (is_sec_sym(sym)) {
3733 sym = find_symbol_containing(reloc->sym->sec, offset);3741 sym = find_symbol_containing(reloc->sym->sec, offset);
3734 if (!sym)3742 if (!sym)
3735 return;3743 goto alts;
3736 3744
3737 offset -= sym->offset;3745 offset -= sym->offset;
3738 }3746 }
3739 3747
3740 checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name));3748 checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name));
3741 checksum_update(func, insn, &offset, sizeof(offset));3749 checksum_update(func, insn, &offset, sizeof(offset));
3750
3751alts:
3752 for (alt = insn->alts; alt; alt = alt->next) {
3753 struct alt_group *alt_group = alt->insn->alt_group;
3754
3755 /* Prevent __ex_table recursion, e.g. LOAD_SEGMENT() */
3756 if (in_alt)
3757 break;
3758 in_alt = true;
3759
3760 checksum_update(func, insn, &alt->type, sizeof(alt->type));
3761
3762 if (alt_group && alt_group->orig_group) {
3763 struct instruction *alt_insn;
3764
3765 checksum_update(func, insn, &alt_group->feature, sizeof(alt_group->feature));
3766
3767 for (alt_insn = alt->insn; alt_insn; alt_insn = next_insn_same_sec(file, alt_insn)) {
3768 checksum_update_insn(file, func, alt_insn);
3769 if (!alt_group->last_insn || alt_insn == alt_group->last_insn)
3770 break;
3771 }
3772 } else {
3773 checksum_update_insn(file, func, alt->insn);
3774 }
3775
3776 in_alt = false;
3777 }
3742}3778}
3743 3779
3780static int calculate_checksums(struct objtool_file *file)
3781{
3782 struct instruction *insn;
3783 struct symbol *func;
3784
3785 if (checksum_debug_init(file))
3786 return -1;
3787
3788 for_each_sym(file->elf, func) {
3789 /*
3790 * Skip cold subfunctions and aliases: they share the
3791 * parent's checksum via func_for_each_insn() which
3792 * follows func->cfunc into the cold subfunction.
3793 */
3794 if (!is_func_sym(func) || is_cold_func(func) ||
3795 is_alias_sym(func) || !func->len)
3796 continue;
3797
3798 checksum_init(func);
3799
3800 func_for_each_insn(file, func, insn)
3801 checksum_update_insn(file, func, insn);
3802
3803 checksum_finish(func);
3804 }
3805 return 0;
3806}
3807#endif /* BUILD_KLP */
3808
3744static int validate_branch(struct objtool_file *file, struct symbol *func,3809static int validate_branch(struct objtool_file *file, struct symbol *func,
3745 struct instruction *insn, struct insn_state state);3810 struct instruction *insn, struct insn_state state);
3746static int do_validate_branch(struct objtool_file *file, struct symbol *func,3811static int do_validate_branch(struct objtool_file *file, struct symbol *func,
@@ -4022,9 +4087,6 @@ static int do_validate_branch(struct objtool_file *file, struct symbol *func, · 275 unmodified lines
4022 insn->trace = 0;4087 insn->trace = 0;
4023 next_insn = next_insn_to_validate(file, insn);4088 next_insn = next_insn_to_validate(file, insn);
4024 4089
4025 if (opts.checksum && func && insn->sec)
4026 checksum_update_insn(file, func, insn);
4027
4028 if (func && insn_func(insn) && func != insn_func(insn)->pfunc) {4090 if (func && insn_func(insn) && func != insn_func(insn)->pfunc) {
4029 /* Ignore KCFI type preambles, which always fall through */4091 /* Ignore KCFI type preambles, which always fall through */
4030 if (is_prefix_func(func))4092 if (is_prefix_func(func))
@@ -4090,9 +4152,6 @@ static int validate_unwind_hint(struct objtool_file *file, · 59 unmodified lines
4090 struct symbol *func = insn_func(insn);4152 struct symbol *func = insn_func(insn);
4091 int ret;4153 int ret;
4092 4154
4093 if (opts.checksum)
4094 checksum_init(func);
4095
4096 ret = validate_branch(file, func, insn, *state);4155 ret = validate_branch(file, func, insn, *state);
4097 if (ret)4156 if (ret)
4098 BT_INSN(insn, "<=== (hint)");4157 BT_INSN(insn, "<=== (hint)");
@@ -4535,9 +4594,6 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, · 436 unmodified lines
4535 4594
4536 func = insn_func(insn);4595 func = insn_func(insn);
4537 4596
4538 if (opts.checksum)
4539 checksum_init(func);
4540
4541 if (opts.trace && !fnmatch(opts.trace, sym->name, 0)) {4597 if (opts.trace && !fnmatch(opts.trace, sym->name, 0)) {
4542 trace_enable();4598 trace_enable();
4543 TRACE("%s: validation begin\n", sym->name);4599 TRACE("%s: validation begin\n", sym->name);
@@ -4550,9 +4606,6 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, · 6 unmodified lines
4550 TRACE("%s: validation %s\n\n", sym->name, ret ? "failed" : "end");4606 TRACE("%s: validation %s\n\n", sym->name, ret ? "failed" : "end");
4551 trace_disable();4607 trace_disable();
4552 4608
4553 if (opts.checksum)
4554 checksum_finish(func);
4555
4556 return ret;4609 return ret;
4557}4610}
4558 4611
@@ -5007,10 +5060,6 @@ int check(struct objtool_file *file) · 448 unmodified lines
5007 cfi_hash_add(&init_cfi);5060 cfi_hash_add(&init_cfi);
5008 cfi_hash_add(&func_cfi);5061 cfi_hash_add(&func_cfi);
5009 5062
5010 ret = checksum_debug_init(file);
5011 if (ret)
5012 goto out;
5013
5014 ret = decode_sections(file);5063 ret = decode_sections(file);
5015 if (ret)5064 if (ret)
5016 goto out;5065 goto out;
@@ -5101,6 +5150,9 @@ int check(struct objtool_file *file) · 84 unmodified lines
5101 warnings += check_abs_references(file);5150 warnings += check_abs_references(file);
5102 5151
5103 if (opts.checksum) {5152 if (opts.checksum) {
5153 ret = calculate_checksums(file);
5154 if (ret)
5155 goto out;
5104 ret = create_sym_checksum_section(file);5156 ret = create_sym_checksum_section(file);
5105 if (ret)5157 if (ret)
5106 goto out;5158 goto out;
tools/objtool/include/objtool/checksum.h+1−5
@@ -33,11 +33,7 @@ static inline void checksum_finish(struct symbol *func) · 32 unmodified lines
33 33
34#else /* !BUILD_KLP */34#else /* !BUILD_KLP */
35 35
36static inline void checksum_init(struct symbol *func) {}36static inline int calculate_checksums(struct objtool_file *file) { return -ENOSYS; }
37static inline void checksum_update(struct symbol *func,
38 struct instruction *insn,
39 const void *data, size_t size) {}
40static inline void checksum_finish(struct symbol *func) {}
41 37
42#endif /* !BUILD_KLP */38#endif /* !BUILD_KLP */
43 39