![]() |
|
|||
0001 // SPDX-License-Identifier: GPL-2.0-or-later 0002 #include <string.h> 0003 0004 #include <objtool/special.h> 0005 #include <objtool/builtin.h> 0006 0007 #define X86_FEATURE_POPCNT (4 * 32 + 23) 0008 #define X86_FEATURE_SMAP (9 * 32 + 20) 0009 0010 void arch_handle_alternative(unsigned short feature, struct special_alt *alt) 0011 { 0012 switch (feature) { 0013 case X86_FEATURE_SMAP: 0014 /* 0015 * If UACCESS validation is enabled; force that alternative; 0016 * otherwise force it the other way. 0017 * 0018 * What we want to avoid is having both the original and the 0019 * alternative code flow at the same time, in that case we can 0020 * find paths that see the STAC but take the NOP instead of 0021 * CLAC and the other way around. 0022 */ 0023 if (opts.uaccess) 0024 alt->skip_orig = true; 0025 else 0026 alt->skip_alt = true; 0027 break; 0028 case X86_FEATURE_POPCNT: 0029 /* 0030 * It has been requested that we don't validate the !POPCNT 0031 * feature path which is a "very very small percentage of 0032 * machines". 0033 */ 0034 alt->skip_orig = true; 0035 break; 0036 default: 0037 break; 0038 } 0039 } 0040 0041 bool arch_support_alt_relocation(struct special_alt *special_alt, 0042 struct instruction *insn, 0043 struct reloc *reloc) 0044 { 0045 /* 0046 * The x86 alternatives code adjusts the offsets only when it 0047 * encounters a branch instruction at the very beginning of the 0048 * replacement group. 0049 */ 0050 return insn->offset == special_alt->new_off && 0051 (insn->type == INSN_CALL || is_jump(insn)); 0052 } 0053 0054 /* 0055 * There are 3 basic jump table patterns: 0056 * 0057 * 1. jmpq *[rodata addr](,%reg,8) 0058 * 0059 * This is the most common case by far. It jumps to an address in a simple 0060 * jump table which is stored in .rodata. 0061 * 0062 * 2. jmpq *[rodata addr](%rip) 0063 * 0064 * This is caused by a rare GCC quirk, currently only seen in three driver 0065 * functions in the kernel, only with certain obscure non-distro configs. 0066 * 0067 * As part of an optimization, GCC makes a copy of an existing switch jump 0068 * table, modifies it, and then hard-codes the jump (albeit with an indirect 0069 * jump) to use a single entry in the table. The rest of the jump table and 0070 * some of its jump targets remain as dead code. 0071 * 0072 * In such a case we can just crudely ignore all unreachable instruction 0073 * warnings for the entire object file. Ideally we would just ignore them 0074 * for the function, but that would require redesigning the code quite a 0075 * bit. And honestly that's just not worth doing: unreachable instruction 0076 * warnings are of questionable value anyway, and this is such a rare issue. 0077 * 0078 * 3. mov [rodata addr],%reg1 0079 * ... some instructions ... 0080 * jmpq *(%reg1,%reg2,8) 0081 * 0082 * This is a fairly uncommon pattern which is new for GCC 6. As of this 0083 * writing, there are 11 occurrences of it in the allmodconfig kernel. 0084 * 0085 * As of GCC 7 there are quite a few more of these and the 'in between' code 0086 * is significant. Esp. with KASAN enabled some of the code between the mov 0087 * and jmpq uses .rodata itself, which can confuse things. 0088 * 0089 * TODO: Once we have DWARF CFI and smarter instruction decoding logic, 0090 * ensure the same register is used in the mov and jump instructions. 0091 * 0092 * NOTE: RETPOLINE made it harder still to decode dynamic jumps. 0093 */ 0094 struct reloc *arch_find_switch_table(struct objtool_file *file, 0095 struct instruction *insn) 0096 { 0097 struct reloc *text_reloc, *rodata_reloc; 0098 struct section *table_sec; 0099 unsigned long table_offset; 0100 0101 /* look for a relocation which references .rodata */ 0102 text_reloc = find_reloc_by_dest_range(file->elf, insn->sec, 0103 insn->offset, insn->len); 0104 if (!text_reloc || text_reloc->sym->type != STT_SECTION || 0105 !text_reloc->sym->sec->rodata) 0106 return NULL; 0107 0108 table_offset = text_reloc->addend; 0109 table_sec = text_reloc->sym->sec; 0110 0111 if (text_reloc->type == R_X86_64_PC32) 0112 table_offset += 4; 0113 0114 /* 0115 * Make sure the .rodata address isn't associated with a 0116 * symbol. GCC jump tables are anonymous data. 0117 * 0118 * Also support C jump tables which are in the same format as 0119 * switch jump tables. For objtool to recognize them, they 0120 * need to be placed in the C_JUMP_TABLE_SECTION section. They 0121 * have symbols associated with them. 0122 */ 0123 if (find_symbol_containing(table_sec, table_offset) && 0124 strcmp(table_sec->name, C_JUMP_TABLE_SECTION)) 0125 return NULL; 0126 0127 /* 0128 * Each table entry has a rela associated with it. The rela 0129 * should reference text in the same function as the original 0130 * instruction. 0131 */ 0132 rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset); 0133 if (!rodata_reloc) 0134 return NULL; 0135 0136 /* 0137 * Use of RIP-relative switch jumps is quite rare, and 0138 * indicates a rare GCC quirk/bug which can leave dead 0139 * code behind. 0140 */ 0141 if (text_reloc->type == R_X86_64_PC32) 0142 file->ignore_unreachables = true; 0143 0144 return rodata_reloc; 0145 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |