]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
x86,objtool: Create .return_sites
authorPeter Zijlstra <peterz@infradead.org>
Tue, 14 Jun 2022 21:15:38 +0000 (23:15 +0200)
committerThadeu Lima de Souza Cascardo <cascardo@canonical.com>
Tue, 19 Jul 2022 19:17:35 +0000 (16:17 -0300)
commit d9e9d2300681d68a775c28de6aa6e5290ae17796 upstream.

Find all the return-thunk sites and record them in a .return_sites
section such that the kernel can undo this.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Borislav Petkov <bp@suse.de>
Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Borislav Petkov <bp@suse.de>
[cascardo: conflict fixup because of functions added to support IBT]
CVE-2022-29900
CVE-2022-29901
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
tools/objtool/arch/x86/decode.c
tools/objtool/check.c
tools/objtool/include/objtool/arch.h
tools/objtool/include/objtool/elf.h
tools/objtool/include/objtool/objtool.h
tools/objtool/objtool.c

index 3d8facc65d813a51e46aeb5bd1f8a23b48c799c1..f62db0e006e9c25e3ad960c560a6badf6d8c65b9 100644 (file)
@@ -722,3 +722,8 @@ bool arch_is_retpoline(struct symbol *sym)
 {
        return !strncmp(sym->name, "__x86_indirect_", 15);
 }
+
+bool arch_is_rethunk(struct symbol *sym)
+{
+       return !strcmp(sym->name, "__x86_return_thunk");
+}
index d3e0ec9fd2e0c3517b71e56a3c08d77a461f423b..41d111c69620d6e1e6d9584e83a494b259acc237 100644 (file)
@@ -654,6 +654,52 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
        return 0;
 }
 
+static int create_return_sites_sections(struct objtool_file *file)
+{
+       struct instruction *insn;
+       struct section *sec;
+       int idx;
+
+       sec = find_section_by_name(file->elf, ".return_sites");
+       if (sec) {
+               WARN("file already has .return_sites, skipping");
+               return 0;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node)
+               idx++;
+
+       if (!idx)
+               return 0;
+
+       sec = elf_create_section(file->elf, ".return_sites", 0,
+                                sizeof(int), idx);
+       if (!sec) {
+               WARN("elf_create_section: .return_sites");
+               return -1;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node) {
+
+               int *site = (int *)sec->data->d_buf + idx;
+               *site = 0;
+
+               if (elf_add_reloc_to_insn(file->elf, sec,
+                                         idx * sizeof(int),
+                                         R_X86_64_PC32,
+                                         insn->sec, insn->offset)) {
+                       WARN("elf_add_reloc_to_insn: .return_sites");
+                       return -1;
+               }
+
+               idx++;
+       }
+
+       return 0;
+}
+
 static int create_mcount_loc_sections(struct objtool_file *file)
 {
        struct section *sec;
@@ -932,6 +978,11 @@ __weak bool arch_is_retpoline(struct symbol *sym)
        return false;
 }
 
+__weak bool arch_is_rethunk(struct symbol *sym)
+{
+       return false;
+}
+
 #define NEGATIVE_RELOC ((void *)-1L)
 
 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
@@ -1092,6 +1143,19 @@ static void add_retpoline_call(struct objtool_file *file, struct instruction *in
 
        annotate_call_site(file, insn, false);
 }
+
+static void add_return_call(struct objtool_file *file, struct instruction *insn)
+{
+       /*
+        * Return thunk tail calls are really just returns in disguise,
+        * so convert them accordingly.
+        */
+       insn->type = INSN_RETURN;
+       insn->retpoline_safe = true;
+
+       list_add_tail(&insn->call_node, &file->return_thunk_list);
+}
+
 /*
  * Find the destination instructions for all jumps.
  */
@@ -1116,6 +1180,9 @@ static int add_jump_destinations(struct objtool_file *file)
                } else if (reloc->sym->retpoline_thunk) {
                        add_retpoline_call(file, insn);
                        continue;
+               } else if (reloc->sym->return_thunk) {
+                       add_return_call(file, insn);
+                       continue;
                } else if (insn->func) {
                        /* internal or external sibling call (with reloc) */
                        add_call_dest(file, insn, reloc->sym, true);
@@ -1937,6 +2004,9 @@ static int classify_symbols(struct objtool_file *file)
                        if (arch_is_retpoline(func))
                                func->retpoline_thunk = true;
 
+                       if (arch_is_rethunk(func))
+                               func->return_thunk = true;
+
                        if (!strcmp(func->name, "__fentry__"))
                                func->fentry = true;
 
@@ -3413,6 +3483,11 @@ int check(struct objtool_file *file)
                if (ret < 0)
                        goto out;
                warnings += ret;
+
+               ret = create_return_sites_sections(file);
+               if (ret < 0)
+                       goto out;
+               warnings += ret;
        }
 
        if (mcount) {
index deae99b423f358bf860baa71d094447f3afaad04..8d57e3d1f763ddb026c26ec14b9377438b14221b 100644 (file)
@@ -88,6 +88,7 @@ const char *arch_ret_insn(int len);
 int arch_decode_hint_reg(u8 sp_reg, int *base);
 
 bool arch_is_retpoline(struct symbol *sym);
+bool arch_is_rethunk(struct symbol *sym);
 
 int arch_rewrite_retpolines(struct objtool_file *file);
 
index 08821307ac99b7ec704c7e1c7e15a737e5851642..6cdfa401b00092a5bd0574bc793f71487afea8df 100644 (file)
@@ -57,6 +57,7 @@ struct symbol {
        u8 uaccess_safe      : 1;
        u8 static_call_tramp : 1;
        u8 retpoline_thunk   : 1;
+       u8 return_thunk      : 1;
        u8 fentry            : 1;
        u8 kcov              : 1;
 };
index 24fa83634de4d7aa6f43735d19852d632e222b96..97b25a217c3a535e7ac143ab2dc7f08697fdcb66 100644 (file)
@@ -19,6 +19,7 @@ struct objtool_file {
        struct list_head insn_list;
        DECLARE_HASHTABLE(insn_hash, 20);
        struct list_head retpoline_call_list;
+       struct list_head return_thunk_list;
        struct list_head static_call_list;
        struct list_head mcount_loc_list;
        bool ignore_unreachables, c_file, hints, rodata;
index e21db8bce4935c91ed313f374ad32ea45ffc938a..24650d533d85c8cfe6cb47b264e1382dee1bc1b5 100644 (file)
@@ -126,6 +126,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
        INIT_LIST_HEAD(&file.insn_list);
        hash_init(file.insn_hash);
        INIT_LIST_HEAD(&file.retpoline_call_list);
+       INIT_LIST_HEAD(&file.return_thunk_list);
        INIT_LIST_HEAD(&file.static_call_list);
        INIT_LIST_HEAD(&file.mcount_loc_list);
        file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");