powerpc applies relocations to the kcrctab. They're absolute symbols, but it's not completely unreasonable: other archs may too, but the relocation is often 0. http://lists.ozlabs.org/pipermail/linuxppc-dev/2009-November/077972.html
Showing the changes to kernel/module.c (1 of 3 files). Show all
Unified · Split
| @@ -880,11 +880,23 @@ static int try_to_force_load(struct module *mod, const char *reason) · 879 unmodified lines | ||
| 880 | 880 | } |
| 881 | 881 | |
| 882 | 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 | 894 | static int check_version(Elf_Shdr *sechdrs, |
| 884 | 895 | unsigned int versindex, |
| 885 | 896 | const char *symname, |
| 886 | 897 | struct module *mod, |
| 887 | − const unsigned long *crc) | |
| 898 | + const unsigned long *crc, | |
| 899 | + const struct module *crc_owner) | |
| 888 | 900 | { |
| 889 | 901 | unsigned int i, num_versions; |
| 890 | 902 | struct modversion_info *versions; |
| @@ -905,10 +917,10 @@ static int check_version(Elf_Shdr *sechdrs, · 14 unmodified lines | ||
| 905 | 917 | if (strcmp(versions[i].name, symname) != 0) |
| 906 | 918 | continue; |
| 907 | 919 | |
| 908 | − if (versions[i].crc == *crc) | |
| 920 | + if (versions[i].crc == maybe_relocated(*crc, crc_owner)) | |
| 909 | 921 | return 1; |
| 910 | 922 | DEBUGP("Found checksum %lX vs module %lX\n", |
| 911 | − *crc, versions[i].crc); | |
| 923 | + maybe_relocated(*crc, crc_owner), versions[i].crc); | |
| 912 | 924 | goto bad_version; |
| 913 | 925 | } |
| 914 | 926 | |
| @@ -931,7 +943,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, · 16 unmodified lines | ||
| 931 | 943 | if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, |
| 932 | 944 | &crc, true, false)) |
| 933 | 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 | 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, · 11 unmodified lines | ||
| 949 | 962 | unsigned int versindex, |
| 950 | 963 | const char *symname, |
| 951 | 964 | struct module *mod, |
| 952 | − const unsigned long *crc) | |
| 965 | + const unsigned long *crc, | |
| 966 | + const struct module *crc_owner) | |
| 953 | 967 | { |
| 954 | 968 | return 1; |
| 955 | 969 | } |
| @@ -984,8 +998,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, · 28 unmodified lines | ||
| 984 | 998 | /* use_module can fail due to OOM, |
| 985 | 999 | or module initialization or unloading */ |
| 986 | 1000 | if (sym) { |
| 987 | − if (!check_version(sechdrs, versindex, name, mod, crc) || | |
| 988 | − !use_module(mod, owner)) | |
| 1001 | + if (!check_version(sechdrs, versindex, name, mod, crc, owner) | |
| 1002 | + || !use_module(mod, owner)) | |
| 989 | 1003 | sym = NULL; |
| 990 | 1004 | } |
| 991 | 1005 | return sym; |