xref: /linux-6.15/kernel/module/version.c (revision 47889798)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Module version support
4  *
5  * Copyright (C) 2008 Rusty Russell
6  */
7 
8 #include <linux/module.h>
9 #include <linux/string.h>
10 #include <linux/printk.h>
11 #include "internal.h"
12 
13 static u32 resolve_rel_crc(const s32 *crc)
14 {
15 	return *(u32 *)((void *)crc + *crc);
16 }
17 
18 int check_version(const struct load_info *info,
19 		  const char *symname,
20 			 struct module *mod,
21 			 const s32 *crc)
22 {
23 	Elf_Shdr *sechdrs = info->sechdrs;
24 	unsigned int versindex = info->index.vers;
25 	unsigned int i, num_versions;
26 	struct modversion_info *versions;
27 
28 	/* Exporting module didn't supply crcs?  OK, we're already tainted. */
29 	if (!crc)
30 		return 1;
31 
32 	/* No versions at all?  modprobe --force does this. */
33 	if (versindex == 0)
34 		return try_to_force_load(mod, symname) == 0;
35 
36 	versions = (void *)sechdrs[versindex].sh_addr;
37 	num_versions = sechdrs[versindex].sh_size
38 		/ sizeof(struct modversion_info);
39 
40 	for (i = 0; i < num_versions; i++) {
41 		u32 crcval;
42 
43 		if (strcmp(versions[i].name, symname) != 0)
44 			continue;
45 
46 		if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
47 			crcval = resolve_rel_crc(crc);
48 		else
49 			crcval = *crc;
50 		if (versions[i].crc == crcval)
51 			return 1;
52 		pr_debug("Found checksum %X vs module %lX\n",
53 			 crcval, versions[i].crc);
54 		goto bad_version;
55 	}
56 
57 	/* Broken toolchain. Warn once, then let it go.. */
58 	pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
59 	return 1;
60 
61 bad_version:
62 	pr_warn("%s: disagrees about version of symbol %s\n", info->name, symname);
63 	return 0;
64 }
65 
66 int check_modstruct_version(const struct load_info *info,
67 			    struct module *mod)
68 {
69 	struct find_symbol_arg fsa = {
70 		.name	= "module_layout",
71 		.gplok	= true,
72 	};
73 
74 	/*
75 	 * Since this should be found in kernel (which can't be removed), no
76 	 * locking is necessary -- use preempt_disable() to placate lockdep.
77 	 */
78 	preempt_disable();
79 	if (!find_symbol(&fsa)) {
80 		preempt_enable();
81 		BUG();
82 	}
83 	preempt_enable();
84 	return check_version(info, "module_layout", mod, fsa.crc);
85 }
86 
87 /* First part is kernel version, which we ignore if module has crcs. */
88 int same_magic(const char *amagic, const char *bmagic,
89 	       bool has_crcs)
90 {
91 	if (has_crcs) {
92 		amagic += strcspn(amagic, " ");
93 		bmagic += strcspn(bmagic, " ");
94 	}
95 	return strcmp(amagic, bmagic) == 0;
96 }
97 
98 /*
99  * Generate the signature for all relevant module structures here.
100  * If these change, we don't want to try to parse the module.
101  */
102 void module_layout(struct module *mod,
103 		   struct modversion_info *ver,
104 		   struct kernel_param *kp,
105 		   struct kernel_symbol *ks,
106 		   struct tracepoint * const *tp)
107 {
108 }
109 EXPORT_SYMBOL(module_layout);
110