1 // SPDX-License-Identifier: GPL-2.0-or-later 2 #include <string.h> 3 4 #include <objtool/special.h> 5 #include <objtool/builtin.h> 6 7 #define X86_FEATURE_POPCNT (4 * 32 + 23) 8 #define X86_FEATURE_SMAP (9 * 32 + 20) 9 10 void arch_handle_alternative(unsigned short feature, struct special_alt *alt) 11 { 12 static struct special_alt *group, *prev; 13 14 /* 15 * Recompute orig_len for nested ALTERNATIVE()s. 16 */ 17 if (group && group->orig_sec == alt->orig_sec && 18 group->orig_off == alt->orig_off) { 19 20 struct special_alt *iter = group; 21 for (;;) { 22 unsigned int len = max(iter->orig_len, alt->orig_len); 23 iter->orig_len = alt->orig_len = len; 24 25 if (iter == prev) 26 break; 27 28 iter = list_next_entry(iter, list); 29 } 30 31 } else group = alt; 32 33 prev = alt; 34 35 switch (feature) { 36 case X86_FEATURE_SMAP: 37 /* 38 * If UACCESS validation is enabled; force that alternative; 39 * otherwise force it the other way. 40 * 41 * What we want to avoid is having both the original and the 42 * alternative code flow at the same time, in that case we can 43 * find paths that see the STAC but take the NOP instead of 44 * CLAC and the other way around. 45 */ 46 if (opts.uaccess) 47 alt->skip_orig = true; 48 else 49 alt->skip_alt = true; 50 break; 51 case X86_FEATURE_POPCNT: 52 /* 53 * It has been requested that we don't validate the !POPCNT 54 * feature path which is a "very very small percentage of 55 * machines". 56 */ 57 alt->skip_orig = true; 58 break; 59 default: 60 break; 61 } 62 } 63 64 bool arch_support_alt_relocation(struct special_alt *special_alt, 65 struct instruction *insn, 66 struct reloc *reloc) 67 { 68 return true; 69 } 70 71 /* 72 * There are 3 basic jump table patterns: 73 * 74 * 1. jmpq *[rodata addr](,%reg,8) 75 * 76 * This is the most common case by far. It jumps to an address in a simple 77 * jump table which is stored in .rodata. 78 * 79 * 2. jmpq *[rodata addr](%rip) 80 * 81 * This is caused by a rare GCC quirk, currently only seen in three driver 82 * functions in the kernel, only with certain obscure non-distro configs. 83 * 84 * As part of an optimization, GCC makes a copy of an existing switch jump 85 * table, modifies it, and then hard-codes the jump (albeit with an indirect 86 * jump) to use a single entry in the table. The rest of the jump table and 87 * some of its jump targets remain as dead code. 88 * 89 * In such a case we can just crudely ignore all unreachable instruction 90 * warnings for the entire object file. Ideally we would just ignore them 91 * for the function, but that would require redesigning the code quite a 92 * bit. And honestly that's just not worth doing: unreachable instruction 93 * warnings are of questionable value anyway, and this is such a rare issue. 94 * 95 * 3. mov [rodata addr],%reg1 96 * ... some instructions ... 97 * jmpq *(%reg1,%reg2,8) 98 * 99 * This is a fairly uncommon pattern which is new for GCC 6. As of this 100 * writing, there are 11 occurrences of it in the allmodconfig kernel. 101 * 102 * As of GCC 7 there are quite a few more of these and the 'in between' code 103 * is significant. Esp. with KASAN enabled some of the code between the mov 104 * and jmpq uses .rodata itself, which can confuse things. 105 * 106 * TODO: Once we have DWARF CFI and smarter instruction decoding logic, 107 * ensure the same register is used in the mov and jump instructions. 108 * 109 * NOTE: MITIGATION_RETPOLINE made it harder still to decode dynamic jumps. 110 */ 111 struct reloc *arch_find_switch_table(struct objtool_file *file, 112 struct instruction *insn) 113 { 114 struct reloc *text_reloc, *rodata_reloc; 115 struct section *table_sec; 116 unsigned long table_offset; 117 118 /* look for a relocation which references .rodata */ 119 text_reloc = find_reloc_by_dest_range(file->elf, insn->sec, 120 insn->offset, insn->len); 121 if (!text_reloc || text_reloc->sym->type != STT_SECTION || 122 !text_reloc->sym->sec->rodata) 123 return NULL; 124 125 table_offset = reloc_addend(text_reloc); 126 table_sec = text_reloc->sym->sec; 127 128 if (reloc_type(text_reloc) == R_X86_64_PC32) 129 table_offset += 4; 130 131 /* 132 * Make sure the .rodata address isn't associated with a 133 * symbol. GCC jump tables are anonymous data. 134 * 135 * Also support C jump tables which are in the same format as 136 * switch jump tables. For objtool to recognize them, they 137 * need to be placed in the C_JUMP_TABLE_SECTION section. They 138 * have symbols associated with them. 139 */ 140 if (find_symbol_containing(table_sec, table_offset) && 141 strcmp(table_sec->name, C_JUMP_TABLE_SECTION)) 142 return NULL; 143 144 /* 145 * Each table entry has a rela associated with it. The rela 146 * should reference text in the same function as the original 147 * instruction. 148 */ 149 rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset); 150 if (!rodata_reloc) 151 return NULL; 152 153 /* 154 * Use of RIP-relative switch jumps is quite rare, and 155 * indicates a rare GCC quirk/bug which can leave dead 156 * code behind. 157 */ 158 if (reloc_type(text_reloc) == R_X86_64_PC32) 159 file->ignore_unreachables = true; 160 161 return rodata_reloc; 162 } 163
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.