Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932098AbbGQREV (ORCPT ); Fri, 17 Jul 2015 13:04:21 -0400 Received: from mx1.redhat.com ([209.132.183.28]:51316 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752840AbbGQQ50 (ORCPT ); Fri, 17 Jul 2015 12:57:26 -0400 From: Josh Poimboeuf To: Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" Cc: Michal Marek , Peter Zijlstra , Andy Lutomirski , Borislav Petkov , Linus Torvalds , Andi Kleen , Pedro Alves , x86@kernel.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 01/21] stackvalidate: Process ignores earlier and add more ignore checks Date: Fri, 17 Jul 2015 11:47:17 -0500 Message-Id: <84e0162c72b86f74538a06120b7389c4d83d9452.1437150175.git.jpoimboe@redhat.com> In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5305 Lines: 178 Process the ignore macros earlier and associate them with their corresponding instructions. This allows ignores to be checked in get_jump_destinations() which is needed for some funky xen code which introduces fake instructions (XEN_EMULATE_PREFIX). Signed-off-by: Josh Poimboeuf --- scripts/stackvalidate/stackvalidate.c | 77 +++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/scripts/stackvalidate/stackvalidate.c b/scripts/stackvalidate/stackvalidate.c index a817130..6173412 100644 --- a/scripts/stackvalidate/stackvalidate.c +++ b/scripts/stackvalidate/stackvalidate.c @@ -49,7 +49,7 @@ struct instruction { unsigned int len, state; unsigned char type; unsigned long immediate; - bool alt_group, visited; + bool alt_group, visited, ignore; struct symbol *call_dest; struct instruction *jump_dest; struct list_head alts; @@ -106,8 +106,7 @@ static struct argp argp = { options, parse_opt, args_doc, 0 }; /* * Check for the STACKVALIDATE_IGNORE_INSN macro. */ -static bool ignore_insn(struct elf *elf, struct section *sec, - unsigned long offset) +static bool ignore_insn(struct elf *elf, struct instruction *insn) { struct section *macro_sec; struct rela *rela; @@ -118,8 +117,8 @@ static bool ignore_insn(struct elf *elf, struct section *sec, list_for_each_entry(rela, ¯o_sec->rela->relas, list) if (rela->sym->type == STT_SECTION && - rela->sym == sec->sym && - rela->addend == offset) + rela->sym == insn->sec->sym && + rela->addend == insn->offset) return true; return false; @@ -138,9 +137,11 @@ static bool ignore_func(struct elf *elf, struct symbol *func) return false; list_for_each_entry(rela, ¯o_sec->rela->relas, list) - if (rela->sym == func) + if (rela->sym->sec == func->sec && + rela->addend == func->offset) return true; + return false; } @@ -266,6 +267,44 @@ static int decode_instructions(struct elf *elf) } /* + * Warnings shouldn't be reported for ignored instructions. Set insn->ignore + * for each ignored instruction and each instruction contained in an ignored + * function. + */ +static void get_ignores(struct elf *elf) +{ + struct instruction *insn; + struct section *sec; + struct symbol *func; + + list_for_each_entry(insn, &insns, list) + insn->ignore = ignore_insn(elf, insn); + + list_for_each_entry(sec, &elf->sections, list) { + list_for_each_entry(func, &sec->symbols, list) { + if (func->type != STT_FUNC) + continue; + + if (!ignore_func(elf, func)) + continue; + + insn = find_instruction(sec, func->offset); + if (!insn) + continue; + + list_for_each_entry_from(insn, &insns, list) { + if (insn->sec != func->sec || + insn->offset >= func->offset + func->len) + break; + + insn->ignore = true; + insn->visited = true; + } + } + } +} + +/* * Find the destination instructions for all jumps. */ static int get_jump_destinations(struct elf *elf) @@ -300,7 +339,7 @@ static int get_jump_destinations(struct elf *elf) } insn->jump_dest = find_instruction(dest_sec, dest_off); - if (!insn->jump_dest) { + if (!insn->jump_dest && !insn->ignore) { /* * This is a special case where an alt instruction @@ -591,6 +630,8 @@ static int decode_sections(struct elf *elf) if (ret) return ret; + get_ignores(elf); + ret = get_jump_destinations(elf); if (ret) return ret; @@ -734,7 +775,8 @@ static int validate_branch(struct elf *elf, struct instruction *first, break; case INSN_JUMP_DYNAMIC: - if (list_empty(&insn->alts) && insn->state) { + if (list_empty(&insn->alts) && insn->state && + !insn->ignore) { WARN("%s: sibling call from callable instruction with changed frame pointer", offstr(sec, insn->offset)); warnings++; @@ -743,9 +785,11 @@ static int validate_branch(struct elf *elf, struct instruction *first, return warnings; case INSN_CONTEXT_SWITCH: - WARN("%s: kernel entry/exit from callable instruction", - offstr(sec, insn->offset)); - warnings++; + if (!insn->ignore) { + WARN("%s: kernel entry/exit from callable instruction", + offstr(sec, insn->offset)); + warnings++; + } return warnings; @@ -786,15 +830,6 @@ static int validate_functions(struct elf *elf) continue; } - if (ignore_func(elf, func)) { - list_for_each_entry_from(insn, &insns, list) { - if (insn->sec != func->sec || - insn->offset >= func->offset + func->len) - break; - insn->visited = true; - } - } - ret = validate_branch(elf, insn, 0); warnings += ret; } @@ -835,7 +870,7 @@ static int validate_uncallable_instructions(struct elf *elf) list_for_each_entry(insn, &insns, list) { if (!insn->visited && insn->type == INSN_RETURN && - !ignore_insn(elf, insn->sec, insn->offset)) { + !insn->ignore) { WARN("%s: return instruction outside of a callable function", offstr(insn->sec, insn->offset)); warnings++; -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/