diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-03-01 02:55:20 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-03-01 02:55:20 -0500 |
| commit | 35858adbfca13678af99fb31618ef4428d6dedb0 (patch) | |
| tree | 3336feaa61324486945816cb52c347733e7c0821 /kernel/module.c | |
| parent | 197d4db752e67160d79fed09968c2140376a80a3 (diff) | |
| parent | 4b70858ba8d4537daf782defebe5f2ff80ccef2b (diff) | |
Merge branch 'next' into for-linus
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 58 |
1 files changed, 39 insertions, 19 deletions
diff --git a/kernel/module.c b/kernel/module.c index 12afc5a3ddd3..f82386bd9ee9 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -880,11 +880,23 @@ static int try_to_force_load(struct module *mod, const char *reason) | |||
| 880 | } | 880 | } |
| 881 | 881 | ||
| 882 | #ifdef CONFIG_MODVERSIONS | 882 | #ifdef CONFIG_MODVERSIONS |
| 883 | /* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */ | ||
| 884 | static unsigned long maybe_relocated(unsigned long crc, | ||
| 885 | const struct module *crc_owner) | ||
| 886 | { | ||
| 887 | #ifdef ARCH_RELOCATES_KCRCTAB | ||
| 888 | if (crc_owner == NULL) | ||
| 889 | return crc - (unsigned long)reloc_start; | ||
| 890 | #endif | ||
| 891 | return crc; | ||
| 892 | } | ||
| 893 | |||
| 883 | static int check_version(Elf_Shdr *sechdrs, | 894 | static int check_version(Elf_Shdr *sechdrs, |
| 884 | unsigned int versindex, | 895 | unsigned int versindex, |
| 885 | const char *symname, | 896 | const char *symname, |
| 886 | struct module *mod, | 897 | struct module *mod, |
| 887 | const unsigned long *crc) | 898 | const unsigned long *crc, |
| 899 | const struct module *crc_owner) | ||
| 888 | { | 900 | { |
| 889 | unsigned int i, num_versions; | 901 | unsigned int i, num_versions; |
| 890 | struct modversion_info *versions; | 902 | struct modversion_info *versions; |
| @@ -905,10 +917,10 @@ static int check_version(Elf_Shdr *sechdrs, | |||
| 905 | if (strcmp(versions[i].name, symname) != 0) | 917 | if (strcmp(versions[i].name, symname) != 0) |
| 906 | continue; | 918 | continue; |
| 907 | 919 | ||
| 908 | if (versions[i].crc == *crc) | 920 | if (versions[i].crc == maybe_relocated(*crc, crc_owner)) |
| 909 | return 1; | 921 | return 1; |
| 910 | DEBUGP("Found checksum %lX vs module %lX\n", | 922 | DEBUGP("Found checksum %lX vs module %lX\n", |
| 911 | *crc, versions[i].crc); | 923 | maybe_relocated(*crc, crc_owner), versions[i].crc); |
| 912 | goto bad_version; | 924 | goto bad_version; |
| 913 | } | 925 | } |
| 914 | 926 | ||
| @@ -931,7 +943,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, | |||
| 931 | if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, | 943 | if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, |
| 932 | &crc, true, false)) | 944 | &crc, true, false)) |
| 933 | BUG(); | 945 | BUG(); |
| 934 | return check_version(sechdrs, versindex, "module_layout", mod, crc); | 946 | return check_version(sechdrs, versindex, "module_layout", mod, crc, |
| 947 | NULL); | ||
| 935 | } | 948 | } |
| 936 | 949 | ||
| 937 | /* First part is kernel version, which we ignore if module has crcs. */ | 950 | /* First part is kernel version, which we ignore if module has crcs. */ |
| @@ -949,7 +962,8 @@ static inline int check_version(Elf_Shdr *sechdrs, | |||
| 949 | unsigned int versindex, | 962 | unsigned int versindex, |
| 950 | const char *symname, | 963 | const char *symname, |
| 951 | struct module *mod, | 964 | struct module *mod, |
| 952 | const unsigned long *crc) | 965 | const unsigned long *crc, |
| 966 | const struct module *crc_owner) | ||
| 953 | { | 967 | { |
| 954 | return 1; | 968 | return 1; |
| 955 | } | 969 | } |
| @@ -984,8 +998,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, | |||
| 984 | /* use_module can fail due to OOM, | 998 | /* use_module can fail due to OOM, |
| 985 | or module initialization or unloading */ | 999 | or module initialization or unloading */ |
| 986 | if (sym) { | 1000 | if (sym) { |
| 987 | if (!check_version(sechdrs, versindex, name, mod, crc) || | 1001 | if (!check_version(sechdrs, versindex, name, mod, crc, owner) |
| 988 | !use_module(mod, owner)) | 1002 | || !use_module(mod, owner)) |
| 989 | sym = NULL; | 1003 | sym = NULL; |
| 990 | } | 1004 | } |
| 991 | return sym; | 1005 | return sym; |
| @@ -996,6 +1010,12 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, | |||
| 996 | * J. Corbet <corbet@lwn.net> | 1010 | * J. Corbet <corbet@lwn.net> |
| 997 | */ | 1011 | */ |
| 998 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) | 1012 | #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) |
| 1013 | |||
| 1014 | static inline bool sect_empty(const Elf_Shdr *sect) | ||
| 1015 | { | ||
| 1016 | return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0; | ||
| 1017 | } | ||
| 1018 | |||
| 999 | struct module_sect_attr | 1019 | struct module_sect_attr |
| 1000 | { | 1020 | { |
| 1001 | struct module_attribute mattr; | 1021 | struct module_attribute mattr; |
| @@ -1037,8 +1057,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, | |||
| 1037 | 1057 | ||
| 1038 | /* Count loaded sections and allocate structures */ | 1058 | /* Count loaded sections and allocate structures */ |
| 1039 | for (i = 0; i < nsect; i++) | 1059 | for (i = 0; i < nsect; i++) |
| 1040 | if (sechdrs[i].sh_flags & SHF_ALLOC | 1060 | if (!sect_empty(&sechdrs[i])) |
| 1041 | && sechdrs[i].sh_size) | ||
| 1042 | nloaded++; | 1061 | nloaded++; |
| 1043 | size[0] = ALIGN(sizeof(*sect_attrs) | 1062 | size[0] = ALIGN(sizeof(*sect_attrs) |
| 1044 | + nloaded * sizeof(sect_attrs->attrs[0]), | 1063 | + nloaded * sizeof(sect_attrs->attrs[0]), |
| @@ -1056,9 +1075,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, | |||
| 1056 | sattr = §_attrs->attrs[0]; | 1075 | sattr = §_attrs->attrs[0]; |
| 1057 | gattr = §_attrs->grp.attrs[0]; | 1076 | gattr = §_attrs->grp.attrs[0]; |
| 1058 | for (i = 0; i < nsect; i++) { | 1077 | for (i = 0; i < nsect; i++) { |
| 1059 | if (! (sechdrs[i].sh_flags & SHF_ALLOC)) | 1078 | if (sect_empty(&sechdrs[i])) |
| 1060 | continue; | ||
| 1061 | if (!sechdrs[i].sh_size) | ||
| 1062 | continue; | 1079 | continue; |
| 1063 | sattr->address = sechdrs[i].sh_addr; | 1080 | sattr->address = sechdrs[i].sh_addr; |
| 1064 | sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, | 1081 | sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, |
| @@ -1142,7 +1159,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, | |||
| 1142 | /* Count notes sections and allocate structures. */ | 1159 | /* Count notes sections and allocate structures. */ |
| 1143 | notes = 0; | 1160 | notes = 0; |
| 1144 | for (i = 0; i < nsect; i++) | 1161 | for (i = 0; i < nsect; i++) |
| 1145 | if ((sechdrs[i].sh_flags & SHF_ALLOC) && | 1162 | if (!sect_empty(&sechdrs[i]) && |
| 1146 | (sechdrs[i].sh_type == SHT_NOTE)) | 1163 | (sechdrs[i].sh_type == SHT_NOTE)) |
| 1147 | ++notes; | 1164 | ++notes; |
| 1148 | 1165 | ||
| @@ -1158,7 +1175,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, | |||
| 1158 | notes_attrs->notes = notes; | 1175 | notes_attrs->notes = notes; |
| 1159 | nattr = ¬es_attrs->attrs[0]; | 1176 | nattr = ¬es_attrs->attrs[0]; |
| 1160 | for (loaded = i = 0; i < nsect; ++i) { | 1177 | for (loaded = i = 0; i < nsect; ++i) { |
| 1161 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | 1178 | if (sect_empty(&sechdrs[i])) |
| 1162 | continue; | 1179 | continue; |
| 1163 | if (sechdrs[i].sh_type == SHT_NOTE) { | 1180 | if (sechdrs[i].sh_type == SHT_NOTE) { |
| 1164 | nattr->attr.name = mod->sect_attrs->attrs[loaded].name; | 1181 | nattr->attr.name = mod->sect_attrs->attrs[loaded].name; |
| @@ -1896,9 +1913,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | |||
| 1896 | unsigned int i; | 1913 | unsigned int i; |
| 1897 | 1914 | ||
| 1898 | /* only scan the sections containing data */ | 1915 | /* only scan the sections containing data */ |
| 1899 | kmemleak_scan_area(mod->module_core, (unsigned long)mod - | 1916 | kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL); |
| 1900 | (unsigned long)mod->module_core, | ||
| 1901 | sizeof(struct module), GFP_KERNEL); | ||
| 1902 | 1917 | ||
| 1903 | for (i = 1; i < hdr->e_shnum; i++) { | 1918 | for (i = 1; i < hdr->e_shnum; i++) { |
| 1904 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | 1919 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) |
| @@ -1907,8 +1922,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | |||
| 1907 | && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0) | 1922 | && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0) |
| 1908 | continue; | 1923 | continue; |
| 1909 | 1924 | ||
| 1910 | kmemleak_scan_area(mod->module_core, sechdrs[i].sh_addr - | 1925 | kmemleak_scan_area((void *)sechdrs[i].sh_addr, |
| 1911 | (unsigned long)mod->module_core, | ||
| 1912 | sechdrs[i].sh_size, GFP_KERNEL); | 1926 | sechdrs[i].sh_size, GFP_KERNEL); |
| 1913 | } | 1927 | } |
| 1914 | } | 1928 | } |
| @@ -2236,6 +2250,12 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2236 | "_ftrace_events", | 2250 | "_ftrace_events", |
| 2237 | sizeof(*mod->trace_events), | 2251 | sizeof(*mod->trace_events), |
| 2238 | &mod->num_trace_events); | 2252 | &mod->num_trace_events); |
| 2253 | /* | ||
| 2254 | * This section contains pointers to allocated objects in the trace | ||
| 2255 | * code and not scanning it leads to false positives. | ||
| 2256 | */ | ||
| 2257 | kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) * | ||
| 2258 | mod->num_trace_events, GFP_KERNEL); | ||
| 2239 | #endif | 2259 | #endif |
| 2240 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | 2260 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD |
| 2241 | /* sechdrs[0].sh_size is always zero */ | 2261 | /* sechdrs[0].sh_size is always zero */ |
