Later commits will depend on having no runtime-mutable text in early entry
code. (ab)use the .noinstr section as a marker of early entry code and warn
about static keys used in it that can be flipped at runtime.
Suggested-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Valentin Schneider <[email protected]>
---
tools/objtool/check.c | 20 ++++++++++++++++++++
tools/objtool/include/objtool/check.h | 1 +
tools/objtool/include/objtool/special.h | 2 ++
tools/objtool/special.c | 3 +++
4 files changed, 26 insertions(+)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index fe62232f218f9..7f8d210ec88c3 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2032,6 +2032,9 @@ static int add_special_section_alts(struct objtool_file *file)
alt->next = orig_insn->alts;
orig_insn->alts = alt;
+ if (special_alt->key_sym)
+ orig_insn->key_sym = special_alt->key_sym;
+
list_del(&special_alt->list);
free(special_alt);
}
@@ -3520,6 +3523,20 @@ static int validate_return(struct symbol *func, struct instruction *insn, struct
return 0;
}
+static int validate_static_key(struct instruction *insn, struct insn_state *state)
+{
+ if (state->noinstr && state->instr <= 0) {
+ if ((strcmp(insn->key_sym->sec->name, ".data..ro_after_init"))) {
+ WARN_INSN(insn,
+ "Non __ro_after_init static key \"%s\" in .noinstr section",
+ insn->key_sym->name);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static struct instruction *next_insn_to_validate(struct objtool_file *file,
struct instruction *insn)
{
@@ -3670,6 +3687,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
if (handle_insn_ops(insn, next_insn, &state))
return 1;
+ if (insn->key_sym)
+ validate_static_key(insn, &state);
+
switch (insn->type) {
case INSN_RETURN:
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index daa46f1f0965a..35dd21f8f41e1 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -77,6 +77,7 @@ struct instruction {
struct symbol *sym;
struct stack_op *stack_ops;
struct cfi_state *cfi;
+ struct symbol *key_sym;
};
static inline struct symbol *insn_func(struct instruction *insn)
diff --git a/tools/objtool/include/objtool/special.h b/tools/objtool/include/objtool/special.h
index 86d4af9c5aa9d..0e61f34fe3a28 100644
--- a/tools/objtool/include/objtool/special.h
+++ b/tools/objtool/include/objtool/special.h
@@ -27,6 +27,8 @@ struct special_alt {
struct section *new_sec;
unsigned long new_off;
+ struct symbol *key_sym;
+
unsigned int orig_len, new_len; /* group only */
};
diff --git a/tools/objtool/special.c b/tools/objtool/special.c
index baa85c31526b3..830e6abf173a2 100644
--- a/tools/objtool/special.c
+++ b/tools/objtool/special.c
@@ -127,6 +127,9 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
return -1;
}
alt->key_addend = key_reloc->addend;
+
+ reloc_to_sec_off(key_reloc, &sec, &offset);
+ alt->key_sym = find_symbol_by_offset(sec, offset & ~2);
}
return 0;
--
2.31.1