1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Module version support
*
* Copyright (C) 2008 Rusty Russell
*/
#include <linux/module.h>
#include <linux/string.h>
#include <linux/printk.h>
#include "internal.h"
int check_version(const struct load_info *info,
const char *symname,
struct module *mod,
const u32 *crc)
{
Elf_Shdr *sechdrs = info->sechdrs;
unsigned int versindex = info->index.vers;
unsigned int i, num_versions;
struct modversion_info *versions;
struct modversion_info_ext version_ext;
/* Exporting module didn't supply crcs? OK, we're already tainted. */
if (!crc)
return 1;
/* If we have extended version info, rely on it */
if (info->index.vers_ext_crc) {
for_each_modversion_info_ext(version_ext, info) {
if (strcmp(version_ext.name, symname) != 0)
continue;
if (*version_ext.crc == *crc)
return 1;
pr_debug("Found checksum %X vs module %X\n",
*crc, *version_ext.crc);
goto bad_version;
}
pr_warn_once("%s: no extended symbol version for %s\n",
info->name, symname);
return 1;
}
/* No versions at all? modprobe --force does this. */
if (versindex == 0)
return try_to_force_load(mod, symname) == 0;
versions = (void *)sechdrs[versindex].sh_addr;
num_versions = sechdrs[versindex].sh_size
/ sizeof(struct modversion_info);
for (i = 0; i < num_versions; i++) {
u32 crcval;
if (strcmp(versions[i].name, symname) != 0)
continue;
crcval = *crc;
if (versions[i].crc == crcval)
return 1;
pr_debug("Found checksum %X vs module %lX\n",
crcval, versions[i].crc);
goto bad_version;
}
/* Broken toolchain. Warn once, then let it go.. */
pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
return 1;
bad_version:
pr_warn("%s: disagrees about version of symbol %s\n", info->name, symname);
return 0;
}
int check_modstruct_version(const struct load_info *info,
struct module *mod)
{
struct find_symbol_arg fsa = {
.name = "module_layout",
.gplok = true,
};
bool have_symbol;
/*
* Since this should be found in kernel (which can't be removed), no
* locking is necessary. Regardless use a RCU read section to keep
* lockdep happy.
*/
scoped_guard(rcu)
have_symbol = find_symbol(&fsa);
BUG_ON(!have_symbol);
return check_version(info, "module_layout", mod, fsa.crc);
}
/* First part is kernel version, which we ignore if module has crcs. */
int same_magic(const char *amagic, const char *bmagic,
bool has_crcs)
{
if (has_crcs) {
amagic += strcspn(amagic, " ");
bmagic += strcspn(bmagic, " ");
}
return strcmp(amagic, bmagic) == 0;
}
void modversion_ext_start(const struct load_info *info,
struct modversion_info_ext *start)
{
unsigned int crc_idx = info->index.vers_ext_crc;
unsigned int name_idx = info->index.vers_ext_name;
Elf_Shdr *sechdrs = info->sechdrs;
/*
* Both of these fields are needed for this to be useful
* Any future fields should be initialized to NULL if absent.
*/
if (crc_idx == 0 || name_idx == 0) {
start->remaining = 0;
return;
}
start->crc = (const u32 *)sechdrs[crc_idx].sh_addr;
start->name = (const char *)sechdrs[name_idx].sh_addr;
start->remaining = sechdrs[crc_idx].sh_size / sizeof(*start->crc);
}
void modversion_ext_advance(struct modversion_info_ext *vers)
{
vers->remaining--;
vers->crc++;
vers->name += strlen(vers->name) + 1;
}
/*
* Generate the signature for all relevant module structures here.
* If these change, we don't want to try to parse the module.
*/
void module_layout(struct module *mod,
struct modversion_info *ver,
struct kernel_param *kp,
struct kernel_symbol *ks,
struct tracepoint * const *tp)
{
}
EXPORT_SYMBOL(module_layout);
|