Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S967892AbeAONpa (ORCPT + 1 other); Mon, 15 Jan 2018 08:45:30 -0500 Received: from merlin.infradead.org ([205.233.59.134]:39814 "EHLO merlin.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S967742AbeAONpW (ORCPT ); Mon, 15 Jan 2018 08:45:22 -0500 Date: Mon, 15 Jan 2018 14:45:00 +0100 From: Peter Zijlstra To: David Woodhouse Cc: Dave Hansen , Ashok Raj , linux-kernel@vger.kernel.org, Thomas Gleixner , Tim Chen , Andy Lutomirski , Linus Torvalds , Greg KH , Andrea Arcangeli , Andi Kleen , Arjan Van De Ven , Dan Williams , Paolo Bonzini , Jun Nakajima , Asit Mallick Subject: Re: [PATCH 3/5] x86/ibrs: Add direct access support for MSR_IA32_SPEC_CTRL Message-ID: <20180115134500.GB2228@hirez.programming.kicks-ass.net> References: <1515720739-43819-1-git-send-email-ashok.raj@intel.com> <1515720739-43819-4-git-send-email-ashok.raj@intel.com> <20180112095148.GP3040@hirez.programming.kicks-ass.net> <1515751748.22302.421.camel@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1515751748.22302.421.camel@infradead.org> User-Agent: Mutt/1.9.2 (2017-12-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Return-Path: On Fri, Jan 12, 2018 at 10:09:08AM +0000, David Woodhouse wrote: > static_cpu_has() + asm-goto is NOT SUFFICIENT. > > It's still *possible* for a missed optimisation in GCC to still leave > us with a conditional branch around the wrmsr, letting the CPU > speculate around it too. OK, so GCC would have to be bloody retarded to mess this up; but would something like the below work for you? The usage is like: if (static_branch_unlikely(key)) { arch_static_assert(); stuff(); } And then objtool will fail things if the first instruction into that branch is not immediately after a NOP/JMP patch site (on either the NOP or the JMP+disp side of things). --- diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index 8c0de4282659..6a1a893145ca 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -62,6 +62,15 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool return true; } +static __always_inline void arch_static_assert(void) +{ + asm volatile ("1:\n\t" + ".pushsection .discard.jump_assert, \"aw\" \n\t" + _ASM_ALIGN "\n\t" + _ASM_PTR "1b \n\t" + ".popsection \n\t"); +} + #ifdef CONFIG_X86_64 typedef u64 jump_label_t; #else diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f40d46e24bcc..657bfc706bb6 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -687,8 +687,17 @@ static int handle_jump_alt(struct objtool_file *file, struct instruction *orig_insn, struct instruction **new_insn) { - if (orig_insn->type == INSN_NOP) + struct instruction *next_insn = list_next_entry(orig_insn, list); + + if (orig_insn->type == INSN_NOP) { + /* + * If orig_insn is a NOP, then new_insn is the branch target + * for when it would've been a JMP. + */ + next_insn->br_static = true; + (*new_insn)->br_static = true; return 0; + } if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { WARN_FUNC("unsupported instruction at jump label", @@ -696,7 +705,16 @@ static int handle_jump_alt(struct objtool_file *file, return -1; } - *new_insn = list_next_entry(orig_insn, list); + /* + * Otherwise, orig_insn is a JMP and it will have orig_insn->jump_dest. + * In this case we'll effectively NOP the alt by pointing new_insn at + * next_insn. + */ + orig_insn->jump_dest->br_static = true; + next_insn->br_static = true; + + *new_insn = next_insn; + return 0; } @@ -1067,6 +1085,50 @@ static int read_unwind_hints(struct objtool_file *file) return 0; } +static int read_jump_assertions(struct objtool_file *file) +{ + struct section *sec, *relasec; + struct instruction *insn; + struct rela *rela; + int i; + + sec = find_section_by_name(file->elf, ".discard.jump_assert"); + if (!sec) + return 0; + + relasec = sec->rela; + if (!relasec) { + WARN("missing .rela.discard.jump_assert section"); + return -1; + } + + if (sec->len % sizeof(unsigned long)) { + WARN("jump_assert size mismatch: %d %ld", sec->len, sizeof(unsigned long)); + return -1; + } + + for (i = 0; i < sec->len / sizeof(unsigned long); i++) { + rela = find_rela_by_dest(sec, i * sizeof(unsigned long)); + if (!rela) { + WARN("can't find rela for jump_assert[%d]", i); + return -1; + } + + insn = find_insn(file, rela->sym->sec, rela->addend); + if (!insn) { + WARN("can't find insn for jump_assert[%d]", i); + return -1; + } + + if (!insn->br_static) { + WARN_FUNC("static assert FAIL", insn->sec, insn->offset); + return -1; + } + } + + return 0; +} + static int decode_sections(struct objtool_file *file) { int ret; @@ -1105,6 +1167,10 @@ static int decode_sections(struct objtool_file *file) if (ret) return ret; + ret = read_jump_assertions(file); + if (ret) + return ret; + return 0; } diff --git a/tools/objtool/check.h b/tools/objtool/check.h index dbadb304a410..12e0a3cf0350 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -45,6 +46,7 @@ struct instruction { unsigned char type; unsigned long immediate; bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; + bool br_static; struct symbol *call_dest; struct instruction *jump_dest; struct list_head alts;