Received: by 10.213.65.68 with SMTP id h4csp427277imn; Tue, 13 Mar 2018 08:43:41 -0700 (PDT) X-Google-Smtp-Source: AG47ELvKMmfpDPhb9+Cvt9SCkOVRg9d/CEBah6+xQRsuH3q2jelGbTARZRuHYvSGH8EZ1Bg2XHUY X-Received: by 10.167.129.195 with SMTP id c3mr1074485pfn.14.1520955821510; Tue, 13 Mar 2018 08:43:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1520955821; cv=none; d=google.com; s=arc-20160816; b=q/tX5Ru6VfQ371tsX7GSPB3DV0W2gAg9MLvf/NBCtZu4Ljdf1kE7zDpr+menJ8WiPD Q6VzloXJiawrRnT9SHPrkLg3Q1piptDV8S6TDRQQSH90+rlswdUILA9U+Fy6pq+HbKmN L3IO/IBah/ENuZgtQYlbg2CimXtvQDn4/eHTxn/Bf4sabsnEqPR/Iyy+IJbEgtqCvk6i zUfIZXLmnrOyZMBQcDG/piT+IPGf0Kxt1z3NwIEOCr25R16e+frgv/byblQ4lFPR8+YU w2OxleBoMV5oOq68owAXKHkh8llWygEV15Em+W+3MB0xD9cx7P7qrT5T+sJr7y5Sc1tO Q+MA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=ktU1i38EF0XodHOZOm5xF+x1IfDjf7SKxUzqbl77NOg=; b=Q3oHtK7OEHQORCZOP0rSe23fPHu+5MZTpNKCa34yDoaPVAZEfXES88RkqmnM/uOs43 q9/x3m/0RL7PiPdfyM4A0nGSSquQnmsPJdelVV4ArkPqhlldj8TeJSvMArdas629ntqQ gJg5EaN56q4kwVyLvyZFBamigo+wtBMRCrRk3kcfarmUyp18XKgmG2bNpNPNagdST6yp vLUPUihKjac0V6LbY1HI9KdJ8LE0ot1ZfMze0jOR80FHtEBI4CI1E1s2ha6BD91hynpe pybyI/8Nabt2VwH9p5XciIQXu7UcqX3mB+aXwirh/2F+/s0bempEvzA9/5ZiDTwxISv+ tfJQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v187si353320pfv.25.2018.03.13.08.43.26; Tue, 13 Mar 2018 08:43:41 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964876AbeCMPlr (ORCPT + 99 others); Tue, 13 Mar 2018 11:41:47 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:37034 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934523AbeCMPlg (ORCPT ); Tue, 13 Mar 2018 11:41:36 -0400 Received: from localhost (LFbn-1-12258-90.w90-92.abo.wanadoo.fr [90.92.71.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 7903C1206; Tue, 13 Mar 2018 15:41:17 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, David Woodhouse , "Peter Zijlstra (Intel)" , David Woodhouse , Thomas Gleixner , Josh Poimboeuf , Andy Lutomirski , Arjan van de Ven , Borislav Petkov , Dan Williams , Dave Hansen , Linus Torvalds , Ingo Molnar Subject: [PATCH 4.14 132/140] objtool: Add retpoline validation Date: Tue, 13 Mar 2018 16:25:35 +0100 Message-Id: <20180313152507.046143471@linuxfoundation.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180313152458.201155692@linuxfoundation.org> References: <20180313152458.201155692@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.14-stable review patch. If anyone has any objections, please let me know. ------------------ From: Peter Zijlstra commit b5bc2231b8ad4387c9641f235ca0ad8cd300b6df upstream. David requested a objtool validation pass for CONFIG_RETPOLINE=y enabled builds, where it validates no unannotated indirect jumps or calls are left. Add an additional .discard.retpoline_safe section to allow annotating the few indirect sites that are required and safe. Requested-by: David Woodhouse Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: David Woodhouse Acked-by: Thomas Gleixner Acked-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: Greg Kroah-Hartman Cc: Linus Torvalds Cc: Peter Zijlstra Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- scripts/Makefile.build | 4 + tools/objtool/builtin-check.c | 3 - tools/objtool/builtin.h | 2 tools/objtool/check.c | 86 +++++++++++++++++++++++++++++++++++++++++- tools/objtool/check.h | 1 5 files changed, 93 insertions(+), 3 deletions(-) --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -269,6 +269,10 @@ objtool_args += --no-unreachable else objtool_args += $(call cc-ifversion, -lt, 0405, --no-unreachable) endif +ifdef CONFIG_RETPOLINE + objtool_args += --retpoline +endif + ifdef CONFIG_MODVERSIONS objtool_o = $(@D)/.tmp_$(@F) --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -29,7 +29,7 @@ #include "builtin.h" #include "check.h" -bool no_fp, no_unreachable; +bool no_fp, no_unreachable, retpoline; static const char * const check_usage[] = { "objtool check [] file.o", @@ -39,6 +39,7 @@ static const char * const check_usage[] const struct option check_options[] = { OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), + OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), OPT_END(), }; --- a/tools/objtool/builtin.h +++ b/tools/objtool/builtin.h @@ -20,7 +20,7 @@ #include extern const struct option check_options[]; -extern bool no_fp, no_unreachable; +extern bool no_fp, no_unreachable, retpoline; extern int cmd_check(int argc, const char **argv); extern int cmd_orc(int argc, const char **argv); --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -496,6 +496,7 @@ static int add_jump_destinations(struct * disguise, so convert them accordingly. */ insn->type = INSN_JUMP_DYNAMIC; + insn->retpoline_safe = true; continue; } else { /* sibling call */ @@ -547,7 +548,8 @@ static int add_call_destinations(struct if (!insn->call_dest && !insn->ignore) { WARN_FUNC("unsupported intra-function call", insn->sec, insn->offset); - WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); + if (retpoline) + WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); return -1; } @@ -1107,6 +1109,54 @@ static int read_unwind_hints(struct objt return 0; } +static int read_retpoline_hints(struct objtool_file *file) +{ + struct section *sec, *relasec; + struct instruction *insn; + struct rela *rela; + int i; + + sec = find_section_by_name(file->elf, ".discard.retpoline_safe"); + if (!sec) + return 0; + + relasec = sec->rela; + if (!relasec) { + WARN("missing .rela.discard.retpoline_safe section"); + return -1; + } + + if (sec->len % sizeof(unsigned long)) { + WARN("retpoline_safe 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 retpoline_safe[%d]", i); + return -1; + } + + insn = find_insn(file, rela->sym->sec, rela->addend); + if (!insn) { + WARN("can't find insn for retpoline_safe[%d]", i); + return -1; + } + + if (insn->type != INSN_JUMP_DYNAMIC && + insn->type != INSN_CALL_DYNAMIC) { + WARN_FUNC("retpoline_safe hint not a indirect jump/call", + insn->sec, insn->offset); + return -1; + } + + insn->retpoline_safe = true; + } + + return 0; +} + static int decode_sections(struct objtool_file *file) { int ret; @@ -1145,6 +1195,10 @@ static int decode_sections(struct objtoo if (ret) return ret; + ret = read_retpoline_hints(file); + if (ret) + return ret; + return 0; } @@ -1890,6 +1944,29 @@ static int validate_unwind_hints(struct return warnings; } +static int validate_retpoline(struct objtool_file *file) +{ + struct instruction *insn; + int warnings = 0; + + for_each_insn(file, insn) { + if (insn->type != INSN_JUMP_DYNAMIC && + insn->type != INSN_CALL_DYNAMIC) + continue; + + if (insn->retpoline_safe) + continue; + + WARN_FUNC("indirect %s found in RETPOLINE build", + insn->sec, insn->offset, + insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); + + warnings++; + } + + return warnings; +} + static bool is_kasan_insn(struct instruction *insn) { return (insn->type == INSN_CALL && @@ -2050,6 +2127,13 @@ int check(const char *_objname, bool orc if (list_empty(&file.insn_list)) goto out; + if (retpoline) { + ret = validate_retpoline(&file); + if (ret < 0) + return ret; + warnings += ret; + } + ret = validate_functions(&file); if (ret < 0) goto out; --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -45,6 +45,7 @@ struct instruction { unsigned char type; unsigned long immediate; bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; + bool retpoline_safe; struct symbol *call_dest; struct instruction *jump_dest; struct instruction *first_jump_src;