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 /scripts/mod | |
| 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
Diffstat (limited to 'scripts/mod')
| -rw-r--r-- | scripts/mod/modpost.c | 341 |
1 files changed, 287 insertions, 54 deletions
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 | } |
