kbuild: modversions: add infrastructure for emitting relative CRCs
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Fri, 3 Feb 2017 09:54:05 +0000 (09:54 +0000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Feb 2017 16:28:25 +0000 (08:28 -0800)
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 <ard.biesheuvel@linaro.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
init/Kconfig
scripts/Makefile.build
scripts/genksyms/genksyms.c
scripts/kallsyms.c
scripts/mod/modpost.c

index e1a937348a3ed2bb3a76820e1ffa6a542f6aa9fb..4dd8bd232a1d4efd012fab8757887426ece9c0aa 100644 (file)
@@ -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
index eadcd4d359d91fc7823a75263c44c520e05f900b..d883116ebaa452d9c2f6c657de53121ebd9d50bd 100644 (file)
@@ -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))
 
index 06121ce524a76006072459d352d727b4aebdf203..c9235d8340f1e7ba33eacfaee94642c18f5fd211 100644 (file)
@@ -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;
index 299b92ca1ae092d82e9a0e3bffaec45988ebcc37..5d554419170b7d54ec82ddb1d31093d3eab0aa7d 100644 (file)
@@ -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]);
 
index 29c89a6bad3d3ac34e539189e83769f1c63ddab3..4dedd0d3d3a7fda58af2bc6150b9f6b6195d2cac 100644 (file)
@@ -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);
        }