objtool: Add --cfi to generate the .cfi_sites section
authorPeter Zijlstra <peterz@infradead.org>
Thu, 27 Oct 2022 09:28:13 +0000 (11:28 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Tue, 1 Nov 2022 12:44:10 +0000 (13:44 +0100)
Add the location of all __cfi_##name symbols (as generated by kCFI) to
a section such that we might re-write things at kernel boot.

Notably; boot time re-hashing and FineIBT are the intended use of
this.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20221027092842.568039454@infradead.org
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/include/objtool/builtin.h

index 95fcecee60ce5f80160f9331f565ba2c6df5b25b..868e3e363786f288047db8258c175bd4a00aca22 100644 (file)
@@ -80,6 +80,7 @@ const struct option check_options[] = {
        OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
        OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
        OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
+       OPT_BOOLEAN(0  , "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"),
        OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),
 
        OPT_GROUP("Options:"),
index 27f35f5f831ab5d30570e76967ffe9eeb2dbba10..55066c49357026dcbfa810397eeeb24a9d8f497d 100644 (file)
@@ -861,6 +861,68 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
        return 0;
 }
 
+static int create_cfi_sections(struct objtool_file *file)
+{
+       struct section *sec, *s;
+       struct symbol *sym;
+       unsigned int *loc;
+       int idx;
+
+       sec = find_section_by_name(file->elf, ".cfi_sites");
+       if (sec) {
+               INIT_LIST_HEAD(&file->call_list);
+               WARN("file already has .cfi_sites section, skipping");
+               return 0;
+       }
+
+       idx = 0;
+       for_each_sec(file, s) {
+               if (!s->text)
+                       continue;
+
+               list_for_each_entry(sym, &s->symbol_list, list) {
+                       if (sym->type != STT_FUNC)
+                               continue;
+
+                       if (strncmp(sym->name, "__cfi_", 6))
+                               continue;
+
+                       idx++;
+               }
+       }
+
+       sec = elf_create_section(file->elf, ".cfi_sites", 0, sizeof(unsigned int), idx);
+       if (!sec)
+               return -1;
+
+       idx = 0;
+       for_each_sec(file, s) {
+               if (!s->text)
+                       continue;
+
+               list_for_each_entry(sym, &s->symbol_list, list) {
+                       if (sym->type != STT_FUNC)
+                               continue;
+
+                       if (strncmp(sym->name, "__cfi_", 6))
+                               continue;
+
+                       loc = (unsigned int *)sec->data->d_buf + idx;
+                       memset(loc, 0, sizeof(unsigned int));
+
+                       if (elf_add_reloc_to_insn(file->elf, sec,
+                                                 idx * sizeof(unsigned int),
+                                                 R_X86_64_PC32,
+                                                 s, sym->offset))
+                               return -1;
+
+                       idx++;
+               }
+       }
+
+       return 0;
+}
+
 static int create_mcount_loc_sections(struct objtool_file *file)
 {
        struct section *sec;
@@ -4430,6 +4492,13 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.cfi) {
+               ret = create_cfi_sections(file);
+               if (ret < 0)
+                       goto out;
+               warnings += ret;
+       }
+
        if (opts.rethunk) {
                ret = create_return_sites_sections(file);
                if (ret < 0)
index f341b620dead47965491875ae026ddffff8a60b5..c44ff39df80c642d287d004cd7f717eb6b2f7875 100644 (file)
@@ -27,6 +27,7 @@ struct opts {
        bool static_call;
        bool uaccess;
        int prefix;
+       bool cfi;
 
        /* options: */
        bool backtrace;