[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <84e0162c72b86f74538a06120b7389c4d83d9452.1437150175.git.jpoimboe@redhat.com>
Date: Fri, 17 Jul 2015 11:47:17 -0500
From: Josh Poimboeuf <jpoimboe@...hat.com>
To: Thomas Gleixner <tglx@...utronix.de>,
Ingo Molnar <mingo@...hat.com>,
"H. Peter Anvin" <hpa@...or.com>
Cc: Michal Marek <mmarek@...e.cz>,
Peter Zijlstra <peterz@...radead.org>,
Andy Lutomirski <luto@...nel.org>,
Borislav Petkov <bp@...en8.de>,
Linus Torvalds <torvalds@...ux-foundation.org>,
Andi Kleen <andi@...stfloor.org>,
Pedro Alves <palves@...hat.com>, x86@...nel.org,
live-patching@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [RFC PATCH 01/21] stackvalidate: Process ignores earlier and add more ignore checks
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 <jpoimboe@...hat.com>
---
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@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists