Merge branch 'modversions' (modversions fixes for powerpc from Ard)
Merge kcrctab entry fixes from Ard Biesheuvel: "This is a followup to [0] 'modversions: redefine kcrctab entries as relative CRC pointers', but since relative CRC pointers do not work in modules, and are actually only needed by powerpc with CONFIG_RELOCATABLE=y, I have made it a Kconfig selectable feature instead. First it introduces the MODULE_REL_CRCS Kconfig symbol, and adds the kbuild handling of it, i.e., modpost, genksyms and kallsyms. Then it switches all architectures to 32-bit CRC entries in kcrctab, where all architectures except powerpc with CONFIG_RELOCATABLE=y use absolute ELF symbol references as before" [0] http://marc.info/?l=linux-arch&m=148493613415294&w=2 * emailed patches from Ard Biesheuvel: module: unify absolute krctab definitions for 32-bit and 64-bit modversions: treat symbol CRCs as 32 bit quantities kbuild: modversions: add infrastructure for emitting relative CRCs
This commit is contained in:
commit
2cb54ce9ee
@ -484,6 +484,7 @@ config RELOCATABLE
|
||||
bool "Build a relocatable kernel"
|
||||
depends on (PPC64 && !COMPILE_TEST) || (FLATMEM && (44x || FSL_BOOKE))
|
||||
select NONSTATIC_KERNEL
|
||||
select MODULE_REL_CRCS if MODVERSIONS
|
||||
help
|
||||
This builds a kernel image that is capable of running at the
|
||||
location the kernel is loaded at. For ppc32, there is no any
|
||||
|
@ -90,9 +90,5 @@ static inline int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sec
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
|
||||
#define ARCH_RELOCATES_KCRCTAB
|
||||
#define reloc_start PHYSICAL_START
|
||||
#endif
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_POWERPC_MODULE_H */
|
||||
|
@ -286,14 +286,6 @@ static void dedotify_versions(struct modversion_info *vers,
|
||||
for (end = (void *)vers + size; vers < end; vers++)
|
||||
if (vers->name[0] == '.') {
|
||||
memmove(vers->name, vers->name+1, strlen(vers->name));
|
||||
#ifdef ARCH_RELOCATES_KCRCTAB
|
||||
/* The TOC symbol has no CRC computed. To avoid CRC
|
||||
* check failing, we must force it to the expected
|
||||
* value (see CRC check in module.c).
|
||||
*/
|
||||
if (!strcmp(vers->name, "TOC."))
|
||||
vers->crc = -(unsigned long)reloc_start;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,18 +9,15 @@
|
||||
#ifndef KSYM_ALIGN
|
||||
#define KSYM_ALIGN 8
|
||||
#endif
|
||||
#ifndef KCRC_ALIGN
|
||||
#define KCRC_ALIGN 8
|
||||
#endif
|
||||
#else
|
||||
#define __put .long
|
||||
#ifndef KSYM_ALIGN
|
||||
#define KSYM_ALIGN 4
|
||||
#endif
|
||||
#endif
|
||||
#ifndef KCRC_ALIGN
|
||||
#define KCRC_ALIGN 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
|
||||
#define KSYM(name) _##name
|
||||
@ -52,7 +49,11 @@ KSYM(__kstrtab_\name):
|
||||
.section ___kcrctab\sec+\name,"a"
|
||||
.balign KCRC_ALIGN
|
||||
KSYM(__kcrctab_\name):
|
||||
__put KSYM(__crc_\name)
|
||||
#if defined(CONFIG_MODULE_REL_CRCS)
|
||||
.long KSYM(__crc_\name) - .
|
||||
#else
|
||||
.long KSYM(__crc_\name)
|
||||
#endif
|
||||
.weak KSYM(__crc_\name)
|
||||
.previous
|
||||
#endif
|
||||
|
@ -43,12 +43,19 @@ extern struct module __this_module;
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
/* Mark the CRC weak since genksyms apparently decides not to
|
||||
* generate a checksums for some symbols */
|
||||
#if defined(CONFIG_MODULE_REL_CRCS)
|
||||
#define __CRC_SYMBOL(sym, sec) \
|
||||
extern __visible void *__crc_##sym __attribute__((weak)); \
|
||||
static const unsigned long __kcrctab_##sym \
|
||||
__used \
|
||||
__attribute__((section("___kcrctab" sec "+" #sym), used)) \
|
||||
= (unsigned long) &__crc_##sym;
|
||||
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
|
||||
" .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
|
||||
" .long " VMLINUX_SYMBOL_STR(__crc_##sym) " - . \n" \
|
||||
" .previous \n");
|
||||
#else
|
||||
#define __CRC_SYMBOL(sym, sec) \
|
||||
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
|
||||
" .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
|
||||
" .long " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
|
||||
" .previous \n");
|
||||
#endif
|
||||
#else
|
||||
#define __CRC_SYMBOL(sym, sec)
|
||||
#endif
|
||||
|
@ -346,7 +346,7 @@ struct module {
|
||||
|
||||
/* Exported symbols */
|
||||
const struct kernel_symbol *syms;
|
||||
const unsigned long *crcs;
|
||||
const s32 *crcs;
|
||||
unsigned int num_syms;
|
||||
|
||||
/* Kernel parameters. */
|
||||
@ -359,18 +359,18 @@ struct module {
|
||||
/* GPL-only exported symbols. */
|
||||
unsigned int num_gpl_syms;
|
||||
const struct kernel_symbol *gpl_syms;
|
||||
const unsigned long *gpl_crcs;
|
||||
const s32 *gpl_crcs;
|
||||
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
/* unused exported symbols. */
|
||||
const struct kernel_symbol *unused_syms;
|
||||
const unsigned long *unused_crcs;
|
||||
const s32 *unused_crcs;
|
||||
unsigned int num_unused_syms;
|
||||
|
||||
/* GPL-only, unused exported symbols. */
|
||||
unsigned int num_unused_gpl_syms;
|
||||
const struct kernel_symbol *unused_gpl_syms;
|
||||
const unsigned long *unused_gpl_crcs;
|
||||
const s32 *unused_gpl_crcs;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
@ -382,7 +382,7 @@ struct module {
|
||||
|
||||
/* symbols that will be GPL-only in the near future. */
|
||||
const struct kernel_symbol *gpl_future_syms;
|
||||
const unsigned long *gpl_future_crcs;
|
||||
const s32 *gpl_future_crcs;
|
||||
unsigned int num_gpl_future_syms;
|
||||
|
||||
/* Exception table */
|
||||
@ -523,7 +523,7 @@ struct module *find_module(const char *name);
|
||||
|
||||
struct symsearch {
|
||||
const struct kernel_symbol *start, *stop;
|
||||
const unsigned long *crcs;
|
||||
const s32 *crcs;
|
||||
enum {
|
||||
NOT_GPL_ONLY,
|
||||
GPL_ONLY,
|
||||
@ -539,7 +539,7 @@ struct symsearch {
|
||||
*/
|
||||
const struct kernel_symbol *find_symbol(const char *name,
|
||||
struct module **owner,
|
||||
const unsigned long **crc,
|
||||
const s32 **crc,
|
||||
bool gplok,
|
||||
bool warn);
|
||||
|
||||
|
@ -1987,6 +1987,10 @@ config MODVERSIONS
|
||||
make them incompatible with the kernel you are running. If
|
||||
unsure, say N.
|
||||
|
||||
config MODULE_REL_CRCS
|
||||
bool
|
||||
depends on MODVERSIONS
|
||||
|
||||
config MODULE_SRCVERSION_ALL
|
||||
bool "Source checksum for all modules"
|
||||
help
|
||||
|
@ -389,16 +389,16 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_gpl[];
|
||||
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
|
||||
extern const unsigned long __start___kcrctab[];
|
||||
extern const unsigned long __start___kcrctab_gpl[];
|
||||
extern const unsigned long __start___kcrctab_gpl_future[];
|
||||
extern const s32 __start___kcrctab[];
|
||||
extern const s32 __start___kcrctab_gpl[];
|
||||
extern const s32 __start___kcrctab_gpl_future[];
|
||||
#ifdef CONFIG_UNUSED_SYMBOLS
|
||||
extern const struct kernel_symbol __start___ksymtab_unused[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_unused[];
|
||||
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
|
||||
extern const unsigned long __start___kcrctab_unused[];
|
||||
extern const unsigned long __start___kcrctab_unused_gpl[];
|
||||
extern const s32 __start___kcrctab_unused[];
|
||||
extern const s32 __start___kcrctab_unused_gpl[];
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_MODVERSIONS
|
||||
@ -497,7 +497,7 @@ struct find_symbol_arg {
|
||||
|
||||
/* Output */
|
||||
struct module *owner;
|
||||
const unsigned long *crc;
|
||||
const s32 *crc;
|
||||
const struct kernel_symbol *sym;
|
||||
};
|
||||
|
||||
@ -563,7 +563,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,
|
||||
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
|
||||
const struct kernel_symbol *find_symbol(const char *name,
|
||||
struct module **owner,
|
||||
const unsigned long **crc,
|
||||
const s32 **crc,
|
||||
bool gplok,
|
||||
bool warn)
|
||||
{
|
||||
@ -1249,23 +1249,17 @@ static int try_to_force_load(struct module *mod, const char *reason)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
|
||||
static unsigned long maybe_relocated(unsigned long crc,
|
||||
const struct module *crc_owner)
|
||||
|
||||
static u32 resolve_rel_crc(const s32 *crc)
|
||||
{
|
||||
#ifdef ARCH_RELOCATES_KCRCTAB
|
||||
if (crc_owner == NULL)
|
||||
return crc - (unsigned long)reloc_start;
|
||||
#endif
|
||||
return crc;
|
||||
return *(u32 *)((void *)crc + *crc);
|
||||
}
|
||||
|
||||
static int check_version(Elf_Shdr *sechdrs,
|
||||
unsigned int versindex,
|
||||
const char *symname,
|
||||
struct module *mod,
|
||||
const unsigned long *crc,
|
||||
const struct module *crc_owner)
|
||||
const s32 *crc)
|
||||
{
|
||||
unsigned int i, num_versions;
|
||||
struct modversion_info *versions;
|
||||
@ -1283,13 +1277,19 @@ static int check_version(Elf_Shdr *sechdrs,
|
||||
/ sizeof(struct modversion_info);
|
||||
|
||||
for (i = 0; i < num_versions; i++) {
|
||||
u32 crcval;
|
||||
|
||||
if (strcmp(versions[i].name, symname) != 0)
|
||||
continue;
|
||||
|
||||
if (versions[i].crc == maybe_relocated(*crc, crc_owner))
|
||||
if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
|
||||
crcval = resolve_rel_crc(crc);
|
||||
else
|
||||
crcval = *crc;
|
||||
if (versions[i].crc == crcval)
|
||||
return 1;
|
||||
pr_debug("Found checksum %lX vs module %lX\n",
|
||||
maybe_relocated(*crc, crc_owner), versions[i].crc);
|
||||
pr_debug("Found checksum %X vs module %lX\n",
|
||||
crcval, versions[i].crc);
|
||||
goto bad_version;
|
||||
}
|
||||
|
||||
@ -1307,7 +1307,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
|
||||
unsigned int versindex,
|
||||
struct module *mod)
|
||||
{
|
||||
const unsigned long *crc;
|
||||
const s32 *crc;
|
||||
|
||||
/*
|
||||
* Since this should be found in kernel (which can't be removed), no
|
||||
@ -1321,8 +1321,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
|
||||
}
|
||||
preempt_enable();
|
||||
return check_version(sechdrs, versindex,
|
||||
VMLINUX_SYMBOL_STR(module_layout), mod, crc,
|
||||
NULL);
|
||||
VMLINUX_SYMBOL_STR(module_layout), mod, crc);
|
||||
}
|
||||
|
||||
/* First part is kernel version, which we ignore if module has crcs. */
|
||||
@ -1340,8 +1339,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
|
||||
unsigned int versindex,
|
||||
const char *symname,
|
||||
struct module *mod,
|
||||
const unsigned long *crc,
|
||||
const struct module *crc_owner)
|
||||
const s32 *crc)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@ -1368,7 +1366,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
|
||||
{
|
||||
struct module *owner;
|
||||
const struct kernel_symbol *sym;
|
||||
const unsigned long *crc;
|
||||
const s32 *crc;
|
||||
int err;
|
||||
|
||||
/*
|
||||
@ -1383,8 +1381,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
|
||||
if (!sym)
|
||||
goto unlock;
|
||||
|
||||
if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
|
||||
owner)) {
|
||||
if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
|
||||
sym = ERR_PTR(-EINVAL);
|
||||
goto getname;
|
||||
}
|
||||
|
@ -164,6 +164,7 @@ cmd_gensymtypes_c = \
|
||||
$(CPP) -D__GENKSYMS__ $(c_flags) $< | \
|
||||
$(GENKSYMS) $(if $(1), -T $(2)) \
|
||||
$(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \
|
||||
$(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
|
||||
$(if $(KBUILD_PRESERVE),-p) \
|
||||
-r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
|
||||
|
||||
@ -337,6 +338,7 @@ cmd_gensymtypes_S = \
|
||||
$(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \
|
||||
$(GENKSYMS) $(if $(1), -T $(2)) \
|
||||
$(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \
|
||||
$(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
|
||||
$(if $(KBUILD_PRESERVE),-p) \
|
||||
-r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
|
||||
|
||||
|
@ -44,7 +44,7 @@ char *cur_filename, *source_file;
|
||||
int in_source_file;
|
||||
|
||||
static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
|
||||
flag_preserve, flag_warnings;
|
||||
flag_preserve, flag_warnings, flag_rel_crcs;
|
||||
static const char *mod_prefix = "";
|
||||
|
||||
static int errors;
|
||||
@ -693,7 +693,10 @@ void export_symbol(const char *name)
|
||||
fputs(">\n", debugfile);
|
||||
|
||||
/* Used as a linker script. */
|
||||
printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
|
||||
printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" :
|
||||
"SECTIONS { .rodata : ALIGN(4) { "
|
||||
"%s__crc_%s = .; LONG(0x%08lx); } }\n",
|
||||
mod_prefix, name, crc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -730,7 +733,7 @@ void error_with_pos(const char *fmt, ...)
|
||||
|
||||
static void genksyms_usage(void)
|
||||
{
|
||||
fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
|
||||
fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
|
||||
#ifdef __GNU_LIBRARY__
|
||||
" -s, --symbol-prefix Select symbol prefix\n"
|
||||
" -d, --debug Increment the debug level (repeatable)\n"
|
||||
@ -742,6 +745,7 @@ static void genksyms_usage(void)
|
||||
" -q, --quiet Disable warnings (default)\n"
|
||||
" -h, --help Print this message\n"
|
||||
" -V, --version Print the release version\n"
|
||||
" -R, --relative-crc Emit section relative symbol CRCs\n"
|
||||
#else /* __GNU_LIBRARY__ */
|
||||
" -s Select symbol prefix\n"
|
||||
" -d Increment the debug level (repeatable)\n"
|
||||
@ -753,6 +757,7 @@ static void genksyms_usage(void)
|
||||
" -q Disable warnings (default)\n"
|
||||
" -h Print this message\n"
|
||||
" -V Print the release version\n"
|
||||
" -R Emit section relative symbol CRCs\n"
|
||||
#endif /* __GNU_LIBRARY__ */
|
||||
, stderr);
|
||||
}
|
||||
@ -774,13 +779,14 @@ int main(int argc, char **argv)
|
||||
{"preserve", 0, 0, 'p'},
|
||||
{"version", 0, 0, 'V'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"relative-crc", 0, 0, 'R'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
|
||||
while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
|
||||
&long_opts[0], NULL)) != EOF)
|
||||
#else /* __GNU_LIBRARY__ */
|
||||
while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
|
||||
while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
|
||||
#endif /* __GNU_LIBRARY__ */
|
||||
switch (o) {
|
||||
case 's':
|
||||
@ -823,6 +829,9 @@ int main(int argc, char **argv)
|
||||
case 'h':
|
||||
genksyms_usage();
|
||||
return 0;
|
||||
case 'R':
|
||||
flag_rel_crcs = 1;
|
||||
break;
|
||||
default:
|
||||
genksyms_usage();
|
||||
return 1;
|
||||
|
@ -219,6 +219,10 @@ static int symbol_valid(struct sym_entry *s)
|
||||
"_SDA2_BASE_", /* ppc */
|
||||
NULL };
|
||||
|
||||
static char *special_prefixes[] = {
|
||||
"__crc_", /* modversions */
|
||||
NULL };
|
||||
|
||||
static char *special_suffixes[] = {
|
||||
"_veneer", /* arm */
|
||||
"_from_arm", /* arm */
|
||||
@ -259,6 +263,14 @@ static int symbol_valid(struct sym_entry *s)
|
||||
if (strcmp(sym_name, special_symbols[i]) == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; special_prefixes[i]; i++) {
|
||||
int l = strlen(special_prefixes[i]);
|
||||
|
||||
if (l <= strlen(sym_name) &&
|
||||
strncmp(sym_name, special_prefixes[i], l) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; special_suffixes[i]; i++) {
|
||||
int l = strlen(sym_name) - strlen(special_suffixes[i]);
|
||||
|
||||
|
@ -621,6 +621,16 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
|
||||
if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
|
||||
is_crc = true;
|
||||
crc = (unsigned int) sym->st_value;
|
||||
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
|
||||
unsigned int *crcp;
|
||||
|
||||
/* symbol points to the CRC in the ELF object */
|
||||
crcp = (void *)info->hdr + sym->st_value +
|
||||
info->sechdrs[sym->st_shndx].sh_offset -
|
||||
(info->hdr->e_type != ET_REL ?
|
||||
info->sechdrs[sym->st_shndx].sh_addr : 0);
|
||||
crc = *crcp;
|
||||
}
|
||||
sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
|
||||
export);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user