Received: by 10.223.185.116 with SMTP id b49csp2197555wrg; Thu, 15 Feb 2018 07:59:26 -0800 (PST) X-Google-Smtp-Source: AH8x2247dXHuxodiojY3zIpfu6xxL5yisE9mMxXDRpVZ1uVXhMN7ZAZuPp6r6K3A6ZndDyP10psn X-Received: by 10.99.64.197 with SMTP id n188mr2586589pga.21.1518710365927; Thu, 15 Feb 2018 07:59:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518710365; cv=none; d=google.com; s=arc-20160816; b=M0tfPVgF83IhceD3XNRqefacnwyYJ/zdqhtqrJogd/xC2LBfVZ7L7jhEiqrd/X9pko JSvAwRkp7NglhxV/uzZgTmHFC58+dB/2lcOZmDPNxnuv0mHJVpujjHIMb7/08USFDEr0 CiGLShnjDao45Iiut1IAOurkLM/SRchM/zMkptQDZVMoEGH+amCvzhqOc4yxfgIwwItl WKS6xH2O2iZNh3pKOO54pg8zb2xnD8HUl+zTYIpHPDYRxLiNbMYBLWx+HDhmddha4QT0 cPk7/8d8GL7M0ZEJamaLi2+6s7Dbya8vL/Aath8CwdST5fETmsr18aH1VkI7OgJRxZuN AEsw== 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=U04OlZaEH1GUM0UhDNpKdLpIskHy3sJtUfAUIS1LO04=; b=B93Lsy71Cu6mrFi2p140uVAHSySj5OLr92b5FVPvXMcqlBxjNJYy5M5kF2VkmQaqTf 4/qoeOONIqW3iA7hdqcjWbE49aAkF5H2oQ5ALUT8NRXqCWmtfu5ulGOqU005EalgzIv2 hXqS1iC563jYQNN9ikD9X+iF1SkH7tYOQRvFYgLm2fhMZjfcVN2SNGoY4LYyn4T5T8uc uZO3rJj7w7x3i204oPiSeeIChvzvjw+0k8vZt/+ILzye2ruYGPz9NWXqvELMTB9DZzDT VdqamCJzFUCrXoneDDvDcAesKbkWcW7CUXMEanA90+w62QCu2pCCwixvWKU0sSRuQdIw XDoA== 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 q4-v6si1436084plb.124.2018.02.15.07.59.06; Thu, 15 Feb 2018 07:59:25 -0800 (PST) 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 S1425197AbeBOP56 (ORCPT + 99 others); Thu, 15 Feb 2018 10:57:58 -0500 Received: from mail.linuxfoundation.org ([140.211.169.12]:36078 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1424841AbeBOPrM (ORCPT ); Thu, 15 Feb 2018 10:47:12 -0500 Received: from localhost (LFbn-1-12258-90.w90-92.abo.wanadoo.fr [90.92.71.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id D1E62101F; Thu, 15 Feb 2018 15:47:11 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "Peter Zijlstra (Intel)" , Josh Poimboeuf , Borislav Petkov , Thomas Gleixner , Ingo Molnar Subject: [PATCH 4.15 187/202] objtool: Fix switch-table detection Date: Thu, 15 Feb 2018 16:18:07 +0100 Message-Id: <20180215151722.578198998@linuxfoundation.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180215151712.768794354@linuxfoundation.org> References: <20180215151712.768794354@linuxfoundation.org> User-Agent: quilt/0.65 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 99ce7962d52d1948ad6f2785e308d48e76e0a6ef upstream. Linus reported that GCC-7.3 generated a switch-table construct that confused objtool. It turns out that, in particular due to KASAN, it is possible to have unrelated .rodata usage in between the .rodata setup for the switch-table and the following indirect jump. The simple linear reverse search from the indirect jump would hit upon the KASAN .rodata usage first and fail to find a switch_table, resulting in a spurious 'sibling call with modified stack frame' warning. Fix this by creating a 'jump-stack' which we can 'unwind' during reversal, thereby skipping over much of the in-between code. This is not fool proof by any means, but is sufficient to make the known cases work. Future work would be to construct more comprehensive flow analysis code. Reported-and-tested-by: Linus Torvalds Signed-off-by: Peter Zijlstra (Intel) Acked-by: Josh Poimboeuf Cc: Borislav Petkov Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20180208130232.GF25235@hirez.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/objtool/check.c | 41 +++++++++++++++++++++++++++++++++++++++-- tools/objtool/check.h | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -851,8 +851,14 @@ static int add_switch_table(struct objto * This is a fairly uncommon pattern which is new for GCC 6. As of this * writing, there are 11 occurrences of it in the allmodconfig kernel. * + * As of GCC 7 there are quite a few more of these and the 'in between' code + * is significant. Esp. with KASAN enabled some of the code between the mov + * and jmpq uses .rodata itself, which can confuse things. + * * TODO: Once we have DWARF CFI and smarter instruction decoding logic, * ensure the same register is used in the mov and jump instructions. + * + * NOTE: RETPOLINE made it harder still to decode dynamic jumps. */ static struct rela *find_switch_table(struct objtool_file *file, struct symbol *func, @@ -874,12 +880,25 @@ static struct rela *find_switch_table(st text_rela->addend + 4); if (!rodata_rela) return NULL; + file->ignore_unreachables = true; return rodata_rela; } /* case 3 */ - func_for_each_insn_continue_reverse(file, func, insn) { + /* + * Backward search using the @first_jump_src links, these help avoid + * much of the 'in between' code. Which avoids us getting confused by + * it. + */ + for (insn = list_prev_entry(insn, list); + + &insn->list != &file->insn_list && + insn->sec == func->sec && + insn->offset >= func->offset; + + insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { + if (insn->type == INSN_JUMP_DYNAMIC) break; @@ -909,14 +928,32 @@ static struct rela *find_switch_table(st return NULL; } + static int add_func_switch_tables(struct objtool_file *file, struct symbol *func) { - struct instruction *insn, *prev_jump = NULL; + struct instruction *insn, *last = NULL, *prev_jump = NULL; struct rela *rela, *prev_rela = NULL; int ret; func_for_each_insn(file, func, insn) { + if (!last) + last = insn; + + /* + * Store back-pointers for unconditional forward jumps such + * that find_switch_table() can back-track using those and + * avoid some potentially confusing code. + */ + if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && + insn->offset > last->offset && + insn->jump_dest->offset > insn->offset && + !insn->jump_dest->first_jump_src) { + + insn->jump_dest->first_jump_src = insn; + last = insn->jump_dest; + } + if (insn->type != INSN_JUMP_DYNAMIC) continue; --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -47,6 +47,7 @@ struct instruction { bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; struct symbol *call_dest; struct instruction *jump_dest; + struct instruction *first_jump_src; struct list_head alts; struct symbol *func; struct stack_op stack_op;