lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 9 Mar 2016 03:45:29 -0800
From:	tip-bot for Josh Poimboeuf <tipbot@...or.com>
To:	linux-tip-commits@...r.kernel.org
Cc:	fengguang.wu@...el.com, tglx@...utronix.de, jpoimboe@...hat.com,
	namhyung@...il.com, luto@...nel.org, acme@...nel.org,
	jslaby@...e.cz, palves@...hat.com, akpm@...ux-foundation.org,
	bp@...en8.de, bernd@...rovitsch.priv.at, hpa@...or.com,
	mmarek@...e.cz, chris.j.arges@...onical.com, peterz@...radead.org,
	acme@...radead.org, torvalds@...ux-foundation.org,
	mingo@...nel.org, linux-kernel@...r.kernel.org
Subject: [tip:core/objtool] objtool: Fix false positive warnings for
 functions with multiple switch statements

Commit-ID:  8133fbb4240ae2918d993defa0f6824864412f56
Gitweb:     http://git.kernel.org/tip/8133fbb4240ae2918d993defa0f6824864412f56
Author:     Josh Poimboeuf <jpoimboe@...hat.com>
AuthorDate: Wed, 9 Mar 2016 00:06:58 -0600
Committer:  Ingo Molnar <mingo@...nel.org>
CommitDate: Wed, 9 Mar 2016 10:48:09 +0100

objtool: Fix false positive warnings for functions with multiple switch statements

Ingo reported [1] some false positive objtool warnings:

  drivers/net/wireless/realtek/rtlwifi/base.o: warning: objtool: rtlwifi_rate_mapping()+0x2e7: frame pointer state mismatch
  drivers/net/wireless/realtek/rtlwifi/base.o: warning: objtool: rtlwifi_rate_mapping()+0x2f3: frame pointer state mismatch
  ...

And so did the 0-day bot [2]:

  drivers/gpu/drm/radeon/cik.o: warning: objtool: cik_tiling_mode_table_init()+0x6ce: call without frame pointer save/setup
  drivers/gpu/drm/radeon/cik.o: warning: objtool: cik_tiling_mode_table_init()+0x72b: call without frame pointer save/setup
  ...

Both sets of warnings involve functions which have multiple switch
statements.  When there's more than one switch statement in a function,
objtool interprets all the switch jump tables as a single table.  If the
targets of one jump table assume a stack frame and the targets of
another one don't, it prints false positive warnings.

Fix the bug by detecting the size of each switch jump table.  For
multiple tables, each one ends where the next one begins.

[1] https://lkml.kernel.org/r/20160308103716.GA9618@gmail.com
[2] https://lists.01.org/pipermail/kbuild-all/2016-March/018124.html

Reported-by: Ingo Molnar <mingo@...nel.org>
Reported-by: kbuild test robot <fengguang.wu@...el.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@...hat.com>
Cc: Andrew Morton <akpm@...ux-foundation.org>
Cc: Andy Lutomirski <luto@...nel.org>
Cc: Arnaldo Carvalho de Melo <acme@...radead.org>
Cc: Arnaldo Carvalho de Melo <acme@...nel.org>
Cc: Bernd Petrovitsch <bernd@...rovitsch.priv.at>
Cc: Borislav Petkov <bp@...en8.de>
Cc: Chris J Arges <chris.j.arges@...onical.com>
Cc: Jiri Slaby <jslaby@...e.cz>
Cc: Linus Torvalds <torvalds@...ux-foundation.org>
Cc: Michal Marek <mmarek@...e.cz>
Cc: Namhyung Kim <namhyung@...il.com>
Cc: Pedro Alves <palves@...hat.com>
Cc: Peter Zijlstra <peterz@...radead.org>
Cc: Thomas Gleixner <tglx@...utronix.de>
Cc: live-patching@...r.kernel.org
Link: http://lkml.kernel.org/r/2d7eecc6bc52d301f494b80f5fd62c2b6c895658.1457502970.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@...nel.org>
---
 tools/objtool/builtin-check.c | 145 +++++++++++++++++++++++++++++-------------
 1 file changed, 100 insertions(+), 45 deletions(-)

diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index cdbdd7d..cf1e48d 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -61,6 +61,7 @@ struct alternative {
 struct objtool_file {
 	struct elf *elf;
 	struct list_head insn_list;
+	struct section *rodata;
 };
 
 const char *objname;
@@ -599,73 +600,125 @@ out:
 	return ret;
 }
 
