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
13501350 {
13511351 struct reloc *reloc;
13521352
1353− if (insn->no_reloc)
1354− return NULL;
1355−
1356− if (!file)
1353+ if (!file || insn->no_reloc || insn->fake)
13571354 return NULL;
13581355
13591356 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
26222619
26232620 static bool validate_branch_enabled(void)
26242621 {
2625− return opts.stackval ||
2626− opts.orc ||
2627− opts.uaccess ||
2622+ return opts.stackval ||
2623+ opts.orc ||
2624+ opts.uaccess;
2625+}
2626+
2627+static bool alts_needed(void)
2628+{
2629+ return validate_branch_enabled() ||
2630+ opts.noinstr ||
2631+ opts.hack_jump_label ||
2632+ opts.disas ||
26282633 opts.checksum;
26292634 }
26302635
@@ -2658,7 +2663,7 @@ static int decode_sections(struct objtool_file *file) · 27 unmodified lines
26582663 * Must be before add_jump_destinations(), which depends on 'func'
26592664 * being set for alternatives, to enable proper sibling call detection.
26602665 */
2661− if (validate_branch_enabled() || opts.noinstr || opts.hack_jump_label || opts.disas) {
2666+ if (alts_needed()) {
26622667 if (add_special_section_alts(file))
26632668 return -1;
26642669 }
@@ -3654,6 +3659,7 @@ static bool skip_alt_group(struct instruction *insn) · 989 unmodified lines
36543659 return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC;
36553660 }
36563661
3662+#ifdef BUILD_KLP
36573663 static int checksum_debug_init(struct objtool_file *file)
36583664 {
36593665 char *dup, *s;
@@ -3701,8 +3707,10 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 41 unmodified lines
37013707 struct instruction *insn)
37023708 {
37033709 struct reloc *reloc = insn_reloc(file, insn);
3710+ struct alternative *alt;
37043711 unsigned long offset;
37053712 struct symbol *sym;
3713+ static bool in_alt;
37063714
37073715 if (insn->fake)
37083716 return;
@@ -3715,7 +3723,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 6 unmodified lines
37153723 if (call_dest)
37163724 checksum_update(func, insn, call_dest->demangled_name,
37173725 strlen(call_dest->demangled_name));
3718− return;
3726+ goto alts;
37193727 }
37203728
37213729 sym = reloc->sym;
@@ -3726,21 +3734,78 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, · 4 unmodified lines
37263734
37273735 str = sym->sec->data->d_buf + sym->offset + offset;
37283736 checksum_update(func, insn, str, strlen(str));
3729− return;
3737+ goto alts;
37303738 }
37313739
37323740 if (is_sec_sym(sym)) {
37333741 sym = find_symbol_containing(reloc->sym->sec, offset);
37343742 if (!sym)
3735− return;
3743+ goto alts;
37363744
37373745 offset -= sym->offset;
37383746 }
37393747
37403748 checksum_update(func, insn, sym->demangled_name, strlen(sym->demangled_name));
37413749 checksum_update(func, insn, &offset, sizeof(offset));
3750+
3751+alts:
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+ }
37423778 }
37433779
3780+static 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+
37443809 static int validate_branch(struct objtool_file *file, struct symbol *func,
37453810 struct instruction *insn, struct insn_state state);
37463811 static 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
40224087 insn->trace = 0;
40234088 next_insn = next_insn_to_validate(file, insn);
40244089
4025− if (opts.checksum && func && insn->sec)
4026− checksum_update_insn(file, func, insn);
4027−
40284090 if (func && insn_func(insn) && func != insn_func(insn)->pfunc) {
40294091 /* Ignore KCFI type preambles, which always fall through */
40304092 if (is_prefix_func(func))
@@ -4090,9 +4152,6 @@ static int validate_unwind_hint(struct objtool_file *file, · 59 unmodified lines
40904152 struct symbol *func = insn_func(insn);
40914153 int ret;
40924154
4093− if (opts.checksum)
4094− checksum_init(func);
4095−
40964155 ret = validate_branch(file, func, insn, *state);
40974156 if (ret)
40984157 BT_INSN(insn, "<=== (hint)");
@@ -4535,9 +4594,6 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, · 436 unmodified lines
45354594
45364595 func = insn_func(insn);
45374596
4538− if (opts.checksum)
4539− checksum_init(func);
4540−
45414597 if (opts.trace && !fnmatch(opts.trace, sym->name, 0)) {
45424598 trace_enable();
45434599 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
45504606 TRACE("%s: validation %s\n\n", sym->name, ret ? "failed" : "end");
45514607 trace_disable();
45524608
4553− if (opts.checksum)
4554− checksum_finish(func);
4555−
45564609 return ret;
45574610 }
45584611
@@ -5007,10 +5060,6 @@ int check(struct objtool_file *file) · 448 unmodified lines
50075060 cfi_hash_add(&init_cfi);
50085061 cfi_hash_add(&func_cfi);
50095062
5010− ret = checksum_debug_init(file);
5011− if (ret)
5012− goto out;
5013−
50145063 ret = decode_sections(file);
50155064 if (ret)
50165065 goto out;
@@ -5101,6 +5150,9 @@ int check(struct objtool_file *file) · 84 unmodified lines
51015150 warnings += check_abs_references(file);
51025151
51035152 if (opts.checksum) {
5153+ ret = calculate_checksums(file);
5154+ if (ret)
5155+ goto out;
51045156 ret = create_sym_checksum_section(file);
51055157 if (ret)
51065158 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
3333
3434 #else /* !BUILD_KLP */
3535
36−static inline void checksum_init(struct symbol *func) {}
37−static inline void checksum_update(struct symbol *func,
38− struct instruction *insn,
39− const void *data, size_t size) {}
40−static inline void checksum_finish(struct symbol *func) {}
36+static inline int calculate_checksums(struct objtool_file *file) { return -ENOSYS; }
4137
4238 #endif /* !BUILD_KLP */
4339