From 050e57fd5936eb175cbb7a788252aa6867201120 Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:41:04 +0930
Subject: modpost: add strict white-listing when referencing sections.

Prints a warning when a section references a section outside a strict
white-list.  This will be useful to print a warning if __ex_table
references a non-executable section.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index d439856f8176..7094a57273b9 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -925,7 +925,8 @@ enum mismatch {
 
 struct sectioncheck {
 	const char *fromsec[20];
-	const char *tosec[20];
+	const char *bad_tosec[20];
+	const char *good_tosec[20];
 	enum mismatch mismatch;
 	const char *symbol_white_list[20];
 };
@@ -936,19 +937,19 @@ static const struct sectioncheck sectioncheck[] = {
  */
 {
 	.fromsec = { TEXT_SECTIONS, NULL },
-	.tosec   = { ALL_INIT_SECTIONS, NULL },
+	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
 	.mismatch = TEXT_TO_ANY_INIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
 	.fromsec = { DATA_SECTIONS, NULL },
-	.tosec   = { ALL_XXXINIT_SECTIONS, NULL },
+	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
 	.mismatch = DATA_TO_ANY_INIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
 	.fromsec = { DATA_SECTIONS, NULL },
-	.tosec   = { INIT_SECTIONS, NULL },
+	.bad_tosec = { INIT_SECTIONS, NULL },
 	.mismatch = DATA_TO_ANY_INIT,
 	.symbol_white_list = {
 		"*_template", "*_timer", "*_sht", "*_ops",
@@ -957,54 +958,54 @@ static const struct sectioncheck sectioncheck[] = {
 },
 {
 	.fromsec = { TEXT_SECTIONS, NULL },
-	.tosec   = { ALL_EXIT_SECTIONS, NULL },
+	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
 	.mismatch = TEXT_TO_ANY_EXIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
 	.fromsec = { DATA_SECTIONS, NULL },
-	.tosec   = { ALL_EXIT_SECTIONS, NULL },
+	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
 	.mismatch = DATA_TO_ANY_EXIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not reference init code/data from meminit code/data */
 {
 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
-	.tosec   = { INIT_SECTIONS, NULL },
+	.bad_tosec = { INIT_SECTIONS, NULL },
 	.mismatch = XXXINIT_TO_SOME_INIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not reference exit code/data from memexit code/data */
 {
 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
-	.tosec   = { EXIT_SECTIONS, NULL },
+	.bad_tosec = { EXIT_SECTIONS, NULL },
 	.mismatch = XXXEXIT_TO_SOME_EXIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not use exit code/data from init code */
 {
 	.fromsec = { ALL_INIT_SECTIONS, NULL },
-	.tosec   = { ALL_EXIT_SECTIONS, NULL },
+	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
 	.mismatch = ANY_INIT_TO_ANY_EXIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 /* Do not use init code/data from exit code */
 {
 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
-	.tosec   = { ALL_INIT_SECTIONS, NULL },
+	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
 	.mismatch = ANY_EXIT_TO_ANY_INIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 },
 {
 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
-	.tosec   = { INIT_SECTIONS, NULL },
+	.bad_tosec = { INIT_SECTIONS, NULL },
 	.mismatch = ANY_INIT_TO_ANY_EXIT,
 	.symbol_white_list = { NULL },
 },
 /* Do not export init/exit functions or data */
 {
 	.fromsec = { "__ksymtab*", NULL },
-	.tosec   = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
+	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
 	.mismatch = EXPORT_TO_INIT_EXIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
 }
@@ -1018,9 +1019,12 @@ static const struct sectioncheck *section_mismatch(
 	const struct sectioncheck *check = &sectioncheck[0];
 
 	for (i = 0; i < elems; i++) {
-		if (match(fromsec, check->fromsec) &&
-		    match(tosec, check->tosec))
-			return check;
+		if (match(fromsec, check->fromsec)) {
+			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
+				return check;
+			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
+				return check;
+		}
 		check++;
 	}
 	return NULL;
-- 
cgit v1.2.1


From 157d1972d079207332d31a761cdfb81598455e0a Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:42:52 +0930
Subject: modpost: add .sched.text and .kprobes.text to the TEXT_SECTIONS list.

sched.text and .kprobes.text should behave exactly like .text with regards
to how we should warn about referencing sections which might get discarded
at runtime.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 7094a57273b9..8cef46b18dc6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -873,7 +873,8 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
 
 #define DATA_SECTIONS ".data", ".data.rel"
-#define TEXT_SECTIONS ".text", ".text.unlikely"
+#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
+		".kprobes.text"
 
 #define INIT_SECTIONS      ".init.*"
 #define MEM_INIT_SECTIONS  ".meminit.*"
-- 
cgit v1.2.1


From 644e8f14cb3bca5c66f6ddd944d9d26074eec46e Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:43:17 +0930
Subject: modpost: add handler function pointer to sectioncheck.

This will be useful when we want to have special handlers which need to go
through more hops to print useful information to the user.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 68 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 42 insertions(+), 26 deletions(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8cef46b18dc6..0f48f8b97b17 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -930,6 +930,10 @@ struct sectioncheck {
 	const char *good_tosec[20];
 	enum mismatch mismatch;
 	const char *symbol_white_list[20];
+	void (*handler)(const char *modname, struct elf_info *elf,
+			const struct sectioncheck* const mismatch,
+			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
+
 };
 
 static const struct sectioncheck sectioncheck[] = {
@@ -1417,37 +1421,49 @@ static void report_sec_mismatch(const char *modname,
 	fprintf(stderr, "\n");
 }
 
-static void check_section_mismatch(const char *modname, struct elf_info *elf,
-				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+static void default_mismatch_handler(const char *modname, struct elf_info *elf,
+				     const struct sectioncheck* const mismatch,
+				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
 {
 	const char *tosec;
-	const struct sectioncheck *mismatch;
+	Elf_Sym *to;
+	Elf_Sym *from;
+	const char *tosym;
+	const char *fromsym;
 
 	tosec = sec_name(elf, get_secindex(elf, sym));
-	mismatch = section_mismatch(fromsec, tosec);
+	from = find_elf_symbol2(elf, r->r_offset, fromsec);
+	fromsym = sym_name(elf, from);
+	to = find_elf_symbol(elf, r->r_addend, sym);
+	tosym = sym_name(elf, to);
+
+	if (!strncmp(fromsym, "reference___initcall",
+		     sizeof("reference___initcall")-1))
+		return;
+
+	/* check whitelist - we may ignore it */
+	if (secref_whitelist(mismatch,
+			     fromsec, fromsym, tosec, tosym)) {
+		report_sec_mismatch(modname, mismatch,
+				    fromsec, r->r_offset, fromsym,
+				    is_function(from), tosec, tosym,
+				    is_function(to));
+	}
+}
+
+static void check_section_mismatch(const char *modname, struct elf_info *elf,
+				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+{
+	const char *tosec = sec_name(elf, get_secindex(elf, sym));;
+	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
+
 	if (mismatch) {
-		Elf_Sym *to;
-		Elf_Sym *from;
-		const char *tosym;
-		const char *fromsym;
-
-		from = find_elf_symbol2(elf, r->r_offset, fromsec);
-		fromsym = sym_name(elf, from);
-		to = find_elf_symbol(elf, r->r_addend, sym);
-		tosym = sym_name(elf, to);
-
-		if (!strncmp(fromsym, "reference___initcall",
-				sizeof("reference___initcall")-1))
-			return;
-
-		/* check whitelist - we may ignore it */
-		if (secref_whitelist(mismatch,
-					fromsec, fromsym, tosec, tosym)) {
-			report_sec_mismatch(modname, mismatch,
-			   fromsec, r->r_offset, fromsym,
-			   is_function(from), tosec, tosym,
-			   is_function(to));
-		}
+		if (mismatch->handler)
+			mismatch->handler(modname, elf,  mismatch,
+					  r, sym, fromsec);
+		else
+			default_mismatch_handler(modname, elf, mismatch,
+						 r, sym, fromsec);
 	}
 }
 
-- 
cgit v1.2.1


From 356ad538128ed9221f7d01199a3a7d080f158a5d Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:43:34 +0930
Subject: modpost: factorize symbol pretty print in get_pretty_name().

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 0f48f8b97b17..c69681e815b2 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1270,6 +1270,15 @@ static void print_section_list(const char * const list[20])
 	fprintf(stderr, "\n");
 }
 
+static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
+{
+	switch (is_func) {
+	case 0:	*name = "variable"; *name_p = ""; break;
+	case 1:	*name = "function"; *name_p = "()"; break;
+	default: *name = "(unknown reference)"; *name_p = ""; break;
+	}
+}
+
 /*
  * Print a warning about a section mismatch.
  * Try to find symbols near it so user can find it.
@@ -1289,21 +1298,13 @@ static void report_sec_mismatch(const char *modname,
 	char *prl_from;
 	char *prl_to;
 
-	switch (from_is_func) {
-	case 0: from = "variable"; from_p = "";   break;
-	case 1: from = "function"; from_p = "()"; break;
-	default: from = "(unknown reference)"; from_p = ""; break;
-	}
-	switch (to_is_func) {
-	case 0: to = "variable"; to_p = "";   break;
-	case 1: to = "function"; to_p = "()"; break;
-	default: to = "(unknown reference)"; to_p = ""; break;
-	}
-
 	sec_mismatch_count++;
 	if (!sec_mismatch_verbose)
 		return;
 
+	get_pretty_name(from_is_func, &from, &from_p);
+	get_pretty_name(to_is_func, &to, &to_p);
+
 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
 	     "to the %s %s:%s%s\n",
 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
-- 
cgit v1.2.1


From c7a65e0645b2d1f8382ce27f4edaf1b4f2e09549 Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:43:45 +0930
Subject: modpost: mismatch_handler: retrieve tosym information only when
 needed.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index c69681e815b2..bf0cf8173beb 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1432,16 +1432,17 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
 	const char *tosym;
 	const char *fromsym;
 
-	tosec = sec_name(elf, get_secindex(elf, sym));
 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
 	fromsym = sym_name(elf, from);
-	to = find_elf_symbol(elf, r->r_addend, sym);
-	tosym = sym_name(elf, to);
 
 	if (!strncmp(fromsym, "reference___initcall",
 		     sizeof("reference___initcall")-1))
 		return;
 
+	tosec = sec_name(elf, get_secindex(elf, sym));
+	to = find_elf_symbol(elf, r->r_addend, sym);
+	tosym = sym_name(elf, to);
+
 	/* check whitelist - we may ignore it */
 	if (secref_whitelist(mismatch,
 			     fromsec, fromsym, tosec, tosym)) {
-- 
cgit v1.2.1


From c31e4b832f124dccdb5d80ba3c1cd4f9081f7fb2 Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:44:04 +0930
Subject: scripts: add check_extable.sh script.

This shell script can be used to sanity check the __ex_table section on an
object file, making sure the relocations in there are pointing to valid
executable sections.  If it finds some suspicious relocations, it'll use
addr2line to try and dump where this is coming from.

This works best with CONFIG_DEBUG_INFO.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/check_extable.sh | 146 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 146 insertions(+)
 create mode 100755 scripts/check_extable.sh

(limited to 'scripts')

diff --git a/scripts/check_extable.sh b/scripts/check_extable.sh
new file mode 100755
index 000000000000..0fb6b1c97c27
--- /dev/null
+++ b/scripts/check_extable.sh
@@ -0,0 +1,146 @@
+#! /bin/bash
+# (c) 2015, Quentin Casasnovas <quentin.casasnovas@oracle.com>
+
+obj=$1
+
+file ${obj} | grep -q ELF || (echo "${obj} is not and ELF file." 1>&2 ; exit 0)
+
+# Bail out early if there isn't an __ex_table section in this object file.
+objdump -hj __ex_table ${obj} 2> /dev/null > /dev/null
+[ $? -ne 0 ] && exit 0
+
+white_list=.text,.fixup
+
+suspicious_relocs=$(objdump -rj __ex_table ${obj}  | tail -n +6 |
+			grep -v $(eval echo -e{${white_list}}) | awk '{print $3}')
+
+# No suspicious relocs in __ex_table, jobs a good'un
+[ -z "${suspicious_relocs}" ] && exit 0
+
+
+# After this point, something is seriously wrong since we just found out we
+# have some relocations in __ex_table which point to sections which aren't
+# white listed.  If you're adding a new section in the Linux kernel, and
+# you're expecting this section to contain code which can fault (i.e. the
+# __ex_table relocation to your new section is expected), simply add your
+# new section to the white_list variable above.  If not, you're probably
+# doing something wrong and the rest of this code is just trying to print
+# you more information about it.
+
+function find_section_offset_from_symbol()
+{
+    eval $(objdump -t ${obj} | grep ${1} | sed 's/\([0-9a-f]\+\) .\{7\} \([^ \t]\+\).*/section="\2"; section_offset="0x\1" /')
+
+    # addr2line takes addresses in hexadecimal...
+    section_offset=$(printf "0x%016x" $(( ${section_offset} + $2 )) )
+}
+
+function find_symbol_and_offset_from_reloc()
+{
+    # Extract symbol and offset from the objdump output
+    eval $(echo $reloc | sed 's/\([^+]\+\)+\?\(0x[0-9a-f]\+\)\?/symbol="\1"; symbol_offset="\2"/')
+
+    # When the relocation points to the begining of a symbol or section, it
+    # won't print the offset since it is zero.
+    if [ -z "${symbol_offset}" ]; then
+	symbol_offset=0x0
+    fi
+}
+
+function find_alt_replacement_target()
+{
+    # The target of the .altinstr_replacement is the relocation just before
+    # the .altinstr_replacement one.
+    eval $(objdump -rj .altinstructions ${obj} | grep -B1 "${section}+${section_offset}" | head -n1 | awk '{print $3}' |
+	   sed 's/\([^+]\+\)+\(0x[0-9a-f]\+\)/alt_target_section="\1"; alt_target_offset="\2"/')
+}
+
+function handle_alt_replacement_reloc()
+{
+    # This will define alt_target_section and alt_target_section_offset
+    find_alt_replacement_target ${section} ${section_offset}
+
+    echo "Error: found a reference to .altinstr_replacement in __ex_table:"
+    addr2line -fip -j ${alt_target_section} -e ${obj} ${alt_target_offset} | awk '{print "\t" $0}'
+
+    error=true
+}
+
+function is_executable_section()
+{
+    objdump -hwj ${section} ${obj} | grep -q CODE
+    return $?
+}
+
+function handle_suspicious_generic_reloc()
+{
+    if is_executable_section ${section}; then
+	# We've got a relocation to a non white listed _executable_
+	# section, print a warning so the developper adds the section to
+	# the white list or fix his code.  We try to pretty-print the file
+	# and line number where that relocation was added.
+	echo "Warning: found a reference to section \"${section}\" in __ex_table:"
+	addr2line -fip -j ${section} -e ${obj} ${section_offset} | awk '{print "\t" $0}'
+    else
+	# Something is definitively wrong here since we've got a relocation
+	# to a non-executable section, there's no way this would ever be
+	# running in the kernel.
+	echo "Error: found a reference to non-executable section \"${section}\" in __ex_table at offset ${section_offset}"
+	error=true
+    fi
+}
+
+function handle_suspicious_reloc()
+{
+    case "${section}" in
+	".altinstr_replacement")
+	    handle_alt_replacement_reloc ${section} ${section_offset}
+	    ;;
+	*)
+	    handle_suspicious_generic_reloc ${section} ${section_offset}
+	    ;;
+    esac
+}
+
+function diagnose()
+{
+
+    for reloc in ${suspicious_relocs}; do
+	# Let's find out where the target of the relocation in __ex_table
+	# is, this will define ${symbol} and ${symbol_offset}
+	find_symbol_and_offset_from_reloc ${reloc}
+
+	# When there's a global symbol at the place of the relocation,
+	# objdump will use it instead of giving us a section+offset, so
+	# let's find out which section is this symbol in and the total
+	# offset withing that section.
+	find_section_offset_from_symbol ${symbol} ${symbol_offset}
+
+	# In this case objdump was presenting us with a reloc to a symbol
+	# rather than a section. Now that we've got the actual section,
+	# we can skip it if it's in the white_list.
+	if [ -z "$( echo $section | grep -v $(eval echo -e{${white_list}}))" ]; then
+	    continue;
+	fi
+
+	# Will either print a warning if the relocation happens to be in a
+	# section we do not know but has executable bit set, or error out.
+	handle_suspicious_reloc
+    done
+}
+
+function check_debug_info() {
+    objdump -hj .debug_info ${obj} 2> /dev/null > /dev/null ||
+	echo -e "${obj} does not contain debug information, the addr2line output will be limited.\n" \
+	     "Recompile ${obj} with CONFIG_DEBUG_INFO to get a more useful output."
+}
+
+check_debug_info
+
+diagnose
+
+if [ "${error}" ]; then
+    exit 1
+fi
+
+exit 0
-- 
cgit v1.2.1


From 52dc0595d540155436d91811f929bdc8afd6a2a1 Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:52:53 +0930
Subject: modpost: handle relocations mismatch in __ex_table.

__ex_table is a simple table section where each entry is a pair of
addresses - the first address is an address which can fault in kernel
space, and the second address points to where the kernel should jump to
when handling that fault.  This is how copy_from_user() does not crash the
kernel if userspace gives a borked pointer for example.

If one of these addresses point to a non-executable section, something is
seriously wrong since it either means the kernel will never fault from
there or it will not be able to jump to there.  As both cases are serious
enough, we simply error out in these cases so the build fails and the
developper has to fix the issue.

In case the section is executable, but it isn't referenced in our list of
authorized sections to point to from __ex_table, we just dump a warning
giving more information about it.  We do this in case the new section is
executable but isn't supposed to be executed by the kernel.  This happened
with .altinstr_replacement, which is executable but is only used to copy
instructions from - we should never have our instruction pointer pointing
in .altinstr_replacement.  Admitedly, a proper fix in that case would be to
just set .altinstr_replacement NX, but we need to warn about future cases
like this.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (added long casts)
---
 scripts/mod/modpost.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index bf0cf8173beb..e95aa28ce0f7 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -875,6 +875,8 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define DATA_SECTIONS ".data", ".data.rel"
 #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
 		".kprobes.text"
+#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
+		".fixup", ".entry.text"
 
 #define INIT_SECTIONS      ".init.*"
 #define MEM_INIT_SECTIONS  ".meminit.*"
@@ -882,6 +884,9 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define EXIT_SECTIONS      ".exit.*"
 #define MEM_EXIT_SECTIONS  ".memexit.*"
 
+#define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
+		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
+
 /* init data sections */
 static const char *const init_data_sections[] =
 	{ ALL_INIT_DATA_SECTIONS, NULL };
@@ -922,6 +927,7 @@ enum mismatch {
 	ANY_INIT_TO_ANY_EXIT,
 	ANY_EXIT_TO_ANY_INIT,
 	EXPORT_TO_INIT_EXIT,
+	EXTABLE_TO_NON_TEXT,
 };
 
 struct sectioncheck {
@@ -936,6 +942,11 @@ struct sectioncheck {
 
 };
 
+static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
+				     const struct sectioncheck* const mismatch,
+				     Elf_Rela *r, Elf_Sym *sym,
+				     const char *fromsec);
+
 static const struct sectioncheck sectioncheck[] = {
 /* Do not reference init/exit code/data from
  * normal code and data
@@ -1013,6 +1024,16 @@ static const struct sectioncheck sectioncheck[] = {
 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
 	.mismatch = EXPORT_TO_INIT_EXIT,
 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+{
+	.fromsec = { "__ex_table", NULL },
+	/* If you're adding any new black-listed sections in here, consider
+	 * adding a special 'printer' for them in scripts/check_extable.
+	 */
+	.bad_tosec = { ".altinstr_replacement", NULL },
+	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
+	.mismatch = EXTABLE_TO_NON_TEXT,
+	.handler = extable_mismatch_handler,
 }
 };
 
@@ -1418,6 +1439,10 @@ static void report_sec_mismatch(const char *modname,
 		tosym, prl_to, prl_to, tosym);
 		free(prl_to);
 		break;
+	case EXTABLE_TO_NON_TEXT:
+		fatal("There's a special handler for this mismatch type, "
+		      "we should never get here.");
+		break;
 	}
 	fprintf(stderr, "\n");
 }
@@ -1453,6 +1478,120 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
 	}
 }
 
+static int is_executable_section(struct elf_info* elf, unsigned int section_index)
+{
+	if (section_index > elf->num_sections)
+		fatal("section_index is outside elf->num_sections!\n");
+
+	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
+}
+
+/*
+ * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
+ * to know the sizeof(struct exception_table_entry) for the target architecture.
+ */
+static unsigned int extable_entry_size = 0;
+static void find_extable_entry_size(const char* const sec, const Elf_Rela* r,
+				    const void* start, const void* cur)
+{
+	/*
+	 * If we're currently checking the second relocation within __ex_table,
+	 * that relocation offset tells us the offsetof(struct
+	 * exception_table_entry, fixup) which is equal to sizeof(struct
+	 * exception_table_entry) divided by two.  We use that to our advantage
+	 * since there's no portable way to get that size as every architecture
+	 * seems to go with different sized types.  Not pretty but better than
+	 * hard-coding the size for every architecture..
+	 */
+	if (!extable_entry_size && cur == start + 1 &&
+	    strcmp("__ex_table", sec) == 0)
+		extable_entry_size = r->r_offset * 2;
+}
+static inline bool is_extable_fault_address(Elf_Rela *r)
+{
+	if (!extable_entry_size == 0)
+		fatal("extable_entry size hasn't been discovered!\n");
+
+	return ((r->r_offset == 0) ||
+		(r->r_offset % extable_entry_size == 0));
+}
+
+static void report_extable_warnings(const char* modname, struct elf_info* elf,
+				    const struct sectioncheck* const mismatch,
+				    Elf_Rela* r, Elf_Sym* sym,
+				    const char* fromsec, const char* tosec)
+{
+	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
+	const char* fromsym_name = sym_name(elf, fromsym);
+	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
+	const char* tosym_name = sym_name(elf, tosym);
+	const char* from_pretty_name;
+	const char* from_pretty_name_p;
+	const char* to_pretty_name;
+	const char* to_pretty_name_p;
+
+	get_pretty_name(is_function(fromsym),
+			&from_pretty_name, &from_pretty_name_p);
+	get_pretty_name(is_function(tosym),
+			&to_pretty_name, &to_pretty_name_p);
+
+	warn("%s(%s+0x%lx): Section mismatch in reference"
+	     " from the %s %s%s to the %s %s:%s%s\n",
+	     modname, fromsec, (long)r->r_offset, from_pretty_name,
+	     fromsym_name, from_pretty_name_p,
+	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
+
+	if (!match(tosec, mismatch->bad_tosec) &&
+	    is_executable_section(elf, get_secindex(elf, sym)))
+		fprintf(stderr,
+			"The relocation at %s+0x%lx references\n"
+			"section \"%s\" which is not in the list of\n"
+			"authorized sections.  If you're adding a new section\n"
+			"and/or if this reference is valid, add \"%s\" to the\n"
+			"list of authorized sections to jump to on fault.\n"
+			"This can be achieved by adding \"%s\" to \n"
+			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
+			fromsec, (long)r->r_offset, tosec, tosec, tosec);
+}
+
+static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
+				     const struct sectioncheck* const mismatch,
+				     Elf_Rela* r, Elf_Sym* sym,
+				     const char *fromsec)
+{
+	const char* tosec = sec_name(elf, get_secindex(elf, sym));
+
+	sec_mismatch_count++;
+
+	if (sec_mismatch_verbose)
+		report_extable_warnings(modname, elf, mismatch, r, sym,
+					fromsec, tosec);
+
+	if (match(tosec, mismatch->bad_tosec))
+		fatal("The relocation at %s+0x%lx references\n"
+		      "section \"%s\" which is black-listed.\n"
+		      "Something is seriously wrong and should be fixed.\n"
+		      "You might get more information about where this is\n"
+		      "coming from by using scripts/check_extable.sh %s\n",
+		      fromsec, (long)r->r_offset, tosec, modname);
+	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
+		if (is_extable_fault_address(r))
+			fatal("The relocation at %s+0x%lx references\n"
+			      "section \"%s\" which is not executable, IOW\n"
+			      "it is not possible for the kernel to fault\n"
+			      "at that address.  Something is seriously wrong\n"
+			      "and should be fixed.\n",
+			      fromsec, (long)r->r_offset, tosec);
+		else
+			fatal("The relocation at %s+0x%lx references\n"
+			      "section \"%s\" which is not executable, IOW\n"
+			      "the kernel will fault if it ever tries to\n"
+			      "jump to it.  Something is seriously wrong\n"
+			      "and should be fixed.\n",
+			      fromsec, (long)r->r_offset, tosec);
+	}
+}
+
 static void check_section_mismatch(const char *modname, struct elf_info *elf,
 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
 {
@@ -1605,6 +1744,7 @@ static void section_rela(const char *modname, struct elf_info *elf,
 		/* Skip special sections */
 		if (is_shndx_special(sym->st_shndx))
 			continue;
+		find_extable_entry_size(fromsec, &r, start, rela);
 		check_section_mismatch(modname, elf, &r, sym, fromsec);
 	}
 }
@@ -1663,6 +1803,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
 		/* Skip special sections */
 		if (is_shndx_special(sym->st_shndx))
 			continue;
+		find_extable_entry_size(fromsec, &r, start, rel);
 		check_section_mismatch(modname, elf, &r, sym, fromsec);
 	}
 }
-- 
cgit v1.2.1


From e5d8f59a5cfa76ab5ebe47622d0c569eddd42fbe Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Mon, 13 Apr 2015 20:55:15 +0930
Subject: modpost: document the use of struct section_check.

struct section_check is used as a generic way of describing what
relocations are authorized/forbidden when running modpost.  This commit
tries to describe how each field is used.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (Fixed "mist"ake)
---
 scripts/mod/modpost.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index e95aa28ce0f7..cbd53e08769d 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -930,6 +930,26 @@ enum mismatch {
 	EXTABLE_TO_NON_TEXT,
 };
 
+/**
+ * Describe how to match sections on different criterias:
+ *
+ * @fromsec: Array of sections to be matched.
+ *
+ * @bad_tosec: Relocations applied to a section in @fromsec to a section in
+ * this array is forbidden (black-list).  Can be empty.
+ *
+ * @good_tosec: Relocations applied to a section in @fromsec must be
+ * targetting sections in this array (white-list).  Can be empty.
+ *
+ * @mismatch: Type of mismatch.
+ *
+ * @symbol_white_list: Do not match a relocation to a symbol in this list
+ * even if it is targetting a section in @bad_to_sec.
+ *
+ * @handler: Specific handler to call when a match is found.  If NULL,
+ * default_mismatch_handler() will be called.
+ *
+ */
 struct sectioncheck {
 	const char *fromsec[20];
 	const char *bad_tosec[20];
-- 
cgit v1.2.1


From d7e0abcf4c6d9fc4ebb948c9bbc880b2483434b4 Mon Sep 17 00:00:00 2001
From: Thierry Reding <thierry.reding@gmail.com>
Date: Wed, 15 Apr 2015 13:23:48 +0930
Subject: modpost: Whitelist .text.fixup and .exception.text

32-bit and 64-bit ARM use these sections to store executable code, so
they must be whitelisted in modpost's table of valid text sections.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index cbd53e08769d..6a925f200b25 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -876,7 +876,7 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
 		".kprobes.text"
 #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
-		".fixup", ".entry.text"
+		".fixup", ".entry.text", ".text.fixup", ".exception.text"
 
 #define INIT_SECTIONS      ".init.*"
 #define MEM_INIT_SECTIONS  ".meminit.*"
-- 
cgit v1.2.1


From 6c730bfc894f5d4989c2c1493512d3330402be94 Mon Sep 17 00:00:00 2001
From: Rusty Russell <rusty@rustcorp.com.au>
Date: Wed, 15 Apr 2015 13:28:08 +0930
Subject: modpost: handle -ffunction-sections

52dc0595d540 introduced OTHER_TEXT_SECTIONS for identifying what
sections could validly have __ex_table entries.  Unfortunately, it
wasn't tested with -ffunction-sections, which some architectures
use.

Reported-by: kbuild test robot <fengguang.wu@intel.com>
Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 6a925f200b25..22dbc604cdb9 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -876,7 +876,7 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
 		".kprobes.text"
 #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
-		".fixup", ".entry.text", ".text.fixup", ".exception.text"
+		".fixup", ".entry.text", ".exception.text", ".text.*"
 
 #define INIT_SECTIONS      ".init.*"
 #define MEM_INIT_SECTIONS  ".meminit.*"
-- 
cgit v1.2.1


From d3df4de7eb095cc4334759a5e65bf3bfb4be04f1 Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Thu, 16 Apr 2015 13:03:32 +0930
Subject: modpost: fix inverted logic in is_extable_fault_address().

As Guenter pointed out, we want to assert that extable_entry_size has been
discovered and not the other way around.  Moreover, this sanity check is
only valid when we're not dealing with the first relocation in __ex_table,
since we have not discovered the extable entry size at that point.

This was leading to a divide-by-zero on some architectures and make the
build fail.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Reported-by: Guenter Roeck <linux@roeck-us.net>
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 22dbc604cdb9..93bb87d0e17d 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1529,7 +1529,12 @@ static void find_extable_entry_size(const char* const sec, const Elf_Rela* r,
 }
 static inline bool is_extable_fault_address(Elf_Rela *r)
 {
-	if (!extable_entry_size == 0)
+	/*
+	 * extable_entry_size is only discovered after we've handled the
+	 * _second_ relocation in __ex_table, so only abort when we're not
+	 * handling the first reloc and extable_entry_size is zero.
+	 */
+	if (r->r_offset && extable_entry_size == 0)
 		fatal("extable_entry size hasn't been discovered!\n");
 
 	return ((r->r_offset == 0) ||
-- 
cgit v1.2.1


From e84048aa173f2403fa468cb189f101b57fece539 Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Thu, 16 Apr 2015 13:05:36 +0930
Subject: modpost: fix extable entry size calculation.

As Guenter pointed out, we were never really calculating the extable entry
size because the pointer arithmetic was simply wrong.  We want to check
we're handling the second relocation in __ex_table to infer an entry size,
but we were using (void*) pointers instead of Elf_Rel[a]* ones.

This fixes the problem by moving that check in the caller (since we can
deal with different types of relocations) and add is_second_extable_reloc()
to make the whole thing more readable.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Reported-by: Guenter Roeck <linux@roeck-us.net>
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 93bb87d0e17d..fd949770da0c 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1511,8 +1511,7 @@ static int is_executable_section(struct elf_info* elf, unsigned int section_inde
  * to know the sizeof(struct exception_table_entry) for the target architecture.
  */
 static unsigned int extable_entry_size = 0;
-static void find_extable_entry_size(const char* const sec, const Elf_Rela* r,
-				    const void* start, const void* cur)
+static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
 {
 	/*
 	 * If we're currently checking the second relocation within __ex_table,
@@ -1523,10 +1522,10 @@ static void find_extable_entry_size(const char* const sec, const Elf_Rela* r,
 	 * seems to go with different sized types.  Not pretty but better than
 	 * hard-coding the size for every architecture..
 	 */
-	if (!extable_entry_size && cur == start + 1 &&
-	    strcmp("__ex_table", sec) == 0)
+	if (!extable_entry_size)
 		extable_entry_size = r->r_offset * 2;
 }
+
 static inline bool is_extable_fault_address(Elf_Rela *r)
 {
 	/*
@@ -1541,6 +1540,9 @@ static inline bool is_extable_fault_address(Elf_Rela *r)
 		(r->r_offset % extable_entry_size == 0));
 }
 
+#define is_second_extable_reloc(Start, Cur, Sec)			\
+	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
+
 static void report_extable_warnings(const char* modname, struct elf_info* elf,
 				    const struct sectioncheck* const mismatch,
 				    Elf_Rela* r, Elf_Sym* sym,
@@ -1769,7 +1771,8 @@ static void section_rela(const char *modname, struct elf_info *elf,
 		/* Skip special sections */
 		if (is_shndx_special(sym->st_shndx))
 			continue;
-		find_extable_entry_size(fromsec, &r, start, rela);
+		if (is_second_extable_reloc(start, rela, fromsec))
+			find_extable_entry_size(fromsec, &r);
 		check_section_mismatch(modname, elf, &r, sym, fromsec);
 	}
 }
@@ -1828,7 +1831,8 @@ static void section_rel(const char *modname, struct elf_info *elf,
 		/* Skip special sections */
 		if (is_shndx_special(sym->st_shndx))
 			continue;
-		find_extable_entry_size(fromsec, &r, start, rel);
+		if (is_second_extable_reloc(start, rel, fromsec))
+			find_extable_entry_size(fromsec, &r);
 		check_section_mismatch(modname, elf, &r, sym, fromsec);
 	}
 }
-- 
cgit v1.2.1


From c5c3439af0f9c08e253d2a703a7eb3deba7d8591 Mon Sep 17 00:00:00 2001
From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Date: Thu, 16 Apr 2015 13:16:41 +0930
Subject: modpost: do not try to match the SHT_NUL section.

Trying to match the SHT_NUL section isn't useful and causes build failures
on parisc and mn10300 since the addition of section strict white-listing
and __ex_table sanitizing.

Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Reported-by: Guenter Roeck <linux@roeck-us.net>
Fixes: 050e57fd5936 ("modpost: add strict white-listing when referencing....")
Fixes: 52dc0595d540 ("modpost: handle relocations mismatch in __ex_table.")
Tested-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index fd949770da0c..45e4027d3193 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1064,6 +1064,15 @@ static const struct sectioncheck *section_mismatch(
 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
 	const struct sectioncheck *check = &sectioncheck[0];
 
+	/*
+	 * The target section could be the SHT_NUL section when we're
+	 * handling relocations to un-resolved symbols, trying to match it
+	 * doesn't make much sense and causes build failures on parisc and
+	 * mn10300 architectures.
+	 */
+	if (*tosec == '\0')
+		return NULL;
+
 	for (i = 0; i < elems; i++) {
 		if (match(fromsec, check->fromsec)) {
 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
-- 
cgit v1.2.1


From 09c20c032b0f753969ae778d9783d946f054d7fe Mon Sep 17 00:00:00 2001
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Mon, 20 Apr 2015 10:20:26 +0930
Subject: modpost: expand pattern matching to support substring matches

Currently the match() function supports a leading * to match any
prefix and a trailing * to match any suffix.  However there currently
is not a combination of both that can be used to target matches of
whole families of functions that share a common substring.

Here we expand the *foo and foo* match to also support *foo* with
the goal of targeting compiler generated symbol names that contain
strings like ".constprop." and ".isra."

Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 45e4027d3193..1c2101bf63d2 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -776,6 +776,7 @@ static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
  * "foo" will match an exact string equal to "foo"
  * "*foo" will match a string that ends with "foo"
  * "foo*" will match a string that begins with "foo"
+ * "*foo*" will match a string that contains "foo"
  */
 static int match(const char *sym, const char * const pat[])
 {
@@ -784,8 +785,17 @@ static int match(const char *sym, const char * const pat[])
 		p = *pat++;
 		const char *endp = p + strlen(p) - 1;
 
+		/* "*foo*" */
+		if (*p == '*' && *endp == '*') {
+			char *here, *bare = strndup(p + 1, strlen(p) - 2);
+
+			here = strstr(sym, bare);
+			free(bare);
+			if (here != NULL)
+				return 1;
+		}
 		/* "*foo" */
-		if (*p == '*') {
+		else if (*p == '*') {
 			if (strrcmp(sym, p + 1) == 0)
 				return 1;
 		}
-- 
cgit v1.2.1


From 4a3893d069b788f3570c19c12d9e986e8e15870f Mon Sep 17 00:00:00 2001
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Mon, 20 Apr 2015 10:20:40 +0930
Subject: modpost: don't emit section mismatch warnings for compiler
 optimizations

Currently an allyesconfig build [gcc-4.9.1] can generate the following:

   WARNING: vmlinux.o(.text.unlikely+0x3864): Section mismatch in
   reference from the function cpumask_empty.constprop.3() to the
   variable .init.data:nmi_ipi_mask

which comes from the cpumask_empty usage in arch/x86/kernel/nmi_selftest.c.

Normally we would not see a symbol entry for cpumask_empty since it is:

	static inline bool cpumask_empty(const struct cpumask *srcp)

however in this case, the variant of the symbol gets emitted when GCC does
constant propagation optimization.

Fix things up so that any locally optimized constprop variants don't warn
when accessing variables that live in the __init sections.

Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 scripts/mod/modpost.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

(limited to 'scripts')

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 1c2101bf63d2..91ee1b2e0f9a 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -908,6 +908,9 @@ static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
 static const char *const init_exit_sections[] =
 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
 
+/* all text sections */
+static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
+
 /* data section */
 static const char *const data_sections[] = { DATA_SECTIONS, NULL };
 
@@ -926,6 +929,7 @@ static const char *const data_sections[] = { DATA_SECTIONS, NULL };
 static const char *const head_sections[] = { ".head.text*", NULL };
 static const char *const linker_symbols[] =
 	{ "__init_begin", "_sinittext", "_einittext", NULL };
+static const char *const optim_symbols[] = { "*.constprop.*", NULL };
 
 enum mismatch {
 	TEXT_TO_ANY_INIT,
@@ -1136,6 +1140,17 @@ static const struct sectioncheck *section_mismatch(
  *   This pattern is identified by
  *   refsymname = __init_begin, _sinittext, _einittext
  *
+ * Pattern 5:
+ *   GCC may optimize static inlines when fed constant arg(s) resulting
+ *   in functions like cpumask_empty() -- generating an associated symbol
+ *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
+ *   is passed in comes from __init, like say nmi_ipi_mask, we get a
+ *   meaningless section warning.  May need to add isra symbols too...
+ *   This pattern is identified by
+ *   tosec   = init section
+ *   fromsec = text section
+ *   refsymname = *.constprop.*
+ *
  **/
 static int secref_whitelist(const struct sectioncheck *mismatch,
 			    const char *fromsec, const char *fromsym,
@@ -1168,6 +1183,12 @@ static int secref_whitelist(const struct sectioncheck *mismatch,
 	if (match(tosym, linker_symbols))
 		return 0;
 
+	/* Check for pattern 5 */
+	if (match(fromsec, text_sections) &&
+	    match(tosec, init_sections) &&
+	    match(fromsym, optim_symbols))
+		return 0;
+
 	return 1;
 }
 
-- 
cgit v1.2.1