Skip to content

Commit d4703ae

Browse files
committed
module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y
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 Inspired-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Tested-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Paul Mackerras <paulus@samba.org>
1 parent a877376 commit d4703ae

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

arch/powerpc/include/asm/module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,10 @@ struct exception_table_entry;
8787
void sort_ex_table(struct exception_table_entry *start,
8888
struct exception_table_entry *finish);
8989

90+
#ifdef CONFIG_MODVERSIONS
91+
#define ARCH_RELOCATES_KCRCTAB
92+
93+
extern const unsigned long reloc_start[];
94+
#endif
9095
#endif /* __KERNEL__ */
9196
#endif /* _ASM_POWERPC_MODULE_H */

arch/powerpc/kernel/vmlinux.lds.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ jiffies = jiffies_64 + 4;
3838
#endif
3939
SECTIONS
4040
{
41+
. = 0;
42+
reloc_start = .;
43+
4144
. = KERNELBASE;
4245

4346
/*

kernel/module.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -880,11 +880,23 @@ static int try_to_force_load(struct module *mod, const char *reason)
880880
}
881881

882882
#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+
883894
static int check_version(Elf_Shdr *sechdrs,
884895
unsigned int versindex,
885896
const char *symname,
886897
struct module *mod,
887-
const unsigned long *crc)
898+
const unsigned long *crc,
899+
const struct module *crc_owner)
888900
{
889901
unsigned int i, num_versions;
890902
struct modversion_info *versions;
@@ -905,10 +917,10 @@ static int check_version(Elf_Shdr *sechdrs,
905917
if (strcmp(versions[i].name, symname) != 0)
906918
continue;
907919

908-
if (versions[i].crc == *crc)
920+
if (versions[i].crc == maybe_relocated(*crc, crc_owner))
909921
return 1;
910922
DEBUGP("Found checksum %lX vs module %lX\n",
911-
*crc, versions[i].crc);
923+
maybe_relocated(*crc, crc_owner), versions[i].crc);
912924
goto bad_version;
913925
}
914926

@@ -931,7 +943,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
931943
if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL,
932944
&crc, true, false))
933945
BUG();
934-
return check_version(sechdrs, versindex, "module_layout", mod, crc);
946+
return check_version(sechdrs, versindex, "module_layout", mod, crc,
947+
NULL);
935948
}
936949

937950
/* First part is kernel version, which we ignore if module has crcs. */
@@ -949,7 +962,8 @@ static inline int check_version(Elf_Shdr *sechdrs,
949962
unsigned int versindex,
950963
const char *symname,
951964
struct module *mod,
952-
const unsigned long *crc)
965+
const unsigned long *crc,
966+
const struct module *crc_owner)
953967
{
954968
return 1;
955969
}
@@ -984,8 +998,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs,
984998
/* use_module can fail due to OOM,
985999
or module initialization or unloading */
9861000
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))
9891003
sym = NULL;
9901004
}
9911005
return sym;

0 commit comments

Comments
 (0)