Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Tue, 15 Jan 2019 13:56:40 -0500
From: Ruslan Nikolaev <nruslan_devel@...oo.com>
To: kernel-hardening@...ts.openwall.com
Cc: thgarnie@...gle.com, x86@...nel.org, kstewart@...uxfoundation.org,
 gregkh@...uxfoundation.org, keescook@...omium.org
Subject: [PATCH v1 01/06]: Extending objtool for PIC modules

Extending objtool for PIC modules

The patch is by Hassan Nadeem and Ruslan Nikolaev. This extends
the prior PIE kernel patch (by Thomas Garnier) to also support
position-independent modules that can be placed anywhere in the
48/64-bit address space (for better KASLR).

Signed-off-by: Ruslan Nikolaev <nruslan_devel@...oo.com>
---
  check.c |   39 ++++++++++++++++++++++++++++-----------
  1 file changed, 28 insertions(+), 11 deletions(-)

diff -uprN a/tools/objtool/check.c b/tools/objtool/check.c
--- a/tools/objtool/check.c	2019-01-15 11:20:46.047176216 -0500
+++ b/tools/objtool/check.c	2019-01-15 11:20:57.727294197 -0500
@@ -179,7 +179,7 @@ static int __dead_end_function(struct ob
  		return 0;

  	insn = find_insn(file, func->sec, func->offset);
-	if (!insn->func)
+	if (!insn || !insn->func)
  		return 0;

  	func_for_each_insn_all(file, func, insn) {
@@ -233,6 +233,8 @@ static int __dead_end_function(struct ob

  static int dead_end_function(struct objtool_file *file, struct symbol 
*func)
  {
+	if (!func)
+		return 0;
  	return __dead_end_function(file, func, 0);
  }

@@ -581,7 +583,7 @@ static int add_call_destinations(struct
  	struct rela *rela;

  	for_each_insn(file, insn) {
-		if (insn->type != INSN_CALL)
+		if (insn->type != INSN_CALL && insn->type != INSN_CALL_DYNAMIC)
  			continue;

  		rela = find_rela_by_dest_range(insn->sec, insn->offset,
@@ -590,8 +592,8 @@ static int add_call_destinations(struct
  			dest_off = insn->offset + insn->len + insn->immediate;
  			insn->call_dest = find_symbol_by_offset(insn->sec,
  								dest_off);
-
-			if (!insn->call_dest && !insn->ignore) {
+			if (!insn->call_dest && !insn->ignore &&
+			    insn->type != INSN_CALL_DYNAMIC) {
  				WARN_FUNC("unsupported intra-function call",
  					  insn->sec, insn->offset);
  				if (retpoline)
@@ -602,8 +604,9 @@ static int add_call_destinations(struct
  		} else if (rela->sym->type == STT_SECTION) {
  			insn->call_dest = find_symbol_by_offset(rela->sym->sec,
  								rela->addend+4);
-			if (!insn->call_dest ||
-			    insn->call_dest->type != STT_FUNC) {
+			if ((!insn->call_dest ||
+			     insn->call_dest->type != STT_FUNC) &&
+			    insn->type != INSN_CALL_DYNAMIC) {
  				WARN_FUNC("can't find call dest symbol at %s+0x%x",
  					  insn->sec, insn->offset,
  					  rela->sym->sec->name,
@@ -836,6 +839,11 @@ static int add_switch_table(struct objto
  	struct symbol *pfunc = insn->func->pfunc;
  	unsigned int prev_offset = 0;

+	/* If PC32 relocations are used (as in PIC), the following logic
+	 * can be broken in many ways.
+	 */
+	if (file->ignore_unreachables)
+		return 0;
  	list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
  		if (rela == next_table)
  			break;
@@ -1244,7 +1252,7 @@ static int decode_sections(struct objtoo

  static bool is_fentry_call(struct instruction *insn)
  {
-	if (insn->type == INSN_CALL &&
+	if (insn->call_dest &&
  	    insn->call_dest->type == STT_NOTYPE &&
  	    !strcmp(insn->call_dest->name, "__fentry__"))
  		return true;
@@ -1889,6 +1897,7 @@ static int validate_branch(struct objtoo
  			return 0;

  		case INSN_CALL:
+		case INSN_CALL_DYNAMIC:
  			if (is_fentry_call(insn))
  				break;

@@ -1898,8 +1907,6 @@ static int validate_branch(struct objtoo
  			if (ret == -1)
  				return 1;

-			/* fallthrough */
-		case INSN_CALL_DYNAMIC:
  			if (!no_fp && func && !has_valid_stack_frame(&state)) {
  				WARN_FUNC("call without frame pointer save/setup",
  					  sec, insn->offset);
@@ -1929,12 +1936,15 @@ static int validate_branch(struct objtoo
  			break;

  		case INSN_JUMP_DYNAMIC:
+			/* XXX: Does not work properly with PIC code. */
+#if 0
  			if (func && list_empty(&insn->alts) &&
  			    has_modified_stack_frame(&state)) {
  				WARN_FUNC("sibling call from callable instruction with modified 
stack frame",
  					  sec, insn->offset);
  				return 1;
  			}
+#endif

  			return 0;

@@ -2015,6 +2025,11 @@ static int validate_retpoline(struct obj
  		if (!strcmp(insn->sec->name, ".init.text") && !module)
  			continue;

+		/* ignore ftrace calls in PIC code */
+		if (!insn->call_dest ||
+		    !strcmp(insn->call_dest->name, "__fentry__"))
+			continue;
+
  		WARN_FUNC("indirect %s found in RETPOLINE build",
  			  insn->sec, insn->offset,
  			  insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
@@ -2027,13 +2042,15 @@ static int validate_retpoline(struct obj

  static bool is_kasan_insn(struct instruction *insn)
  {
-	return (insn->type == INSN_CALL &&
+	return ((insn->type == INSN_CALL || insn->type == INSN_CALL_DYNAMIC) &&
+		insn->call_dest &&
  		!strcmp(insn->call_dest->name, "__asan_handle_no_return"));
  }

  static bool is_ubsan_insn(struct instruction *insn)
  {
-	return (insn->type == INSN_CALL &&
+	return ((insn->type == INSN_CALL || insn->type == INSN_CALL_DYNAMIC) &&
+		insn->call_dest &&
  		!strcmp(insn->call_dest->name,
  			"__ubsan_handle_builtin_unreachable"));
  }

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.