Received: by 10.213.65.68 with SMTP id h4csp456669imn; Tue, 13 Mar 2018 09:38:03 -0700 (PDT) X-Google-Smtp-Source: AG47ELt59AaI4sNYyem+fhWjTsPf53A3D49q4mDf1CGvropLblZCUbQ13IvTaWUoU4piIEp2qXKQ X-Received: by 10.98.13.24 with SMTP id v24mr1181071pfi.89.1520959083434; Tue, 13 Mar 2018 09:38:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1520959083; cv=none; d=google.com; s=arc-20160816; b=piHKqvZE4mK8hSSV1ZFSNov8rc0e0VK3CYLTpnUscqJg242vyHCnINHQqkWzGvZPlQ gjbOql43qp68xL86AQnO+Ye6ZLxrwuXg7bB8bLmQGQ4yumkhP5/YOlQ6xXdSE4c83YEv CyV+OR+rV8OxOr0XICMGLmjjIRpvgIHcmmMz4qheDyrDJGhwy646MpJvPwBOjuxoihfD zsMRSWvxlSSgBf/Y4ZrUua9P2DcgXAMYYvLDHKEMT5m8Vdh4WzY7Ec5rRUviEyWL7B7H 8krGz1nIez1MXx+RHIgX09LbRNPwN50Ru3frKXOBmrwyYL2Gs3NszVwu1O9jK3KqdD0h viKw== 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=g6J/usBJ0Q0CI5oLKVLjLkmLFm3gghFUysmKA2WRz/I=; b=Ci/h5D3tFfmF5sIHLX0X/yKwqRLk/Jsx8zInRtOs4lLK4Hays7e6UXd09j9pxfJQl0 fNrVya6jOTzvHDVpxUqXYzu1gtBTooZxfEroHLToedlHMUa1YDVdH3FJvHZJ6zsUA29K LwMuekP5apdr+NAa+dUoDI8N2bcAUlKzZYfAjUy1yNN8GyQ6GbI+zuUz/4n8P+FdQL5s WhK97+XiqdraC+AGnqHGYhXo9iDRmSp1t9dFcqoU7Kc2al4e1tBNBjUXxHzHVisGVARX Fpbl3iAMTd541kZBS2GrzoQl8cXuIji0/A7oQvy/0bnpMNksIel7/ODcgQriHNZhfqVc x3Ag== 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 j2si327716pff.214.2018.03.13.09.37.49; Tue, 13 Mar 2018 09:38:03 -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 S933290AbeCMQgd (ORCPT + 99 others); Tue, 13 Mar 2018 12:36:33 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:59814 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752981AbeCMPca (ORCPT ); Tue, 13 Mar 2018 11:32:30 -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 5026BF8F; Tue, 13 Mar 2018 15:32:29 +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.15 098/146] objtool: Add retpoline validation Date: Tue, 13 Mar 2018 16:24:25 +0100 Message-Id: <20180313152328.145234083@linuxfoundation.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180313152320.439085687@linuxfoundation.org> References: <20180313152320.439085687@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.15-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 @@ -264,6 +264,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;