-/*
- * For some switch statements, gcc generates a jump table in the .rodata
- * section which contains a list of addresses within the function to jump to.
- * This finds these jump tables and adds them to the insn->alts lists.
- */
-static int add_switch_table_alts(struct objtool_file *file)
+static int add_switch_table(struct objtool_file *file, struct symbol *func,
+			    struct instruction *insn, struct rela *table,
+			    struct rela *next_table)
 {
-	struct instruction *insn, *alt_insn;
-	struct rela *rodata_rela, *text_rela;
-	struct section *rodata;
-	struct symbol *func;
+	struct rela *rela = table;
+	struct instruction *alt_insn;
 	struct alternative *alt;
 
-	for_each_insn(file, insn) {
+	list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
+		if (rela == next_table)
+			break;
+
+		if (rela->sym->sec != insn->sec ||
+		    rela->addend <= func->offset ||
+		    rela->addend >= func->offset + func->len)
+			break;
+
+		alt_insn = find_insn(file, insn->sec, rela->addend);
+		if (!alt_insn) {
+			WARN("%s: can't find instruction at %s+0x%x",
+			     file->rodata->rela->name, insn->sec->name,
+			     rela->addend);
+			return -1;
+		}
+
+		alt = malloc(sizeof(*alt));
+		if (!alt) {
+			WARN("malloc failed");
+			return -1;
+		}
+
+		alt->insn = alt_insn;
+		list_add_tail(&alt->list, &insn->alts);
+	}
+
+	return 0;
+}
+
+static int add_func_switch_tables(struct objtool_file *file,
+				  struct symbol *func)
+{
+	struct instruction *insn, *prev_jump;
+	struct rela *text_rela, *rodata_rela, *prev_rela;
+	int ret;
+
+	prev_jump = NULL;
+
+	func_for_each_insn(file, func, insn) {
 		if (insn->type != INSN_JUMP_DYNAMIC)
 			continue;
 
 		text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
 						    insn->len);
-		if (!text_rela || strcmp(text_rela->sym->name, ".rodata"))
-			continue;
-
-		rodata = find_section_by_name(file->elf, ".rodata");
-		if (!rodata || !rodata->rela)
+		if (!text_rela || text_rela->sym != file->rodata->sym)
 			continue;
 
 		/* common case: jmpq *[addr](,%rax,8) */
-		rodata_rela = find_rela_by_dest(rodata, text_rela->addend);
+		rodata_rela = find_rela_by_dest(file->rodata,
+						text_rela->addend);
 
-		/* rare case:   jmpq *[addr](%rip) */
+		/*
+		 * TODO: Document where this is needed, or get rid of it.
+		 *
+		 * rare case:   jmpq *[addr](%rip)
+		 */
 		if (!rodata_rela)
-			rodata_rela = find_rela_by_dest(rodata,
+			rodata_rela = find_rela_by_dest(file->rodata,
 							text_rela->addend + 4);
+
 		if (!rodata_rela)
 			continue;
 
-		func = find_containing_func(insn->sec, insn->offset);
-		if (!func) {
-			WARN_FUNC("can't find containing func",
-				  insn->sec, insn->offset);
-			return -1;
+		/*
+		 * We found a switch table, but we don't know yet how big it
+		 * is.  Don't add it until we reach the end of the function or
+		 * the beginning of another switch table in the same function.
+		 */
+		if (prev_jump) {
+			ret = add_switch_table(file, func, prev_jump, prev_rela,
+					       rodata_rela);
+			if (ret)
+				return ret;
 		}
 
-		list_for_each_entry_from(rodata_rela, &rodata->rela->rela_list,
-					 list) {
-			if (rodata_rela->sym->sec != insn->sec ||
-			    rodata_rela->addend <= func->offset ||
-			    rodata_rela->addend >= func->offset + func->len)
-				break;
+		prev_jump = insn;
+		prev_rela = rodata_rela;
+	}
 
-			alt_insn = find_insn(file, insn->sec,
-					     rodata_rela->addend);
-			if (!alt_insn) {
-				WARN("%s: can't find instruction at %s+0x%x",
-				     rodata->rela->name, insn->sec->name,
-				     rodata_rela->addend);
-				return -1;
-			}
+	if (prev_jump) {
+		ret = add_switch_table(file, func, prev_jump, prev_rela, NULL);
+		if (ret)
+			return ret;
+	}
 
-			alt = malloc(sizeof(*alt));
-			if (!alt) {
-				WARN("malloc failed");
-				return -1;
-			}
+	return 0;
+}
 
-			alt->insn = alt_insn;
-			list_add_tail(&alt->list, &insn->alts);
+/*
+ * For some switch statements, gcc generates a jump table in the .rodata
+ * section which contains a list of addresses within the function to jump to.
+ * This finds these jump tables and adds them to the insn->alts lists.
+ */
+static int add_switch_table_alts(struct objtool_file *file)
+{
+	struct section *sec;
+	struct symbol *func;
+	int ret;
+
+	if (!file->rodata || !file->rodata->rela)
+		return 0;
+
+	list_for_each_entry(sec, &file->elf->sections, list) {
+		list_for_each_entry(func, &sec->symbol_list, list) {
+			if (func->type != STT_FUNC)
+				continue;
+
+			ret = add_func_switch_tables(file, func);
+			if (ret)
+				return ret;
 		}
 	}
 
@@ -676,6 +729,8 @@ static int decode_sections(struct objtool_file *file)
 {
 	int ret;
 
+	file->rodata = find_section_by_name(file->elf, ".rodata");
+
 	ret = decode_instructions(file);
 	if (ret)
 		return ret;

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