Skip to content

Commit 71810db

Browse files
Ard Biesheuveltorvalds
Ard Biesheuvel
authored andcommitted
modversions: treat symbol CRCs as 32 bit quantities
The modversion symbol CRCs are emitted as ELF symbols, which allows us to easily populate the kcrctab sections by relying on the linker to associate each kcrctab slot with the correct value. This has a couple of downsides: - Given that the CRCs are treated as memory addresses, we waste 4 bytes for each CRC on 64 bit architectures, - On architectures that support runtime relocation, a R_<arch>_RELATIVE relocation entry is emitted for each CRC value, which identifies it as a quantity that requires fixing up based on the actual runtime load offset of the kernel. This results in corrupted CRCs unless we explicitly undo the fixup (and this is currently being handled in the core module code) - Such runtime relocation entries take up 24 bytes of __init space each, resulting in a x8 overhead in [uncompressed] kernel size for CRCs. Switching to explicit 32 bit values on 64 bit architectures fixes most of these issues, given that 32 bit values are not treated as quantities that require fixing up based on the actual runtime load offset. Note that on some ELF64 architectures [such as PPC64], these 32-bit values are still emitted as [absolute] runtime relocatable quantities, even if the value resolves to a build time constant. Since relative relocations are always resolved at build time, this patch enables MODULE_REL_CRCS on powerpc when CONFIG_RELOCATABLE=y, which turns the absolute CRC references into relative references into .rodata where the actual CRC value is stored. So redefine all CRC fields and variables as u32, and redefine the __CRC_SYMBOL() macro for 64 bit builds to emit the CRC reference using inline assembler (which is necessary since 64-bit C code cannot use 32-bit types to hold memory addresses, even if they are ultimately resolved using values that do not exceed 0xffffffff). To avoid potential problems with legacy 32-bit architectures using legacy toolchains, the equivalent C definition of the kcrctab entry is retained for 32-bit architectures. Note that this mostly reverts commit d4703ae ("module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y") Acked-by: Rusty Russell <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 5606781 commit 71810db

File tree

7 files changed

+53
-52
lines changed

7 files changed

+53
-52
lines changed

arch/powerpc/Kconfig

+1
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ config RELOCATABLE
484484
bool "Build a relocatable kernel"
485485
depends on (PPC64 && !COMPILE_TEST) || (FLATMEM && (44x || FSL_BOOKE))
486486
select NONSTATIC_KERNEL
487+
select MODULE_REL_CRCS if MODVERSIONS
487488
help
488489
This builds a kernel image that is capable of running at the
489490
location the kernel is loaded at. For ppc32, there is no any

arch/powerpc/include/asm/module.h

-4
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,5 @@ static inline int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sec
9090
}
9191
#endif
9292

93-
#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
94-
#define ARCH_RELOCATES_KCRCTAB
95-
#define reloc_start PHYSICAL_START
96-
#endif
9793
#endif /* __KERNEL__ */
9894
#endif /* _ASM_POWERPC_MODULE_H */

arch/powerpc/kernel/module_64.c

-8
Original file line numberDiff line numberDiff line change
@@ -286,14 +286,6 @@ static void dedotify_versions(struct modversion_info *vers,
286286
for (end = (void *)vers + size; vers < end; vers++)
287287
if (vers->name[0] == '.') {
288288
memmove(vers->name, vers->name+1, strlen(vers->name));
289-
#ifdef ARCH_RELOCATES_KCRCTAB
290-
/* The TOC symbol has no CRC computed. To avoid CRC
291-
* check failing, we must force it to the expected
292-
* value (see CRC check in module.c).
293-
*/
294-
if (!strcmp(vers->name, "TOC."))
295-
vers->crc = -(unsigned long)reloc_start;
296-
#endif
297289
}
298290
}
299291

include/asm-generic/export.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@
99
#ifndef KSYM_ALIGN
1010
#define KSYM_ALIGN 8
1111
#endif
12-
#ifndef KCRC_ALIGN
13-
#define KCRC_ALIGN 8
14-
#endif
1512
#else
1613
#define __put .long
1714
#ifndef KSYM_ALIGN
1815
#define KSYM_ALIGN 4
1916
#endif
17+
#endif
2018
#ifndef KCRC_ALIGN
2119
#define KCRC_ALIGN 4
2220
#endif
23-
#endif
2421

