147889798SAaron Tomlin // SPDX-License-Identifier: GPL-2.0-or-later
247889798SAaron Tomlin /*
347889798SAaron Tomlin * Module version support
447889798SAaron Tomlin *
547889798SAaron Tomlin * Copyright (C) 2008 Rusty Russell
647889798SAaron Tomlin */
747889798SAaron Tomlin
847889798SAaron Tomlin #include <linux/module.h>
947889798SAaron Tomlin #include <linux/string.h>
1047889798SAaron Tomlin #include <linux/printk.h>
1147889798SAaron Tomlin #include "internal.h"
1247889798SAaron Tomlin
check_version(const struct load_info * info,const char * symname,struct module * mod,const u32 * crc)1347889798SAaron Tomlin int check_version(const struct load_info *info,
1447889798SAaron Tomlin const char *symname,
1547889798SAaron Tomlin struct module *mod,
161cd9502eSMasahiro Yamada const u32 *crc)
1747889798SAaron Tomlin {
1847889798SAaron Tomlin Elf_Shdr *sechdrs = info->sechdrs;
1947889798SAaron Tomlin unsigned int versindex = info->index.vers;
2047889798SAaron Tomlin unsigned int i, num_versions;
2147889798SAaron Tomlin struct modversion_info *versions;
2254ac1ac8SMatthew Maurer struct modversion_info_ext version_ext;
2347889798SAaron Tomlin
2447889798SAaron Tomlin /* Exporting module didn't supply crcs? OK, we're already tainted. */
2547889798SAaron Tomlin if (!crc)
2647889798SAaron Tomlin return 1;
2747889798SAaron Tomlin
2854ac1ac8SMatthew Maurer /* If we have extended version info, rely on it */
2954ac1ac8SMatthew Maurer if (info->index.vers_ext_crc) {
3054ac1ac8SMatthew Maurer for_each_modversion_info_ext(version_ext, info) {
3154ac1ac8SMatthew Maurer if (strcmp(version_ext.name, symname) != 0)
3254ac1ac8SMatthew Maurer continue;
3354ac1ac8SMatthew Maurer if (*version_ext.crc == *crc)
3454ac1ac8SMatthew Maurer return 1;
3554ac1ac8SMatthew Maurer pr_debug("Found checksum %X vs module %X\n",
3654ac1ac8SMatthew Maurer *crc, *version_ext.crc);
3754ac1ac8SMatthew Maurer goto bad_version;
3854ac1ac8SMatthew Maurer }
3954ac1ac8SMatthew Maurer pr_warn_once("%s: no extended symbol version for %s\n",
4054ac1ac8SMatthew Maurer info->name, symname);
4154ac1ac8SMatthew Maurer return 1;
4254ac1ac8SMatthew Maurer }
4354ac1ac8SMatthew Maurer
4447889798SAaron Tomlin /* No versions at all? modprobe --force does this. */
4547889798SAaron Tomlin if (versindex == 0)
4647889798SAaron Tomlin return try_to_force_load(mod, symname) == 0;
4747889798SAaron Tomlin
4847889798SAaron Tomlin versions = (void *)sechdrs[versindex].sh_addr;
4947889798SAaron Tomlin num_versions = sechdrs[versindex].sh_size
5047889798SAaron Tomlin / sizeof(struct modversion_info);
5147889798SAaron Tomlin
5247889798SAaron Tomlin for (i = 0; i < num_versions; i++) {
5347889798SAaron Tomlin u32 crcval;
5447889798SAaron Tomlin
5547889798SAaron Tomlin if (strcmp(versions[i].name, symname) != 0)
5647889798SAaron Tomlin continue;
5747889798SAaron Tomlin
5847889798SAaron Tomlin crcval = *crc;
5947889798SAaron Tomlin if (versions[i].crc == crcval)
6047889798SAaron Tomlin return 1;
6147889798SAaron Tomlin pr_debug("Found checksum %X vs module %lX\n",
6247889798SAaron Tomlin crcval, versions[i].crc);
6347889798SAaron Tomlin goto bad_version;
6447889798SAaron Tomlin }
6547889798SAaron Tomlin
6647889798SAaron Tomlin /* Broken toolchain. Warn once, then let it go.. */
6747889798SAaron Tomlin pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
6847889798SAaron Tomlin return 1;
6947889798SAaron Tomlin
7047889798SAaron Tomlin bad_version:
7147889798SAaron Tomlin pr_warn("%s: disagrees about version of symbol %s\n", info->name, symname);
7247889798SAaron Tomlin return 0;
7347889798SAaron Tomlin }
7447889798SAaron Tomlin
check_modstruct_version(const struct load_info * info,struct module * mod)7547889798SAaron Tomlin int check_modstruct_version(const struct load_info *info,
7647889798SAaron Tomlin struct module *mod)
7747889798SAaron Tomlin {
7847889798SAaron Tomlin struct find_symbol_arg fsa = {
7947889798SAaron Tomlin .name = "module_layout",
8047889798SAaron Tomlin .gplok = true,
8147889798SAaron Tomlin };
82*2ff49f89SSebastian Andrzej Siewior bool have_symbol;
8347889798SAaron Tomlin
8447889798SAaron Tomlin /*
8547889798SAaron Tomlin * Since this should be found in kernel (which can't be removed), no
86*2ff49f89SSebastian Andrzej Siewior * locking is necessary. Regardless use a RCU read section to keep
87*2ff49f89SSebastian Andrzej Siewior * lockdep happy.
8847889798SAaron Tomlin */
89*2ff49f89SSebastian Andrzej Siewior scoped_guard(rcu)
90*2ff49f89SSebastian Andrzej Siewior have_symbol = find_symbol(&fsa);
91*2ff49f89SSebastian Andrzej Siewior BUG_ON(!have_symbol);
92*2ff49f89SSebastian Andrzej Siewior
9347889798SAaron Tomlin return check_version(info, "module_layout", mod, fsa.crc);
9447889798SAaron Tomlin }
9547889798SAaron Tomlin
9647889798SAaron Tomlin /* First part is kernel version, which we ignore if module has crcs. */
same_magic(const char * amagic,const char * bmagic,bool has_crcs)9747889798SAaron Tomlin int same_magic(const char *amagic, const char *bmagic,
9847889798SAaron Tomlin bool has_crcs)
9947889798SAaron Tomlin {
10047889798SAaron Tomlin if (has_crcs) {
10147889798SAaron Tomlin amagic += strcspn(amagic, " ");
10247889798SAaron Tomlin bmagic += strcspn(bmagic, " ");
10347889798SAaron Tomlin }
10447889798SAaron Tomlin return strcmp(amagic, bmagic) == 0;
10547889798SAaron Tomlin }
10647889798SAaron Tomlin
modversion_ext_start(const struct load_info * info,struct modversion_info_ext * start)10754ac1ac8SMatthew Maurer void modversion_ext_start(const struct load_info *info,
10854ac1ac8SMatthew Maurer struct modversion_info_ext *start)
10954ac1ac8SMatthew Maurer {
11054ac1ac8SMatthew Maurer unsigned int crc_idx = info->index.vers_ext_crc;
11154ac1ac8SMatthew Maurer unsigned int name_idx = info->index.vers_ext_name;
11254ac1ac8SMatthew Maurer Elf_Shdr *sechdrs = info->sechdrs;
11354ac1ac8SMatthew Maurer
11454ac1ac8SMatthew Maurer /*
11554ac1ac8SMatthew Maurer * Both of these fields are needed for this to be useful
11654ac1ac8SMatthew Maurer * Any future fields should be initialized to NULL if absent.
11754ac1ac8SMatthew Maurer */
11854ac1ac8SMatthew Maurer if (crc_idx == 0 || name_idx == 0) {
11954ac1ac8SMatthew Maurer start->remaining = 0;
12054ac1ac8SMatthew Maurer return;
12154ac1ac8SMatthew Maurer }
12254ac1ac8SMatthew Maurer
12354ac1ac8SMatthew Maurer start->crc = (const u32 *)sechdrs[crc_idx].sh_addr;
12454ac1ac8SMatthew Maurer start->name = (const char *)sechdrs[name_idx].sh_addr;
12554ac1ac8SMatthew Maurer start->remaining = sechdrs[crc_idx].sh_size / sizeof(*start->crc);
12654ac1ac8SMatthew Maurer }
12754ac1ac8SMatthew Maurer
modversion_ext_advance(struct modversion_info_ext * vers)12854ac1ac8SMatthew Maurer void modversion_ext_advance(struct modversion_info_ext *vers)
12954ac1ac8SMatthew Maurer {
13054ac1ac8SMatthew Maurer vers->remaining--;
13154ac1ac8SMatthew Maurer vers->crc++;
13254ac1ac8SMatthew Maurer vers->name += strlen(vers->name) + 1;
13354ac1ac8SMatthew Maurer }
13454ac1ac8SMatthew Maurer
13547889798SAaron Tomlin /*
13647889798SAaron Tomlin * Generate the signature for all relevant module structures here.
13747889798SAaron Tomlin * If these change, we don't want to try to parse the module.
13847889798SAaron Tomlin */
module_layout(struct module * mod,struct modversion_info * ver,struct kernel_param * kp,struct kernel_symbol * ks,struct tracepoint * const * tp)13947889798SAaron Tomlin void module_layout(struct module *mod,
14047889798SAaron Tomlin struct modversion_info *ver,
14147889798SAaron Tomlin struct kernel_param *kp,
14247889798SAaron Tomlin struct kernel_symbol *ks,
14347889798SAaron Tomlin struct tracepoint * const *tp)
14447889798SAaron Tomlin {
14547889798SAaron Tomlin }
14647889798SAaron Tomlin EXPORT_SYMBOL(module_layout);
147