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