]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Andreas Gruenbacher <agruen@suse.de> |
2 | Subject: Novell/external support flag in modules | |
3 | ||
4 | Upon module load, check if a module is supported, and set the | |
5 | N (TAINT_NO_SUPPORT) or X (TAINT_EXTERNAL_SUPPORT) tail flags | |
6 | for unsupported or externally suported modules. | |
7 | ||
8 | Changes: | |
9 | * Feb 21 2008 - jeffm | |
10 | - 2.6.25 claimed -S and bumped the flags up a bit, modpost now uses -N | |
11 | ||
12 | Signed-off-by: Andreas Gruenbacher <agruen@suse.de> | |
13 | ||
14 | --- | |
15 | ||
16 | Documentation/kernel-parameters.txt | 6 +++ | |
17 | Documentation/sysctl/kernel.txt | 12 ++++++ | |
18 | Makefile | 5 ++ | |
19 | include/linux/kernel.h | 8 ++++ | |
20 | kernel/module.c | 41 ++++++++++++++++++++++ | |
21 | kernel/panic.c | 8 +++- | |
22 | kernel/sysctl.c | 10 +++++ | |
23 | scripts/Makefile.modpost | 4 +- | |
24 | scripts/mod/modpost.c | 65 +++++++++++++++++++++++++++++++++++- | |
25 | 9 files changed, 155 insertions(+), 4 deletions(-) | |
26 | ||
27 | --- a/Documentation/kernel-parameters.txt | |
28 | +++ b/Documentation/kernel-parameters.txt | |
29 | @@ -2113,6 +2113,12 @@ and is between 256 and 4096 characters. | |
30 | pernode one pool for each NUMA node (equivalent | |
31 | to global on non-NUMA machines) | |
32 | ||
33 | + unsupported Allow loading of unsupported kernel modules: | |
34 | + 0 = only allow supported modules, | |
35 | + 1 = warn when loading unsupported modules, | |
36 | + 2 = don't warn. | |
37 | + | |
38 | + | |
39 | swiotlb= [IA-64] Number of I/O TLB slabs | |
40 | ||
41 | switches= [HW,M68k] | |
42 | --- a/Documentation/sysctl/kernel.txt | |
43 | +++ b/Documentation/sysctl/kernel.txt | |
44 | @@ -369,4 +369,16 @@ can be ORed together: | |
45 | 2 - A module was force loaded by insmod -f. | |
46 | Set by modutils >= 2.4.9 and module-init-tools. | |
47 | 4 - Unsafe SMP processors: SMP with CPUs not designed for SMP. | |
48 | + 0x40000000 - An unsupported kernel module was loaded. | |
49 | + 0x80000000 - An kernel module with external support was loaded. | |
50 | + | |
51 | +============================================================== | |
52 | + | |
53 | +unsupported: | |
54 | + | |
55 | +Allow to load unsupported kernel modules: | |
56 | + | |
57 | + 0 - refuse to load unsupported modules, | |
58 | + 1 - warn when loading unsupported modules, | |
59 | + 2 - don't warn. | |
60 | ||
61 | --- a/Makefile | |
62 | +++ b/Makefile | |
63 | @@ -343,6 +343,11 @@ KBUILD_CFLAGS := -Wall -Wundef -Wstric | |
64 | -Werror-implicit-function-declaration | |
65 | KBUILD_AFLAGS := -D__ASSEMBLY__ | |
66 | ||
67 | +# Warn about unsupported modules in kernels built inside Autobuild | |
68 | +ifneq ($(wildcard /.buildenv),) | |
69 | +CFLAGS += -DUNSUPPORTED_MODULES=2 | |
70 | +endif | |
71 | + | |
72 | # Read KERNELRELEASE from include/config/kernel.release (if it exists) | |
73 | KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) | |
74 | KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) | |
75 | --- a/include/linux/kernel.h | |
76 | +++ b/include/linux/kernel.h | |
77 | @@ -236,6 +236,7 @@ extern int panic_timeout; | |
78 | extern int panic_on_oops; | |
79 | extern int panic_on_unrecovered_nmi; | |
80 | extern int tainted; | |
81 | +extern int unsupported; | |
82 | extern const char *print_tainted(void); | |
83 | extern void add_taint(unsigned); | |
84 | extern int root_mountflags; | |
85 | @@ -261,6 +262,13 @@ extern enum system_states { | |
86 | #define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8) | |
87 | #define TAINT_WARN (1<<9) | |
88 | ||
89 | +/* | |
90 | + * Take the upper bits to hopefully allow them | |
91 | + * to stay the same for more than one release. | |
92 | + */ | |
93 | +#define TAINT_NO_SUPPORT (1<<30) | |
94 | +#define TAINT_EXTERNAL_SUPPORT (1<<31) | |
95 | + | |
96 | extern void dump_stack(void) __cold; | |
97 | ||
98 | enum { | |
99 | --- a/kernel/module.c | |
100 | +++ b/kernel/module.c | |
101 | @@ -60,6 +60,20 @@ | |
102 | /* If this is set, the section belongs in the init part of the module */ | |
103 | #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) | |
104 | ||
105 | +/* Allow unsupported modules switch. */ | |
106 | +#ifdef UNSUPPORTED_MODULES | |
107 | +int unsupported = UNSUPPORTED_MODULES; | |
108 | +#else | |
109 | +int unsupported = 2; /* don't warn when loading unsupported modules. */ | |
110 | +#endif | |
111 | + | |
112 | +static int __init unsupported_setup(char *str) | |
113 | +{ | |
114 | + get_option(&str, &unsupported); | |
115 | + return 1; | |
116 | +} | |
117 | +__setup("unsupported=", unsupported_setup); | |
118 | + | |
119 | /* List of modules, protected by module_mutex or preempt_disable | |
120 | * (add/delete uses stop_machine). */ | |
121 | static DEFINE_MUTEX(module_mutex); | |
122 | @@ -1806,6 +1820,7 @@ static noinline struct module *load_modu | |
123 | Elf_Ehdr *hdr; | |
124 | Elf_Shdr *sechdrs; | |
125 | char *secstrings, *args, *modmagic, *strtab = NULL; | |
126 | + char *supported; | |
127 | unsigned int i; | |
128 | unsigned int symindex = 0; | |
129 | unsigned int strindex = 0; | |
130 | @@ -1960,6 +1975,28 @@ static noinline struct module *load_modu | |
131 | goto free_hdr; | |
132 | } | |
133 | ||
134 | + supported = get_modinfo(sechdrs, infoindex, "supported"); | |
135 | + if (supported) { | |
136 | + if (!strcmp(supported, "external")) | |
137 | + add_taint_module(mod, TAINT_EXTERNAL_SUPPORT); | |
138 | + else if (strcmp(supported, "yes")) | |
139 | + supported = NULL; | |
140 | + } | |
141 | + if (!supported) { | |
142 | + if (unsupported == 0) { | |
143 | + printk(KERN_WARNING "%s: module not supported by " | |
144 | + "Novell, refusing to load. To override, echo " | |
145 | + "1 > /proc/sys/kernel/unsupported\n", mod->name); | |
146 | + err = -ENOEXEC; | |
147 | + goto free_hdr; | |
148 | + } | |
149 | + add_taint_module(mod, TAINT_NO_SUPPORT); | |
150 | + if (unsupported == 1) { | |
151 | + printk(KERN_WARNING "%s: module not supported by " | |
152 | + "Novell, setting U taint flag.\n", mod->name); | |
153 | + } | |
154 | + } | |
155 | + | |
156 | /* Now copy in args */ | |
157 | args = strndup_user(uargs, ~0UL >> 1); | |
158 | if (IS_ERR(args)) { | |
159 | @@ -2554,6 +2591,10 @@ static char *module_flags(struct module | |
160 | buf[bx++] = 'P'; | |
161 | if (mod->taints & TAINT_FORCED_MODULE) | |
162 | buf[bx++] = 'F'; | |
163 | + if (mod->taints & TAINT_NO_SUPPORT) | |
164 | + buf[bx++] = 'N'; | |
165 | + if (mod->taints & TAINT_EXTERNAL_SUPPORT) | |
166 | + buf[bx++] = 'X'; | |
167 | /* | |
168 | * TAINT_FORCED_RMMOD: could be added. | |
169 | * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't | |
170 | --- a/kernel/panic.c | |
171 | +++ b/kernel/panic.c | |
172 | @@ -155,6 +155,8 @@ EXPORT_SYMBOL(panic); | |
173 | * 'U' - Userspace-defined naughtiness. | |
174 | * 'A' - ACPI table overridden. | |
175 | * 'W' - Taint on warning. | |
176 | + * 'N' - Unsuported modules loaded. | |
177 | + * 'X' - Modules with external support loaded. | |
178 | * | |
179 | * The string is overwritten by the next call to print_taint(). | |
180 | */ | |
181 | @@ -163,7 +165,7 @@ const char *print_tainted(void) | |
182 | { | |
183 | static char buf[20]; | |
184 | if (tainted) { | |
185 | - snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c", | |
186 | + snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c%c%c", | |
187 | tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', | |
188 | tainted & TAINT_FORCED_MODULE ? 'F' : ' ', | |
189 | tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', | |
190 | @@ -173,7 +175,9 @@ const char *print_tainted(void) | |
191 | tainted & TAINT_USER ? 'U' : ' ', | |
192 | tainted & TAINT_DIE ? 'D' : ' ', | |
193 | tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ', | |
194 | - tainted & TAINT_WARN ? 'W' : ' '); | |
195 | + tainted & TAINT_WARN ? 'W' : ' ', | |
196 | + tainted & TAINT_NO_SUPPORT ? 'N' : ' ', | |
197 | + tainted & TAINT_EXTERNAL_SUPPORT ? 'X' : ' '); | |
198 | } | |
199 | else | |
200 | snprintf(buf, sizeof(buf), "Not tainted"); | |
201 | --- a/kernel/sysctl.c | |
202 | +++ b/kernel/sysctl.c | |
203 | @@ -550,6 +550,16 @@ static struct ctl_table kern_table[] = { | |
204 | .mode = 0644, | |
205 | .proc_handler = &proc_dointvec, | |
206 | }, | |
207 | +#ifdef CONFIG_MODULES | |
208 | + { | |
209 | + .ctl_name = CTL_UNNUMBERED, | |
210 | + .procname = "unsupported", | |
211 | + .data = &unsupported, | |
212 | + .maxlen = sizeof(int), | |
213 | + .mode = 0644, | |
214 | + .proc_handler = &proc_dointvec, | |
215 | + }, | |
216 | +#endif | |
217 | { | |
218 | .ctl_name = KERN_RANDOM, | |
219 | .procname = "random", | |
220 | --- a/scripts/Makefile.modpost | |
221 | +++ b/scripts/Makefile.modpost | |
222 | @@ -88,7 +88,9 @@ modpost = scripts/mod/modpost | |
223 | $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \ | |
224 | $(if $(CONFIG_MARKERS),-M $(markersfile)) \ | |
225 | $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ | |
226 | - $(if $(cross_build),-c) | |
227 | + $(if $(cross_build),-c) \ | |
228 | + -N $(firstword $(wildcard $(dir $(MODVERDIR))/Module.supported \ | |
229 | + $(objtree)/Module.supported /dev/null)) | |
230 | ||
231 | quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules | |
232 | cmd_modpost = $(modpost) -s | |
233 | --- a/scripts/mod/modpost.c | |
234 | +++ b/scripts/mod/modpost.c | |
235 | @@ -1545,6 +1545,48 @@ static void get_markers(struct elf_info | |
236 | } | |
237 | } | |
238 | ||
239 | +void *supported_file; | |
240 | +unsigned long supported_size; | |
241 | + | |
242 | +const char *supported(struct module *mod) | |
243 | +{ | |
244 | + unsigned long pos = 0; | |
245 | + char *line; | |
246 | + | |
247 | + /* In a first shot, do a simple linear scan. */ | |
248 | + while ((line = get_next_line(&pos, supported_file, | |
249 | + supported_size))) { | |
250 | + const char *basename, *how = "yes"; | |
251 | + char *l = line; | |
252 | + | |
253 | + /* optional type-of-support flag */ | |
254 | + for (l = line; *l != '\0'; l++) { | |
255 | + if (*l == ' ' || *l == '\t') { | |
256 | + *l = '\0'; | |
257 | + how = l + 1; | |
258 | + break; | |
259 | + } | |
260 | + } | |
261 | + | |
262 | + /* skip directory components */ | |
263 | + if ((l = strrchr(line, '/'))) | |
264 | + line = l + 1; | |
265 | + /* strip .ko extension */ | |
266 | + l = line + strlen(line); | |
267 | + if (l - line > 3 && !strcmp(l-3, ".ko")) | |
268 | + *(l-3) = '\0'; | |
269 | + | |
270 | + /* skip directory components */ | |
271 | + if ((basename = strrchr(mod->name, '/'))) | |
272 | + basename++; | |
273 | + else | |
274 | + basename = mod->name; | |
275 | + if (!strcmp(basename, line)) | |
276 | + return how; | |
277 | + } | |
278 | + return NULL; | |
279 | +} | |
280 | + | |
281 | static void read_symbols(char *modname) | |
282 | { | |
283 | const char *symname; | |
284 | @@ -1726,6 +1768,13 @@ static void add_header(struct buffer *b, | |
285 | buf_printf(b, "};\n"); | |
286 | } | |
287 | ||
288 | +void add_supported_flag(struct buffer *b, struct module *mod) | |
289 | +{ | |
290 | + const char *how = supported(mod); | |
291 | + if (how) | |
292 | + buf_printf(b, "\nMODULE_INFO(supported, \"%s\");\n", how); | |
293 | +} | |
294 | + | |
295 | /** | |
296 | * Record CRCs for unresolved symbols | |
297 | **/ | |
298 | @@ -1866,6 +1915,13 @@ static void write_if_changed(struct buff | |
299 | fclose(file); | |
300 | } | |
301 | ||
302 | +void read_supported(const char *fname) | |
303 | +{ | |
304 | + supported_file = grab_file(fname, &supported_size); | |
305 | + if (!supported_file) | |
306 | + ; /* ignore error */ | |
307 | +} | |
308 | + | |
309 | /* parse Module.symvers file. line format: | |
310 | * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] | |
311 | **/ | |
312 | @@ -2051,12 +2107,13 @@ int main(int argc, char **argv) | |
313 | char *dump_write = NULL; | |
314 | char *markers_read = NULL; | |
315 | char *markers_write = NULL; | |
316 | + const char *supported = NULL; | |
317 | int opt; | |
318 | int err; | |
319 | struct ext_sym_list *extsym_iter; | |
320 | struct ext_sym_list *extsym_start = NULL; | |
321 | ||
322 | - while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) { | |
323 | + while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:N:")) != -1) { | |
324 | switch (opt) { | |
325 | case 'i': | |
326 | kernel_read = optarg; | |
327 | @@ -2100,11 +2157,16 @@ int main(int argc, char **argv) | |
328 | case 'K': | |
329 | markers_read = optarg; | |
330 | break; | |
331 | + case 'N': | |
332 | + supported = optarg; | |
333 | + break; | |
334 | default: | |
335 | exit(1); | |
336 | } | |
337 | } | |
338 | ||
339 | + if (supported) | |
340 | + read_supported(supported); | |
341 | if (kernel_read) | |
342 | read_dump(kernel_read, 1); | |
343 | if (module_read) | |
344 | @@ -2136,6 +2198,7 @@ int main(int argc, char **argv) | |
345 | buf.pos = 0; | |
346 | ||
347 | add_header(&buf, mod); | |
348 | + add_supported_flag(&buf, mod); | |
349 | err |= add_versions(&buf, mod); | |
350 | add_depends(&buf, mod, modules); | |
351 | add_moddevtable(&buf, mod); |