2522
#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
2623
#define KSYM(name) _##name
@@ -52,7 +49,11 @@ KSYM(__kstrtab_\name):
5249
.section ___kcrctab\sec+\name,"a"
5350
.balign KCRC_ALIGN
5451
KSYM(__kcrctab_\name):
55-
__put KSYM(__crc_\name)
52+
#if defined(CONFIG_MODULE_REL_CRCS)
53+
.long KSYM(__crc_\name) - .
54+
#else
55+
.long KSYM(__crc_\name)
56+
#endif
5657
.weak KSYM(__crc_\name)
5758
.previous
5859
#endif

include/linux/export.h

+14
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,27 @@ extern struct module __this_module;
4343
#ifdef CONFIG_MODVERSIONS
4444
/* Mark the CRC weak since genksyms apparently decides not to
4545
* generate a checksums for some symbols */
46+
#if defined(CONFIG_MODULE_REL_CRCS)
47+
#define __CRC_SYMBOL(sym, sec) \
48+
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
49+
" .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
50+
" .long " VMLINUX_SYMBOL_STR(__crc_##sym) " - . \n" \
51+
" .previous \n");
52+
#elif !defined(CONFIG_64BIT)
4653
#define __CRC_SYMBOL(sym, sec) \
4754
extern __visible void *__crc_##sym __attribute__((weak)); \
4855
static const unsigned long __kcrctab_##sym \
4956
__used \
5057
__attribute__((section("___kcrctab" sec "+" #sym), used)) \
5158
= (unsigned long) &__crc_##sym;
5259
#else
60+
#define __CRC_SYMBOL(sym, sec) \
61+
asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
62+
" .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
63+
" .long " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
64+
" .previous \n");
65+
#endif
66+
#else
5367
#define __CRC_SYMBOL(sym, sec)
5468
#endif
5569

include/linux/module.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ struct module {
346346

347347
/* Exported symbols */
348348
const struct kernel_symbol *syms;
349-
const unsigned long *crcs;
349+
const s32 *crcs;
350350
unsigned int num_syms;
351351

352352
/* Kernel parameters. */
@@ -359,18 +359,18 @@ struct module {
359359
/* GPL-only exported symbols. */
360360
unsigned int num_gpl_syms;
361361
const struct kernel_symbol *gpl_syms;
362-
const unsigned long *gpl_crcs;
362+
const s32 *gpl_crcs;
363363

364364
#ifdef CONFIG_UNUSED_SYMBOLS
365365
/* unused exported symbols. */
366366
const struct kernel_symbol *unused_syms;
367-
const unsigned long *unused_crcs;
367+
const s32 *unused_crcs;
368368
unsigned int num_unused_syms;
369369

370370
/* GPL-only, unused exported symbols. */
371371
unsigned int num_unused_gpl_syms;
372372
const struct kernel_symbol *unused_gpl_syms;
373-
const unsigned long *unused_gpl_crcs;
373+
const s32 *unused_gpl_crcs;
374374
#endif
375375

376376
#ifdef CONFIG_MODULE_SIG
@@ -382,7 +382,7 @@ struct module {
382382

383383
/* symbols that will be GPL-only in the near future. */
384384
const struct kernel_symbol *gpl_future_syms;
385-
const unsigned long *gpl_future_crcs;
385+
const s32 *gpl_future_crcs;
386386
unsigned int num_gpl_future_syms;
387387

388388
/* Exception table */
@@ -523,7 +523,7 @@ struct module *find_module(const char *name);
523523

524524
struct symsearch {
525525
const struct kernel_symbol *start, *stop;
526-
const unsigned long *crcs;
526+
const s32 *crcs;
527527
enum {
528528
NOT_GPL_ONLY,
529529
GPL_ONLY,
@@ -539,7 +539,7 @@ struct symsearch {
539539
*/
540540
const struct kernel_symbol *find_symbol(const char *name,
541541
struct module **owner,
542-
const unsigned long **crc,
542+
const s32 **crc,
543543
bool gplok,
544544
bool warn);
545545

kernel/module.c

+25-28
Original file line numberDiff line numberDiff line change
@@ -389,16 +389,16 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
389389
extern const struct kernel_symbol __stop___ksymtab_gpl[];
390390
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
391391
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
392-
extern const unsigned long __start___kcrctab[];
393-
extern const unsigned long __start___kcrctab_gpl[];
394-
extern const unsigned long __start___kcrctab_gpl_future[];
392+
extern const s32 __start___kcrctab[];
393+
extern const s32 __start___kcrctab_gpl[];
394+
extern const s32 __start___kcrctab_gpl_future[];
395395
#ifdef CONFIG_UNUSED_SYMBOLS
396396
extern const struct kernel_symbol __start___ksymtab_unused[];
397397
extern const struct kernel_symbol __stop___ksymtab_unused[];
398398
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
399399
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
400-
extern const unsigned long __start___kcrctab_unused[];
401-
extern const unsigned long __start___kcrctab_unused_gpl[];
400+
extern const s32 __start___kcrctab_unused[];
401+
extern const s32 __start___kcrctab_unused_gpl[];
402402
#endif
403403

404404
#ifndef CONFIG_MODVERSIONS
@@ -497,7 +497,7 @@ struct find_symbol_arg {
497497

498498
/* Output */
499499
struct module *owner;
500-
const unsigned long *crc;
500+
const s32 *crc;
501501
const struct kernel_symbol *sym;
502502
};
503503

@@ -563,7 +563,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,
563563
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
564564
const struct kernel_symbol *find_symbol(const char *name,
565565
struct module **owner,
566-
const unsigned long **crc,
566+
const s32 **crc,
567567
bool gplok,
568568
bool warn)
569569
{
@@ -1249,23 +1249,17 @@ static int try_to_force_load(struct module *mod, const char *reason)
12491249
}
12501250

12511251
#ifdef CONFIG_MODVERSIONS
1252-
/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
1253-
static unsigned long maybe_relocated(unsigned long crc,
1254-
const struct module *crc_owner)
1252+
1253+
static u32 resolve_rel_crc(const s32 *crc)
12551254
{
1256-
#ifdef ARCH_RELOCATES_KCRCTAB
1257-
if (crc_owner == NULL)
1258-
return crc - (unsigned long)reloc_start;
1259-
#endif
1260-
return crc;
1255+
return *(u32 *)((void *)crc + *crc);
12611256
}
12621257

12631258
static int check_version(Elf_Shdr *sechdrs,
12641259
unsigned int versindex,
12651260
const char *symname,
12661261
struct module *mod,
1267-
const unsigned long *crc,
1268-
const struct module *crc_owner)
1262+
const s32 *crc)
12691263
{
12701264
unsigned int i, num_versions;
12711265
struct modversion_info *versions;
@@ -1283,13 +1277,19 @@ static int check_version(Elf_Shdr *sechdrs,
12831277
/ sizeof(struct modversion_info);
12841278

12851279
for (i = 0; i < num_versions; i++) {
1280+
u32 crcval;
1281+
12861282
if (strcmp(versions[i].name, symname) != 0)
12871283
continue;
12881284

1289-
if (versions[i].crc == maybe_relocated(*crc, crc_owner))
1285+
if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
1286+
crcval = resolve_rel_crc(crc);
1287+
else
1288+
crcval = *crc;
1289+
if (versions[i].crc == crcval)
12901290
return 1;
1291-
pr_debug("Found checksum %lX vs module %lX\n",
1292-
maybe_relocated(*crc, crc_owner), versions[i].crc);
1291+
pr_debug("Found checksum %X vs module %lX\n",
1292+
crcval, versions[i].crc);
12931293
goto bad_version;
12941294
}
12951295

@@ -1307,7 +1307,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
13071307
unsigned int versindex,
13081308
struct module *mod)
13091309
{
1310-
const unsigned long *crc;
1310+
const s32 *crc;
13111311

13121312
/*
13131313
* 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,
13211321
}
13221322
preempt_enable();
13231323
return check_version(sechdrs, versindex,
1324-
VMLINUX_SYMBOL_STR(module_layout), mod, crc,
1325-
NULL);
1324+
VMLINUX_SYMBOL_STR(module_layout), mod, crc);
13261325
}
13271326

13281327
/* First part is kernel version, which we ignore if module has crcs. */
@@ -1340,8 +1339,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
13401339
unsigned int versindex,
13411340
const char *symname,
13421341
struct module *mod,
1343-
const unsigned long *crc,
1344-
const struct module *crc_owner)
1342+
const s32 *crc)
13451343
{
13461344
return 1;
13471345
}
@@ -1368,7 +1366,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
13681366
{
13691367
struct module *owner;
13701368
const struct kernel_symbol *sym;
1371-
const unsigned long *crc;
1369+
const s32 *crc;
13721370
int err;
13731371

13741372
/*
@@ -1383,8 +1381,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
13831381
if (!sym)
13841382
goto unlock;
13851383

1386-
if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
1387-
owner)) {
1384+
if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
13881385
sym = ERR_PTR(-EINVAL);
13891386
goto getname;
13901387
}

0 commit comments

Comments
 (0)