diff options
| -rw-r--r-- | arch/powerpc/include/asm/module.h | 5 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vmlinux.lds.S | 3 | ||||
| -rw-r--r-- | kernel/module.c | 28 |
3 files changed, 29 insertions, 7 deletions
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index 08454880a2c0..0192a4ee2bc2 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h | |||
| @@ -87,5 +87,10 @@ struct exception_table_entry; | |||
| 87 | void sort_ex_table(struct exception_table_entry *start, | 87 | void sort_ex_table(struct exception_table_entry *start, |
| 88 | struct exception_table_entry *finish); | 88 | struct exception_table_entry *finish); |
| 89 | 89 | ||
| 90 | #ifdef CONFIG_MODVERSIONS | ||
| 91 | #define ARCH_RELOCATES_KCRCTAB | ||
| 92 | |||
| 93 | extern const unsigned long reloc_start[]; | ||
| 94 | #endif | ||
| 90 | #endif /* __KERNEL__ */ | 95 | #endif /* __KERNEL__ */ |
| 91 | #endif /* _ASM_POWERPC_MODULE_H */ | 96 | #endif /* _ASM_POWERPC_MODULE_H */ |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 27735a7ac12b..dcd01c82e701 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
| @@ -38,6 +38,9 @@ jiffies = jiffies_64 + 4; | |||
| 38 | #endif | 38 | #endif |
| 39 | SECTIONS | 39 | SECTIONS |
| 40 | { | 40 | { |
| 41 | . = 0; | ||
| 42 | reloc_start = .; | ||
| 43 | |||
| 41 | . = KERNELBASE; | 44 | . = KERNELBASE; |
| 42 | 45 | ||
| 43 | /* | 46 | /* |
diff --git a/kernel/module.c b/kernel/module.c index 12afc5a3ddd3..a65dc787a27b 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; |
