diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-22 12:49:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-22 12:49:24 -0400 |
commit | 15ce2658ddbd3db20dfba3622f3d224f01837fdc (patch) | |
tree | c1a62e6d2c0b5942cbb8624e8db9be06e28e04b0 | |
parent | f3ca10dde49043fbbb055854278b26954b549b36 (diff) | |
parent | 4a3893d069b788f3570c19c12d9e986e8e15870f (diff) |
Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module updates from Rusty Russell:
"Quentin opened a can of worms by adding extable entry checking to
modpost, but most architectures seem fixed now. Thanks to all
involved.
Last minute rebase because I noticed a "[PATCH]" had snuck into a
commit message somehow"
* tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
modpost: don't emit section mismatch warnings for compiler optimizations
modpost: expand pattern matching to support substring matches
modpost: do not try to match the SHT_NUL section.
modpost: fix extable entry size calculation.
modpost: fix inverted logic in is_extable_fault_address().
modpost: handle -ffunction-sections
modpost: Whitelist .text.fixup and .exception.text
params: handle quotes properly for values not of form foo="bar".
modpost: document the use of struct section_check.
modpost: handle relocations mismatch in __ex_table.
scripts: add check_extable.sh script.
modpost: mismatch_handler: retrieve tosym information only when needed.
modpost: factorize symbol pretty print in get_pretty_name().
modpost: add handler function pointer to sectioncheck.
modpost: add .sched.text and .kprobes.text to the TEXT_SECTIONS list.
modpost: add strict white-listing when referencing sections.
module: do not print allocation-fail warning on bogus user buffer size
kernel/module.c: fix typos in message about unused symbols
-rw-r--r-- | kernel/module.c | 9 | ||||
-rw-r--r-- | kernel/params.c | 4 | ||||
-rwxr-xr-x | scripts/check_extable.sh | 146 | ||||
-rw-r--r-- | scripts/mod/modpost.c | 341 |
4 files changed, 440 insertions, 60 deletions
diff --git a/kernel/module.c b/kernel/module.c index 650b038ae520..42a1d2afb217 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -387,9 +387,9 @@ static bool check_symbol(const struct symsearch *syms, | |||
387 | pr_warn("Symbol %s is marked as UNUSED, however this module is " | 387 | pr_warn("Symbol %s is marked as UNUSED, however this module is " |
388 | "using it.\n", fsa->name); | 388 | "using it.\n", fsa->name); |
389 | pr_warn("This symbol will go away in the future.\n"); | 389 | pr_warn("This symbol will go away in the future.\n"); |
390 | pr_warn("Please evalute if this is the right api to use and if " | 390 | pr_warn("Please evaluate if this is the right api to use and " |
391 | "it really is, submit a report the linux kernel " | 391 | "if it really is, submit a report to the linux kernel " |
392 | "mailinglist together with submitting your code for " | 392 | "mailing list together with submitting your code for " |
393 | "inclusion.\n"); | 393 | "inclusion.\n"); |
394 | } | 394 | } |
395 | #endif | 395 | #endif |
@@ -2511,7 +2511,8 @@ static int copy_module_from_user(const void __user *umod, unsigned long len, | |||
2511 | return err; | 2511 | return err; |
2512 | 2512 | ||
2513 | /* Suck in entire file: we'll want most of it. */ | 2513 | /* Suck in entire file: we'll want most of it. */ |
2514 | info->hdr = vmalloc(info->len); | 2514 | info->hdr = __vmalloc(info->len, |
2515 | GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, PAGE_KERNEL); | ||
2515 | if (!info->hdr) | 2516 | if (!info->hdr) |
2516 | return -ENOMEM; | 2517 | return -ENOMEM; |
2517 | 2518 | ||
diff --git a/kernel/params.c b/kernel/params.c index 728e05b167de..a22d6a759b1a 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -173,9 +173,9 @@ static char *next_arg(char *args, char **param, char **val) | |||
173 | if (args[i-1] == '"') | 173 | if (args[i-1] == '"') |
174 | args[i-1] = '\0'; | 174 | args[i-1] = '\0'; |
175 | } | 175 | } |
176 | if (quoted && args[i-1] == '"') | ||
177 | args[i-1] = '\0'; | ||
178 | } | 176 | } |
177 | if (quoted && args[i-1] == '"') | ||
178 | args[i-1] = '\0'; | ||
179 | 179 | ||
180 | if (args[i]) { | 180 | if (args[i]) { |
181 | args[i] = '\0'; | 181 | args[i] = '\0'; |
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 @@ | |||
1 | #! /bin/bash | ||
2 | # (c) 2015, Quentin Casasnovas <quentin.casasnovas@oracle.com> | ||
3 | |||
4 | obj=$1 | ||
5 | |||
6 | file ${obj} | grep -q ELF || (echo "${obj} is not and ELF file." 1>&2 ; exit 0) | ||
7 | |||
8 | # Bail out early if there isn't an __ex_table section in this object file. | ||
9 | objdump -hj __ex_table ${obj} 2> /dev/null > /dev/null | ||
10 | [ $? -ne 0 ] && exit 0 | ||
11 | |||
12 | white_list=.text,.fixup | ||
13 | |||
14 | suspicious_relocs=$(objdump -rj __ex_table ${obj} | tail -n +6 | | ||
15 | grep -v $(eval echo -e{${white_list}}) | awk '{print $3}') | ||
16 | |||
17 | # No suspicious relocs in __ex_table, jobs a good'un | ||
18 | [ -z "${suspicious_relocs}" ] && exit 0 | ||
19 | |||
20 | |||
21 | # After this point, something is seriously wrong since we just found out we | ||
22 | # have some relocations in __ex_table which point to sections which aren't | ||
23 | # white listed. If you're adding a new section in the Linux kernel, and | ||
24 | # you're expecting this section to contain code which can fault (i.e. the | ||
25 | # __ex_table relocation to your new section is expected), simply add your | ||
26 | # new section to the white_list variable above. If not, you're probably | ||
27 | # doing something wrong and the rest of this code is just trying to print | ||
28 | # you more information about it. | ||
29 | |||
30 | function find_section_offset_from_symbol() | ||
31 | { | ||
32 | eval $(objdump -t ${obj} | grep ${1} | sed 's/\([0-9a-f]\+\) .\{7\} \([^ \t]\+\).*/section="\2"; section_offset="0x\1" /') | ||
33 | |||
34 | # addr2line takes addresses in hexadecimal... | ||
35 | section_offset=$(printf "0x%016x" $(( ${section_offset} + $2 )) ) | ||
36 | } | ||
37 | |||
38 | function find_symbol_and_offset_from_reloc() | ||
39 | { | ||
40 | # Extract symbol and offset from the objdump output | ||
41 | eval $(echo $reloc | sed 's/\([^+]\+\)+\?\(0x[0-9a-f]\+\)\?/symbol="\1"; symbol_offset="\2"/') | ||
42 | |||
43 | # When the relocation points to the begining of a symbol or section, it | ||
44 | # won't print the offset since it is zero. | ||
45 | if [ -z "${symbol_offset}" ]; then | ||
46 | symbol_offset=0x0 | ||
47 | fi | ||
48 | } | ||
49 | |||
50 | function find_alt_replacement_target() | ||
51 | { | ||
52 | # The target of the .altinstr_replacement is the relocation just before | ||
53 | # the .altinstr_replacement one. | ||
54 | eval $(objdump -rj .altinstructions ${obj} | grep -B1 "${section}+${section_offset}" | head -n1 | awk '{print $3}' | | ||
55 | sed 's/\([^+]\+\)+\(0x[0-9a-f]\+\)/alt_target_section="\1"; alt_target_offset="\2"/') | ||
56 | } | ||
57 | |||
58 | function handle_alt_replacement_reloc() | ||
59 | { | ||
60 | # This will define alt_target_section and alt_target_section_offset | ||
61 | find_alt_replacement_target ${section} ${section_offset} | ||
62 | |||
63 | echo "Error: found a reference to .altinstr_replacement in __ex_table:" | ||
64 | addr2line -fip -j ${alt_target_section} -e ${obj} ${alt_target_offset} | awk '{print "\t" $0}' | ||
65 | |||
66 | error=true | ||
67 | } | ||
68 | |||
69 | function is_executable_section() | ||
70 | { | ||
71 | objdump -hwj ${section} ${obj} | grep -q CODE | ||
72 | return $? | ||
73 | } | ||
74 | |||
75 | function handle_suspicious_generic_reloc() | ||
76 | { | ||
77 | if is_executable_section ${section}; then | ||
78 | # We've got a relocation to a non white listed _executable_ | ||
79 | # section, print a warning so the developper adds the section to | ||
80 | # the white list or fix his code. We try to pretty-print the file | ||
81 | # and line number where that relocation was added. | ||
82 | echo "Warning: found a reference to section \"${section}\" in __ex_table:" | ||
83 | addr2line -fip -j ${section} -e ${obj} ${section_offset} | awk '{print "\t" $0}' | ||
84 | else | ||
85 | # Something is definitively wrong here since we've got a relocation | ||
86 | # to a non-executable section, there's no way this would ever be | ||
87 | # running in the kernel. | ||
88 | echo "Error: found a reference to non-executable section \"${section}\" in __ex_table at offset ${section_offset}" | ||
89 | error=true | ||
90 | fi | ||
91 | } | ||
92 | |||
93 | function handle_suspicious_reloc() | ||
94 | { | ||
95 | case "${section}" in | ||
96 | ".altinstr_replacement") | ||
97 | handle_alt_replacement_reloc ${section} ${section_offset} | ||
98 | ;; | ||
99 | *) | ||
100 | handle_suspicious_generic_reloc ${section} ${section_offset} | ||
101 | ;; | ||
102 | esac | ||
103 | } | ||
104 | |||
105 | function diagnose() | ||
106 | { | ||
107 | |||
108 | for reloc in ${suspicious_relocs}; do | ||
109 | # Let's find out where the target of the relocation in __ex_table | ||
110 | # is, this will define ${symbol} and ${symbol_offset} | ||
111 | find_symbol_and_offset_from_reloc ${reloc} | ||
112 | |||
113 | # When there's a global symbol at the place of the relocation, | ||
114 | # objdump will use it instead of giving us a section+offset, so | ||
115 | # let's find out which section is this symbol in and the total | ||
116 | # offset withing that section. | ||
117 | find_section_offset_from_symbol ${symbol} ${symbol_offset} | ||
118 | |||
119 | # In this case objdump was presenting us with a reloc to a symbol | ||
120 | # rather than a section. Now that we've got the actual section, | ||
121 | # we can skip it if it's in the white_list. | ||
122 | if [ -z "$( echo $section | grep -v $(eval echo -e{${white_list}}))" ]; then | ||
123 | continue; | ||
124 | fi | ||
125 | |||
126 | # Will either print a warning if the relocation happens to be in a | ||
127 | # section we do not know but has executable bit set, or error out. | ||
128 | handle_suspicious_reloc | ||
129 | done | ||
130 | } | ||
131 | |||
132 | function check_debug_info() { | ||
133 | objdump -hj .debug_info ${obj} 2> /dev/null > /dev/null || | ||
134 | echo -e "${obj} does not contain debug information, the addr2line output will be limited.\n" \ | ||
135 | "Recompile ${obj} with CONFIG_DEBUG_INFO to get a more useful output." | ||
136 | } | ||
137 | |||
138 | check_debug_info | ||
139 | |||
140 | diagnose | ||
141 | |||
142 | if [ "${error}" ]; then | ||
143 | exit 1 | ||
144 | fi | ||
145 | |||
146 | exit 0 | ||
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index d439856f8176..91ee1b2e0f9a 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) | |||
776 | * "foo" will match an exact string equal to "foo" | 776 | * "foo" will match an exact string equal to "foo" |
777 | * "*foo" will match a string that ends with "foo" | 777 | * "*foo" will match a string that ends with "foo" |
778 | * "foo*" will match a string that begins with "foo" | 778 | * "foo*" will match a string that begins with "foo" |
779 | * "*foo*" will match a string that contains "foo" | ||
779 | */ | 780 | */ |
780 | static int match(const char *sym, const char * const pat[]) | 781 | static int match(const char *sym, const char * const pat[]) |
781 | { | 782 | { |
@@ -784,8 +785,17 @@ static int match(const char *sym, const char * const pat[]) | |||
784 | p = *pat++; | 785 | p = *pat++; |
785 | const char *endp = p + strlen(p) - 1; | 786 | const char *endp = p + strlen(p) - 1; |
786 | 787 | ||
788 | /* "*foo*" */ | ||
789 | if (*p == '*' && *endp == '*') { | ||
790 | char *here, *bare = strndup(p + 1, strlen(p) - 2); | ||
791 | |||
792 | here = strstr(sym, bare); | ||
793 | free(bare); | ||
794 | if (here != NULL) | ||
795 | return 1; | ||
796 | } | ||
787 | /* "*foo" */ | 797 | /* "*foo" */ |
788 | if (*p == '*') { | 798 | else if (*p == '*') { |
789 | if (strrcmp(sym, p + 1) == 0) | 799 | if (strrcmp(sym, p + 1) == 0) |
790 | return 1; | 800 | return 1; |
791 | } | 801 | } |
@@ -873,7 +883,10 @@ static void check_section(const char *modname, struct elf_info *elf, | |||
873 | #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS | 883 | #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS |
874 | 884 | ||
875 | #define DATA_SECTIONS ".data", ".data.rel" | 885 | #define DATA_SECTIONS ".data", ".data.rel" |
876 | #define TEXT_SECTIONS ".text", ".text.unlikely" | 886 | #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ |
887 | ".kprobes.text" | ||
888 | #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ | ||
889 | ".fixup", ".entry.text", ".exception.text", ".text.*" | ||
877 | 890 | ||
878 | #define INIT_SECTIONS ".init.*" | 891 | #define INIT_SECTIONS ".init.*" |
879 | #define MEM_INIT_SECTIONS ".meminit.*" | 892 | #define MEM_INIT_SECTIONS ".meminit.*" |
@@ -881,6 +894,9 @@ static void check_section(const char *modname, struct elf_info *elf, | |||
881 | #define EXIT_SECTIONS ".exit.*" | 894 | #define EXIT_SECTIONS ".exit.*" |
882 | #define MEM_EXIT_SECTIONS ".memexit.*" | 895 | #define MEM_EXIT_SECTIONS ".memexit.*" |
883 | 896 | ||
897 | #define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \ | ||
898 | TEXT_SECTIONS, OTHER_TEXT_SECTIONS | ||
899 | |||
884 | /* init data sections */ | 900 | /* init data sections */ |
885 | static const char *const init_data_sections[] = | 901 | static const char *const init_data_sections[] = |
886 | { ALL_INIT_DATA_SECTIONS, NULL }; | 902 | { ALL_INIT_DATA_SECTIONS, NULL }; |
@@ -892,6 +908,9 @@ static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; | |||
892 | static const char *const init_exit_sections[] = | 908 | static const char *const init_exit_sections[] = |
893 | {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; | 909 | {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; |
894 | 910 | ||
911 | /* all text sections */ | ||
912 | static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL }; | ||
913 | |||
895 | /* data section */ | 914 | /* data section */ |
896 | static const char *const data_sections[] = { DATA_SECTIONS, NULL }; | 915 | static const char *const data_sections[] = { DATA_SECTIONS, NULL }; |
897 | 916 | ||
@@ -910,6 +929,7 @@ static const char *const data_sections[] = { DATA_SECTIONS, NULL }; | |||
910 | static const char *const head_sections[] = { ".head.text*", NULL }; | 929 | static const char *const head_sections[] = { ".head.text*", NULL }; |
911 | static const char *const linker_symbols[] = | 930 | static const char *const linker_symbols[] = |
912 | { "__init_begin", "_sinittext", "_einittext", NULL }; | 931 | { "__init_begin", "_sinittext", "_einittext", NULL }; |
932 | static const char *const optim_symbols[] = { "*.constprop.*", NULL }; | ||
913 | 933 | ||
914 | enum mismatch { | 934 | enum mismatch { |
915 | TEXT_TO_ANY_INIT, | 935 | TEXT_TO_ANY_INIT, |
@@ -921,34 +941,65 @@ enum mismatch { | |||
921 | ANY_INIT_TO_ANY_EXIT, | 941 | ANY_INIT_TO_ANY_EXIT, |
922 | ANY_EXIT_TO_ANY_INIT, | 942 | ANY_EXIT_TO_ANY_INIT, |
923 | EXPORT_TO_INIT_EXIT, | 943 | EXPORT_TO_INIT_EXIT, |
944 | EXTABLE_TO_NON_TEXT, | ||
924 | }; | 945 | }; |
925 | 946 | ||
947 | /** | ||
948 | * Describe how to match sections on different criterias: | ||
949 | * | ||
950 | * @fromsec: Array of sections to be matched. | ||
951 | * | ||
952 | * @bad_tosec: Relocations applied to a section in @fromsec to a section in | ||
953 | * this array is forbidden (black-list). Can be empty. | ||
954 | * | ||
955 | * @good_tosec: Relocations applied to a section in @fromsec must be | ||
956 | * targetting sections in this array (white-list). Can be empty. | ||
957 | * | ||
958 | * @mismatch: Type of mismatch. | ||
959 | * | ||
960 | * @symbol_white_list: Do not match a relocation to a symbol in this list | ||
961 | * even if it is targetting a section in @bad_to_sec. | ||
962 | * | ||
963 | * @handler: Specific handler to call when a match is found. If NULL, | ||
964 | * default_mismatch_handler() will be called. | ||
965 | * | ||
966 | */ | ||
926 | struct sectioncheck { | 967 | struct sectioncheck { |
927 | const char *fromsec[20]; | 968 | const char *fromsec[20]; |
928 | const char *tosec[20]; | 969 | const char *bad_tosec[20]; |
970 | const char *good_tosec[20]; | ||
929 | enum mismatch mismatch; | 971 | enum mismatch mismatch; |
930 | const char *symbol_white_list[20]; | 972 | const char *symbol_white_list[20]; |
973 | void (*handler)(const char *modname, struct elf_info *elf, | ||
974 | const struct sectioncheck* const mismatch, | ||
975 | Elf_Rela *r, Elf_Sym *sym, const char *fromsec); | ||
976 | |||
931 | }; | 977 | }; |
932 | 978 | ||
979 | static void extable_mismatch_handler(const char *modname, struct elf_info *elf, | ||
980 | const struct sectioncheck* const mismatch, | ||
981 | Elf_Rela *r, Elf_Sym *sym, | ||
982 | const char *fromsec); | ||
983 | |||
933 | static const struct sectioncheck sectioncheck[] = { | 984 | static const struct sectioncheck sectioncheck[] = { |
934 | /* Do not reference init/exit code/data from | 985 | /* Do not reference init/exit code/data from |
935 | * normal code and data | 986 | * normal code and data |
936 | */ | 987 | */ |
937 | { | 988 | { |
938 | .fromsec = { TEXT_SECTIONS, NULL }, | 989 | .fromsec = { TEXT_SECTIONS, NULL }, |
939 | .tosec = { ALL_INIT_SECTIONS, NULL }, | 990 | .bad_tosec = { ALL_INIT_SECTIONS, NULL }, |
940 | .mismatch = TEXT_TO_ANY_INIT, | 991 | .mismatch = TEXT_TO_ANY_INIT, |
941 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 992 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
942 | }, | 993 | }, |
943 | { | 994 | { |
944 | .fromsec = { DATA_SECTIONS, NULL }, | 995 | .fromsec = { DATA_SECTIONS, NULL }, |
945 | .tosec = { ALL_XXXINIT_SECTIONS, NULL }, | 996 | .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, |
946 | .mismatch = DATA_TO_ANY_INIT, | 997 | .mismatch = DATA_TO_ANY_INIT, |
947 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 998 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
948 | }, | 999 | }, |
949 | { | 1000 | { |
950 | .fromsec = { DATA_SECTIONS, NULL }, | 1001 | .fromsec = { DATA_SECTIONS, NULL }, |
951 | .tosec = { INIT_SECTIONS, NULL }, | 1002 | .bad_tosec = { INIT_SECTIONS, NULL }, |
952 | .mismatch = DATA_TO_ANY_INIT, | 1003 | .mismatch = DATA_TO_ANY_INIT, |
953 | .symbol_white_list = { | 1004 | .symbol_white_list = { |
954 | "*_template", "*_timer", "*_sht", "*_ops", | 1005 | "*_template", "*_timer", "*_sht", "*_ops", |
@@ -957,56 +1008,66 @@ static const struct sectioncheck sectioncheck[] = { | |||
957 | }, | 1008 | }, |
958 | { | 1009 | { |
959 | .fromsec = { TEXT_SECTIONS, NULL }, | 1010 | .fromsec = { TEXT_SECTIONS, NULL }, |
960 | .tosec = { ALL_EXIT_SECTIONS, NULL }, | 1011 | .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, |
961 | .mismatch = TEXT_TO_ANY_EXIT, | 1012 | .mismatch = TEXT_TO_ANY_EXIT, |
962 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 1013 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
963 | }, | 1014 | }, |
964 | { | 1015 | { |
965 | .fromsec = { DATA_SECTIONS, NULL }, | 1016 | .fromsec = { DATA_SECTIONS, NULL }, |
966 | .tosec = { ALL_EXIT_SECTIONS, NULL }, | 1017 | .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, |
967 | .mismatch = DATA_TO_ANY_EXIT, | 1018 | .mismatch = DATA_TO_ANY_EXIT, |
968 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 1019 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
969 | }, | 1020 | }, |
970 | /* Do not reference init code/data from meminit code/data */ | 1021 | /* Do not reference init code/data from meminit code/data */ |
971 | { | 1022 | { |
972 | .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, | 1023 | .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, |
973 | .tosec = { INIT_SECTIONS, NULL }, | 1024 | .bad_tosec = { INIT_SECTIONS, NULL }, |
974 | .mismatch = XXXINIT_TO_SOME_INIT, | 1025 | .mismatch = XXXINIT_TO_SOME_INIT, |
975 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 1026 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
976 | }, | 1027 | }, |
977 | /* Do not reference exit code/data from memexit code/data */ | 1028 | /* Do not reference exit code/data from memexit code/data */ |
978 | { | 1029 | { |
979 | .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, | 1030 | .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, |
980 | .tosec = { EXIT_SECTIONS, NULL }, | 1031 | .bad_tosec = { EXIT_SECTIONS, NULL }, |
981 | .mismatch = XXXEXIT_TO_SOME_EXIT, | 1032 | .mismatch = XXXEXIT_TO_SOME_EXIT, |
982 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 1033 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
983 | }, | 1034 | }, |
984 | /* Do not use exit code/data from init code */ | 1035 | /* Do not use exit code/data from init code */ |
985 | { | 1036 | { |
986 | .fromsec = { ALL_INIT_SECTIONS, NULL }, | 1037 | .fromsec = { ALL_INIT_SECTIONS, NULL }, |
987 | .tosec = { ALL_EXIT_SECTIONS, NULL }, | 1038 | .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, |
988 | .mismatch = ANY_INIT_TO_ANY_EXIT, | 1039 | .mismatch = ANY_INIT_TO_ANY_EXIT, |
989 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 1040 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
990 | }, | 1041 | }, |
991 | /* Do not use init code/data from exit code */ | 1042 | /* Do not use init code/data from exit code */ |
992 | { | 1043 | { |
993 | .fromsec = { ALL_EXIT_SECTIONS, NULL }, | 1044 | .fromsec = { ALL_EXIT_SECTIONS, NULL }, |
994 | .tosec = { ALL_INIT_SECTIONS, NULL }, | 1045 | .bad_tosec = { ALL_INIT_SECTIONS, NULL }, |
995 | .mismatch = ANY_EXIT_TO_ANY_INIT, | 1046 | .mismatch = ANY_EXIT_TO_ANY_INIT, |
996 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 1047 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
997 | }, | 1048 | }, |
998 | { | 1049 | { |
999 | .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, | 1050 | .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, |
1000 | .tosec = { INIT_SECTIONS, NULL }, | 1051 | .bad_tosec = { INIT_SECTIONS, NULL }, |
1001 | .mismatch = ANY_INIT_TO_ANY_EXIT, | 1052 | .mismatch = ANY_INIT_TO_ANY_EXIT, |
1002 | .symbol_white_list = { NULL }, | 1053 | .symbol_white_list = { NULL }, |
1003 | }, | 1054 | }, |
1004 | /* Do not export init/exit functions or data */ | 1055 | /* Do not export init/exit functions or data */ |
1005 | { | 1056 | { |
1006 | .fromsec = { "__ksymtab*", NULL }, | 1057 | .fromsec = { "__ksymtab*", NULL }, |
1007 | .tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, | 1058 | .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, |
1008 | .mismatch = EXPORT_TO_INIT_EXIT, | 1059 | .mismatch = EXPORT_TO_INIT_EXIT, |
1009 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, | 1060 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
1061 | }, | ||
1062 | { | ||
1063 | .fromsec = { "__ex_table", NULL }, | ||
1064 | /* If you're adding any new black-listed sections in here, consider | ||
1065 | * adding a special 'printer' for them in scripts/check_extable. | ||
1066 | */ | ||
1067 | .bad_tosec = { ".altinstr_replacement", NULL }, | ||
1068 | .good_tosec = {ALL_TEXT_SECTIONS , NULL}, | ||
1069 | .mismatch = EXTABLE_TO_NON_TEXT, | ||
1070 | .handler = extable_mismatch_handler, | ||
1010 | } | 1071 | } |
1011 | }; | 1072 | }; |
1012 | 1073 | ||
@@ -1017,10 +1078,22 @@ static const struct sectioncheck *section_mismatch( | |||
1017 | int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); | 1078 | int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); |
1018 | const struct sectioncheck *check = §ioncheck[0]; | 1079 | const struct sectioncheck *check = §ioncheck[0]; |
1019 | 1080 | ||
1081 | /* | ||
1082 | * The target section could be the SHT_NUL section when we're | ||
1083 | * handling relocations to un-resolved symbols, trying to match it | ||
1084 | * doesn't make much sense and causes build failures on parisc and | ||
1085 | * mn10300 architectures. | ||
1086 | */ | ||
1087 | if (*tosec == '\0') | ||
1088 | return NULL; | ||
1089 | |||
1020 | for (i = 0; i < elems; i++) { | 1090 | for (i = 0; i < elems; i++) { |
1021 | if (match(fromsec, check->fromsec) && | 1091 | if (match(fromsec, check->fromsec)) { |
1022 | match(tosec, check->tosec)) | 1092 | if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) |
1023 | return check; | 1093 | return check; |
1094 | if (check->good_tosec[0] && !match(tosec, check->good_tosec)) | ||
1095 | return check; | ||
1096 | } | ||
1024 | check++; | 1097 | check++; |
1025 | } | 1098 | } |
1026 | return NULL; | 1099 | return NULL; |
@@ -1067,6 +1140,17 @@ static const struct sectioncheck *section_mismatch( | |||
1067 | * This pattern is identified by | 1140 | * This pattern is identified by |
1068 | * refsymname = __init_begin, _sinittext, _einittext | 1141 | * refsymname = __init_begin, _sinittext, _einittext |
1069 | * | 1142 | * |
1143 | * Pattern 5: | ||
1144 | * GCC may optimize static inlines when fed constant arg(s) resulting | ||
1145 | * in functions like cpumask_empty() -- generating an associated symbol | ||
1146 | * cpumask_empty.constprop.3 that appears in the audit. If the const that | ||
1147 | * is passed in comes from __init, like say nmi_ipi_mask, we get a | ||
1148 | * meaningless section warning. May need to add isra symbols too... | ||
1149 | * This pattern is identified by | ||
1150 | * tosec = init section | ||
1151 | * fromsec = text section | ||
1152 | * refsymname = *.constprop.* | ||
1153 | * | ||
1070 | **/ | 1154 | **/ |
1071 | static int secref_whitelist(const struct sectioncheck *mismatch, | 1155 | static int secref_whitelist(const struct sectioncheck *mismatch, |
1072 | const char *fromsec, const char *fromsym, | 1156 | const char *fromsec, const char *fromsym, |
@@ -1099,6 +1183,12 @@ static int secref_whitelist(const struct sectioncheck *mismatch, | |||
1099 | if (match(tosym, linker_symbols)) | 1183 | if (match(tosym, linker_symbols)) |
1100 | return 0; | 1184 | return 0; |
1101 | 1185 | ||
1186 | /* Check for pattern 5 */ | ||
1187 | if (match(fromsec, text_sections) && | ||
1188 | match(tosec, init_sections) && | ||
1189 | match(fromsym, optim_symbols)) | ||
1190 | return 0; | ||
1191 | |||
1102 | return 1; | 1192 | return 1; |
1103 | } | 1193 | } |
1104 | 1194 | ||
@@ -1261,6 +1351,15 @@ static void print_section_list(const char * const list[20]) | |||
1261 | fprintf(stderr, "\n"); | 1351 | fprintf(stderr, "\n"); |
1262 | } | 1352 | } |
1263 | 1353 | ||
1354 | static inline void get_pretty_name(int is_func, const char** name, const char** name_p) | ||
1355 | { | ||
1356 | switch (is_func) { | ||
1357 | case 0: *name = "variable"; *name_p = ""; break; | ||
1358 | case 1: *name = "function"; *name_p = "()"; break; | ||
1359 | default: *name = "(unknown reference)"; *name_p = ""; break; | ||
1360 | } | ||
1361 | } | ||
1362 | |||
1264 | /* | 1363 | /* |
1265 | * Print a warning about a section mismatch. | 1364 | * Print a warning about a section mismatch. |
1266 | * Try to find symbols near it so user can find it. | 1365 | * Try to find symbols near it so user can find it. |
@@ -1280,21 +1379,13 @@ static void report_sec_mismatch(const char *modname, | |||
1280 | char *prl_from; | 1379 | char *prl_from; |
1281 | char *prl_to; | 1380 | char *prl_to; |
1282 | 1381 | ||
1283 | switch (from_is_func) { | ||
1284 | case 0: from = "variable"; from_p = ""; break; | ||
1285 | case 1: from = "function"; from_p = "()"; break; | ||
1286 | default: from = "(unknown reference)"; from_p = ""; break; | ||
1287 | } | ||
1288 | switch (to_is_func) { | ||
1289 | case 0: to = "variable"; to_p = ""; break; | ||
1290 | case 1: to = "function"; to_p = "()"; break; | ||
1291 | default: to = "(unknown reference)"; to_p = ""; break; | ||
1292 | } | ||
1293 | |||
1294 | sec_mismatch_count++; | 1382 | sec_mismatch_count++; |
1295 | if (!sec_mismatch_verbose) | 1383 | if (!sec_mismatch_verbose) |
1296 | return; | 1384 | return; |
1297 | 1385 | ||
1386 | get_pretty_name(from_is_func, &from, &from_p); | ||
1387 | get_pretty_name(to_is_func, &to, &to_p); | ||
1388 | |||
1298 | warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " | 1389 | warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " |
1299 | "to the %s %s:%s%s\n", | 1390 | "to the %s %s:%s%s\n", |
1300 | modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, | 1391 | modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, |
@@ -1408,41 +1499,179 @@ static void report_sec_mismatch(const char *modname, | |||
1408 | tosym, prl_to, prl_to, tosym); | 1499 | tosym, prl_to, prl_to, tosym); |
1409 | free(prl_to); | 1500 | free(prl_to); |
1410 | break; | 1501 | break; |
1502 | case EXTABLE_TO_NON_TEXT: | ||
1503 | fatal("There's a special handler for this mismatch type, " | ||
1504 | "we should never get here."); | ||
1505 | break; | ||
1411 | } | 1506 | } |
1412 | fprintf(stderr, "\n"); | 1507 | fprintf(stderr, "\n"); |
1413 | } | 1508 | } |
1414 | 1509 | ||
1415 | static void check_section_mismatch(const char *modname, struct elf_info *elf, | 1510 | static void default_mismatch_handler(const char *modname, struct elf_info *elf, |
1416 | Elf_Rela *r, Elf_Sym *sym, const char *fromsec) | 1511 | const struct sectioncheck* const mismatch, |
1512 | Elf_Rela *r, Elf_Sym *sym, const char *fromsec) | ||
1417 | { | 1513 | { |
1418 | const char *tosec; | 1514 | const char *tosec; |
1419 | const struct sectioncheck *mismatch; | 1515 | Elf_Sym *to; |
1516 | Elf_Sym *from; | ||
1517 | const char *tosym; | ||
1518 | const char *fromsym; | ||
1519 | |||
1520 | from = find_elf_symbol2(elf, r->r_offset, fromsec); | ||
1521 | fromsym = sym_name(elf, from); | ||
1522 | |||
1523 | if (!strncmp(fromsym, "reference___initcall", | ||
1524 | sizeof("reference___initcall")-1)) | ||
1525 | return; | ||
1420 | 1526 | ||
1421 | tosec = sec_name(elf, get_secindex(elf, sym)); | 1527 | tosec = sec_name(elf, get_secindex(elf, sym)); |
1422 | mismatch = section_mismatch(fromsec, tosec); | 1528 | to = find_elf_symbol(elf, r->r_addend, sym); |
1529 | tosym = sym_name(elf, to); | ||
1530 | |||
1531 | /* check whitelist - we may ignore it */ | ||
1532 | if (secref_whitelist(mismatch, | ||
1533 | fromsec, fromsym, tosec, tosym)) { | ||
1534 | report_sec_mismatch(modname, mismatch, | ||
1535 | fromsec, r->r_offset, fromsym, | ||
1536 | is_function(from), tosec, tosym, | ||
1537 | is_function(to)); | ||
1538 | } | ||
1539 | } | ||
1540 | |||
1541 | static int is_executable_section(struct elf_info* elf, unsigned int section_index) | ||
1542 | { | ||
1543 | if (section_index > elf->num_sections) | ||
1544 | fatal("section_index is outside elf->num_sections!\n"); | ||
1545 | |||
1546 | return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); | ||
1547 | } | ||
1548 | |||
1549 | /* | ||
1550 | * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size() | ||
1551 | * to know the sizeof(struct exception_table_entry) for the target architecture. | ||
1552 | */ | ||
1553 | static unsigned int extable_entry_size = 0; | ||
1554 | static void find_extable_entry_size(const char* const sec, const Elf_Rela* r) | ||
1555 | { | ||
1556 | /* | ||
1557 | * If we're currently checking the second relocation within __ex_table, | ||
1558 | * that relocation offset tells us the offsetof(struct | ||
1559 | * exception_table_entry, fixup) which is equal to sizeof(struct | ||
1560 | * exception_table_entry) divided by two. We use that to our advantage | ||
1561 | * since there's no portable way to get that size as every architecture | ||
1562 | * seems to go with different sized types. Not pretty but better than | ||
1563 | * hard-coding the size for every architecture.. | ||
1564 | */ | ||
1565 | if (!extable_entry_size) | ||
1566 | extable_entry_size = r->r_offset * 2; | ||
1567 | } | ||
1568 | |||
1569 | static inline bool is_extable_fault_address(Elf_Rela *r) | ||
1570 | { | ||
1571 | /* | ||
1572 | * extable_entry_size is only discovered after we've handled the | ||
1573 | * _second_ relocation in __ex_table, so only abort when we're not | ||
1574 | * handling the first reloc and extable_entry_size is zero. | ||
1575 | */ | ||
1576 | if (r->r_offset && extable_entry_size == 0) | ||
1577 | fatal("extable_entry size hasn't been discovered!\n"); | ||
1578 | |||
1579 | return ((r->r_offset == 0) || | ||
1580 | (r->r_offset % extable_entry_size == 0)); | ||
1581 | } | ||
1582 | |||
1583 | #define is_second_extable_reloc(Start, Cur, Sec) \ | ||
1584 | (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0)) | ||
1585 | |||
1586 | static void report_extable_warnings(const char* modname, struct elf_info* elf, | ||
1587 | const struct sectioncheck* const mismatch, | ||
1588 | Elf_Rela* r, Elf_Sym* sym, | ||
1589 | const char* fromsec, const char* tosec) | ||
1590 | { | ||
1591 | Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec); | ||
1592 | const char* fromsym_name = sym_name(elf, fromsym); | ||
1593 | Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym); | ||
1594 | const char* tosym_name = sym_name(elf, tosym); | ||
1595 | const char* from_pretty_name; | ||
1596 | const char* from_pretty_name_p; | ||
1597 | const char* to_pretty_name; | ||
1598 | const char* to_pretty_name_p; | ||
1599 | |||
1600 | get_pretty_name(is_function(fromsym), | ||
1601 | &from_pretty_name, &from_pretty_name_p); | ||
1602 | get_pretty_name(is_function(tosym), | ||
1603 | &to_pretty_name, &to_pretty_name_p); | ||
1604 | |||
1605 | warn("%s(%s+0x%lx): Section mismatch in reference" | ||
1606 | " from the %s %s%s to the %s %s:%s%s\n", | ||
1607 | modname, fromsec, (long)r->r_offset, from_pretty_name, | ||
1608 | fromsym_name, from_pretty_name_p, | ||
1609 | to_pretty_name, tosec, tosym_name, to_pretty_name_p); | ||
1610 | |||
1611 | if (!match(tosec, mismatch->bad_tosec) && | ||
1612 | is_executable_section(elf, get_secindex(elf, sym))) | ||
1613 | fprintf(stderr, | ||
1614 | "The relocation at %s+0x%lx references\n" | ||
1615 | "section \"%s\" which is not in the list of\n" | ||
1616 | "authorized sections. If you're adding a new section\n" | ||
1617 | "and/or if this reference is valid, add \"%s\" to the\n" | ||
1618 | "list of authorized sections to jump to on fault.\n" | ||
1619 | "This can be achieved by adding \"%s\" to \n" | ||
1620 | "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n", | ||
1621 | fromsec, (long)r->r_offset, tosec, tosec, tosec); | ||
1622 | } | ||
1623 | |||
1624 | static void extable_mismatch_handler(const char* modname, struct elf_info *elf, | ||
1625 | const struct sectioncheck* const mismatch, | ||
1626 | Elf_Rela* r, Elf_Sym* sym, | ||
1627 | const char *fromsec) | ||
1628 | { | ||
1629 | const char* tosec = sec_name(elf, get_secindex(elf, sym)); | ||
1630 | |||
1631 | sec_mismatch_count++; | ||
1632 | |||
1633 | if (sec_mismatch_verbose) | ||
1634 | report_extable_warnings(modname, elf, mismatch, r, sym, | ||
1635 | fromsec, tosec); | ||
1636 | |||
1637 | if (match(tosec, mismatch->bad_tosec)) | ||
1638 | fatal("The relocation at %s+0x%lx references\n" | ||
1639 | "section \"%s\" which is black-listed.\n" | ||
1640 | "Something is seriously wrong and should be fixed.\n" | ||
1641 | "You might get more information about where this is\n" | ||
1642 | "coming from by using scripts/check_extable.sh %s\n", | ||
1643 | fromsec, (long)r->r_offset, tosec, modname); | ||
1644 | else if (!is_executable_section(elf, get_secindex(elf, sym))) { | ||
1645 | if (is_extable_fault_address(r)) | ||
1646 | fatal("The relocation at %s+0x%lx references\n" | ||
1647 | "section \"%s\" which is not executable, IOW\n" | ||
1648 | "it is not possible for the kernel to fault\n" | ||
1649 | "at that address. Something is seriously wrong\n" | ||
1650 | "and should be fixed.\n", | ||
1651 | fromsec, (long)r->r_offset, tosec); | ||
1652 | else | ||
1653 | fatal("The relocation at %s+0x%lx references\n" | ||
1654 | "section \"%s\" which is not executable, IOW\n" | ||
1655 | "the kernel will fault if it ever tries to\n" | ||
1656 | "jump to it. Something is seriously wrong\n" | ||
1657 | "and should be fixed.\n", | ||
1658 | fromsec, (long)r->r_offset, tosec); | ||
1659 | } | ||
1660 | } | ||
1661 | |||
1662 | static void check_section_mismatch(const char *modname, struct elf_info *elf, | ||
1663 | Elf_Rela *r, Elf_Sym *sym, const char *fromsec) | ||
1664 | { | ||
1665 | const char *tosec = sec_name(elf, get_secindex(elf, sym));; | ||
1666 | const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec); | ||
1667 | |||
1423 | if (mismatch) { | 1668 | if (mismatch) { |
1424 | Elf_Sym *to; | 1669 | if (mismatch->handler) |
1425 | Elf_Sym *from; | 1670 | mismatch->handler(modname, elf, mismatch, |
1426 | const char *tosym; | 1671 | r, sym, fromsec); |
1427 | const char *fromsym; | 1672 | else |
1428 | 1673 | default_mismatch_handler(modname, elf, mismatch, | |
1429 | from = find_elf_symbol2(elf, r->r_offset, fromsec); | 1674 | r, sym, fromsec); |
1430 | fromsym = sym_name(elf, from); | ||
1431 | to = find_elf_symbol(elf, r->r_addend, sym); | ||
1432 | tosym = sym_name(elf, to); | ||
1433 | |||
1434 | if (!strncmp(fromsym, "reference___initcall", | ||
1435 | sizeof("reference___initcall")-1)) | ||
1436 | return; | ||
1437 | |||
1438 | /* check whitelist - we may ignore it */ | ||
1439 | if (secref_whitelist(mismatch, | ||
1440 | fromsec, fromsym, tosec, tosym)) { | ||
1441 | report_sec_mismatch(modname, mismatch, | ||
1442 | fromsec, r->r_offset, fromsym, | ||
1443 | is_function(from), tosec, tosym, | ||
1444 | is_function(to)); | ||
1445 | } | ||
1446 | } | 1675 | } |
1447 | } | 1676 | } |
1448 | 1677 | ||
@@ -1582,6 +1811,8 @@ static void section_rela(const char *modname, struct elf_info *elf, | |||
1582 | /* Skip special sections */ | 1811 | /* Skip special sections */ |
1583 | if (is_shndx_special(sym->st_shndx)) | 1812 | if (is_shndx_special(sym->st_shndx)) |
1584 | continue; | 1813 | continue; |
1814 | if (is_second_extable_reloc(start, rela, fromsec)) | ||
1815 | find_extable_entry_size(fromsec, &r); | ||
1585 | check_section_mismatch(modname, elf, &r, sym, fromsec); | 1816 | check_section_mismatch(modname, elf, &r, sym, fromsec); |
1586 | } | 1817 | } |
1587 | } | 1818 | } |
@@ -1640,6 +1871,8 @@ static void section_rel(const char *modname, struct elf_info *elf, | |||
1640 | /* Skip special sections */ | 1871 | /* Skip special sections */ |
1641 | if (is_shndx_special(sym->st_shndx)) | 1872 | if (is_shndx_special(sym->st_shndx)) |
1642 | continue; | 1873 | continue; |
1874 | if (is_second_extable_reloc(start, rel, fromsec)) | ||
1875 | find_extable_entry_size(fromsec, &r); | ||
1643 | check_section_mismatch(modname, elf, &r, sym, fromsec); | 1876 | check_section_mismatch(modname, elf, &r, sym, fromsec); |
1644 | } | 1877 | } |
1645 | } | 1878 | } |