Teach objtool to validate the straight-line-speculation constraints: - speculation trap after indirect calls - speculation trap after RET Notable: when an instruction is annotated RETPOLINE_SAFE, indicating speculation isn't a problem, also don't care about sls for that instruction.
Unified · Split
| @@ -531,6 +531,11 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec · 530 unmodified lines | ||
| 531 | 531 | } |
| 532 | 532 | break; |
| 533 | 533 | |
| 534 | + case 0xcc: | |
| 535 | + /* int3 */ | |
| 536 | + *type = INSN_TRAP; | |
| 537 | + break; | |
| 538 | + | |
| 534 | 539 | case 0xe3: |
| 535 | 540 | /* jecxz/jrcxz */ |
| 536 | 541 | *type = INSN_JUMP_CONDITIONAL; |
| @@ -697,10 +702,10 @@ const char *arch_ret_insn(int len) · 160 unmodified lines | ||
| 697 | 702 | { |
| 698 | 703 | static const char ret[5][5] = { |
| 699 | 704 | { BYTE_RET }, |
| 700 | − { BYTE_RET, BYTES_NOP1 }, | |
| 701 | − { BYTE_RET, BYTES_NOP2 }, | |
| 702 | − { BYTE_RET, BYTES_NOP3 }, | |
| 703 | − { BYTE_RET, BYTES_NOP4 }, | |
| 705 | + { BYTE_RET, 0xcc }, | |
| 706 | + { BYTE_RET, 0xcc, BYTES_NOP1 }, | |
| 707 | + { BYTE_RET, 0xcc, BYTES_NOP2 }, | |
| 708 | + { BYTE_RET, 0xcc, BYTES_NOP3 }, | |
| 704 | 709 | }; |
| 705 | 710 | |
| 706 | 711 | if (len < 1 || len > 5) { |
| @@ -20,7 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <objtool/objtool.h> |
| 21 | 21 | |
| 22 | 22 | bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, |
| 23 | − validate_dup, vmlinux, mcount, noinstr, backup; | |
| 23 | + validate_dup, vmlinux, mcount, noinstr, backup, sls; | |
| 24 | 24 | |
| 25 | 25 | static const char * const check_usage[] = { |
| 26 | 26 | "objtool check [<options>] file.o", |
| @@ -45,6 +45,7 @@ const struct option check_options[] = { · 18 unmodified lines | ||
| 45 | 45 | OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"), |
| 46 | 46 | OPT_BOOLEAN('M', "mcount", &mcount, "generate __mcount_loc"), |
| 47 | 47 | OPT_BOOLEAN('B', "backup", &backup, "create .orig files before modification"), |
| 48 | + OPT_BOOLEAN('S', "sls", &sls, "validate straight-line-speculation"), | |
| 48 | 49 | OPT_END(), |
| 49 | 50 | }; |
| 50 | 51 | |
| @@ -3084,6 +3084,12 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, · 3083 unmodified lines | ||
| 3084 | 3084 | switch (insn->type) { |
| 3085 | 3085 | |
| 3086 | 3086 | case INSN_RETURN: |
| 3087 | + if (next_insn && next_insn->type == INSN_TRAP) { | |
| 3088 | + next_insn->ignore = true; | |
| 3089 | + } else if (sls && !insn->retpoline_safe) { | |
| 3090 | + WARN_FUNC("missing int3 after ret", | |
| 3091 | + insn->sec, insn->offset); | |
| 3092 | + } | |
| 3087 | 3093 | return validate_return(func, insn, &state); |
| 3088 | 3094 | |
| 3089 | 3095 | case INSN_CALL: |
| @@ -3127,6 +3133,14 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, · 37 unmodified lines | ||
| 3127 | 3133 | break; |
| 3128 | 3134 | |
| 3129 | 3135 | case INSN_JUMP_DYNAMIC: |
| 3136 | + if (next_insn && next_insn->type == INSN_TRAP) { | |
| 3137 | + next_insn->ignore = true; | |
| 3138 | + } else if (sls && !insn->retpoline_safe) { | |
| 3139 | + WARN_FUNC("missing int3 after indirect jump", | |
| 3140 | + insn->sec, insn->offset); | |
| 3141 | + } | |
| 3142 | + | |
| 3143 | + /* fallthrough */ | |
| 3130 | 3144 | case INSN_JUMP_DYNAMIC_CONDITIONAL: |
| 3131 | 3145 | if (is_sibling_call(insn)) { |
| 3132 | 3146 | ret = validate_sibling_call(file, insn, &state); |
| @@ -26,6 +26,7 @@ enum insn_type { · 25 unmodified lines | ||
| 26 | 26 | INSN_CLAC, |
| 27 | 27 | INSN_STD, |
| 28 | 28 | INSN_CLD, |
| 29 | + INSN_TRAP, | |
| 29 | 30 | INSN_OTHER, |
| 30 | 31 | }; |
| 31 | 32 | |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | extern const struct option check_options[]; |
| 11 | 11 | extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, |
| 12 | − validate_dup, vmlinux, mcount, noinstr, backup; | |
| 12 | + validate_dup, vmlinux, mcount, noinstr, backup, sls; | |
| 13 | 13 | |
| 14 | 14 | extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]); |
| 15 | 15 | |