xref: /linux-6.15/kernel/module/version.c (revision 2ff49f89)
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