Skip to content

Commit

Permalink
kbuild: modversions: add infrastructure for emitting relative CRCs
Browse files Browse the repository at this point in the history
This add the kbuild infrastructure that will allow architectures to emit
vmlinux symbol CRCs as 32-bit offsets to another location in the kernel
where the actual value is stored. This works around problems with CRCs
being mistaken for relocatable symbols on kernels that self relocate at
runtime (i.e., powerpc with CONFIG_RELOCATABLE=y)

For the kbuild side of things, this comes down to the following:

 - introducing a Kconfig symbol MODULE_REL_CRCS

 - adding a -R switch to genksyms to instruct it to emit the CRC symbols
   as references into the .rodata section

 - making modpost distinguish such references from absolute CRC symbols
   by the section index (SHN_ABS)

 - making kallsyms disregard non-absolute symbols with a __crc_ prefix

Signed-off-by: Ard Biesheuvel <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Ard Biesheuvel authored and torvalds committed Feb 3, 2017
1 parent 34e00ac commit 5606781
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 5 deletions.
4 changes: 4 additions & 0 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions scripts/Makefile.build
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -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))

Expand Down
19 changes: 14 additions & 5 deletions scripts/genksyms/genksyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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);
}
Expand All @@ -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':
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions scripts/kallsyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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]);

Expand Down
10 changes: 10 additions & 0 deletions scripts/mod/modpost.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit 5606781

Please sign in to comment.