From: Andreas Gruenbacher Subject: Novell/external support flag in modules Patch-mainline: Never, SLES feature Upon module load, check if a module is supported, and set the N (TAINT_NO_SUPPORT) or X (TAINT_EXTERNAL_SUPPORT) tail flags for unsupported or externally suported modules. Changes: * Feb 21 2008 - jeffm - 2.6.25 claimed -S and bumped the flags up a bit, modpost now uses -N Signed-off-by: Andreas Gruenbacher --- Documentation/kernel-parameters.txt | 6 +++ Documentation/sysctl/kernel.txt | 12 ++++++ Makefile | 5 ++ include/linux/kernel.h | 8 ++++ kernel/module.c | 42 ++++++++++++++++++++++- kernel/panic.c | 4 ++ kernel/sysctl.c | 9 ++++ scripts/Makefile.modpost | 4 +- scripts/mod/modpost.c | 65 +++++++++++++++++++++++++++++++++++- 9 files changed, 152 insertions(+), 3 deletions(-) --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2549,6 +2549,12 @@ and is between 256 and 4096 characters. improve throughput, but will also increase the amount of memory reserved for use by the client. + unsupported Allow loading of unsupported kernel modules: + 0 = only allow supported modules, + 1 = warn when loading unsupported modules, + 2 = don't warn. + + swiotlb= [IA-64] Number of I/O TLB slabs switches= [HW,M68k] --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -477,6 +477,18 @@ can be ORed together: instead of using the one provided by the hardware. 512 - A kernel warning has occurred. 1024 - A module from drivers/staging was loaded. + 0x40000000 - An unsupported kernel module was loaded. + 0x80000000 - An kernel module with external support was loaded. + +============================================================== + +unsupported: + +Allow to load unsupported kernel modules: + + 0 - refuse to load unsupported modules, + 1 - warn when loading unsupported modules, + 2 - don't warn. ============================================================== --- a/Makefile +++ b/Makefile @@ -353,6 +353,11 @@ KBUILD_CFLAGS := -Wall -Wundef -Wstric -fno-delete-null-pointer-checks KBUILD_AFLAGS := -D__ASSEMBLY__ +# Warn about unsupported modules in kernels built inside Autobuild +ifneq ($(wildcard /.buildenv),) +CFLAGS += -DUNSUPPORTED_MODULES=2 +endif + # Read KERNELRELEASE from include/config/kernel.release (if it exists) KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -317,6 +317,7 @@ extern int panic_timeout; extern int panic_on_oops; extern int panic_on_unrecovered_nmi; extern int panic_on_io_nmi; +extern int unsupported; extern const char *print_tainted(void); extern void add_taint(unsigned flag); extern int test_taint(unsigned flag); @@ -345,6 +346,13 @@ extern enum system_states { #define TAINT_WARN 9 #define TAINT_CRAP 10 +/* + * Take the upper bits to hopefully allow them + * to stay the same for more than one release. + */ +#define TAINT_NO_SUPPORT 30 +#define TAINT_EXTERNAL_SUPPORT 31 + extern void dump_stack(void) __cold; enum { --- a/kernel/module.c +++ b/kernel/module.c @@ -74,6 +74,20 @@ EXPORT_TRACEPOINT_SYMBOL(module_get); /* If this is set, the section belongs in the init part of the module */ #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) +/* Allow unsupported modules switch. */ +#ifdef UNSUPPORTED_MODULES +int unsupported = UNSUPPORTED_MODULES; +#else +int unsupported = 2; /* don't warn when loading unsupported modules. */ +#endif + +static int __init unsupported_setup(char *str) +{ + get_option(&str, &unsupported); + return 1; +} +__setup("unsupported=", unsupported_setup); + /* List of modules, protected by module_mutex or preempt_disable * (delete uses stop_machine/add uses RCU list operations). */ DEFINE_MUTEX(module_mutex); @@ -1947,7 +1961,7 @@ static noinline struct module *load_modu Elf_Ehdr *hdr; Elf_Shdr *sechdrs; char *secstrings, *args, *modmagic, *strtab = NULL; - char *staging; + char *staging, *supported; unsigned int i; unsigned int symindex = 0; unsigned int strindex = 0; @@ -2066,6 +2080,28 @@ static noinline struct module *load_modu mod->name); } + supported = get_modinfo(sechdrs, infoindex, "supported"); + if (supported) { + if (!strcmp(supported, "external")) + add_taint_module(mod, TAINT_EXTERNAL_SUPPORT); + else if (strcmp(supported, "yes")) + supported = NULL; + } + if (!supported) { + if (unsupported == 0) { + printk(KERN_WARNING "%s: module not supported by " + "Novell, refusing to load. To override, echo " + "1 > /proc/sys/kernel/unsupported\n", mod->name); + err = -ENOEXEC; + goto free_hdr; + } + add_taint_module(mod, TAINT_NO_SUPPORT); + if (unsupported == 1) { + printk(KERN_WARNING "%s: module not supported by " + "Novell, setting U taint flag.\n", mod->name); + } + } + /* Now copy in args */ args = strndup_user(uargs, ~0UL >> 1); if (IS_ERR(args)) { @@ -2748,6 +2784,10 @@ static char *module_flags(struct module buf[bx++] = 'F'; if (mod->taints & (1 << TAINT_CRAP)) buf[bx++] = 'C'; + if (mod->taints & (1 << TAINT_NO_SUPPORT)) + buf[bx++] = 'N'; + if (mod->taints & (1 << TAINT_EXTERNAL_SUPPORT)) + buf[bx++] = 'X'; /* * TAINT_FORCED_RMMOD: could be added. * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't --- a/kernel/panic.c +++ b/kernel/panic.c @@ -178,6 +178,8 @@ static const struct tnt tnts[] = { { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' }, { TAINT_WARN, 'W', ' ' }, { TAINT_CRAP, 'C', ' ' }, + { TAINT_NO_SUPPORT, 'N', ' ' }, + { TAINT_EXTERNAL_SUPPORT, 'X', ' ' }, }; /** @@ -194,6 +196,8 @@ static const struct tnt tnts[] = { * 'A' - ACPI table overridden. * 'W' - Taint on warning. * 'C' - modules from drivers/staging are loaded. + * 'N' - Unsuported modules loaded. + * 'X' - Modules with external support loaded. * * The string is overwritten by the next call to print_tainted(). */ --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -636,6 +636,15 @@ static struct ctl_table kern_table[] = { .extra1 = &pid_max_min, .extra2 = &pid_max_max, }, +#ifdef CONFIG_MODULES + { + .procname = "unsupported", + .data = &unsupported, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif { .procname = "panic_on_oops", .data = &panic_on_oops, --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -81,7 +81,9 @@ modpost = scripts/mod/modpost $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ - $(if $(cross_build),-c) + $(if $(cross_build),-c) \ + -N $(firstword $(wildcard $(dir $(MODVERDIR))/Module.supported \ + $(objtree)/Module.supported /dev/null)) quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules cmd_modpost = $(modpost) -s --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1516,6 +1516,48 @@ static void check_sec_ref(struct module } } +void *supported_file; +unsigned long supported_size; + +static const char *supported(struct module *mod) +{ + unsigned long pos = 0; + char *line; + + /* In a first shot, do a simple linear scan. */ + while ((line = get_next_line(&pos, supported_file, + supported_size))) { + const char *basename, *how = "yes"; + char *l = line; + + /* optional type-of-support flag */ + for (l = line; *l != '\0'; l++) { + if (*l == ' ' || *l == '\t') { + *l = '\0'; + how = l + 1; + break; + } + } + + /* skip directory components */ + if ((l = strrchr(line, '/'))) + line = l + 1; + /* strip .ko extension */ + l = line + strlen(line); + if (l - line > 3 && !strcmp(l-3, ".ko")) + *(l-3) = '\0'; + + /* skip directory components */ + if ((basename = strrchr(mod->name, '/'))) + basename++; + else + basename = mod->name; + if (!strcmp(basename, line)) + return how; + } + return NULL; +} + static void read_symbols(char *modname) { const char *symname; @@ -1703,6 +1745,13 @@ static void add_staging_flag(struct buff buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); } +static void add_supported_flag(struct buffer *b, struct module *mod) +{ + const char *how = supported(mod); + if (how) + buf_printf(b, "\nMODULE_INFO(supported, \"%s\");\n", how); +} + /** * Record CRCs for unresolved symbols **/ @@ -1843,6 +1892,13 @@ static void write_if_changed(struct buff fclose(file); } +static void read_supported(const char *fname) +{ + supported_file = grab_file(fname, &supported_size); + if (!supported_file) + ; /* ignore error */ +} + /* parse Module.symvers file. line format: * 0x12345678symbolmodule[[export]something] **/ @@ -1936,12 +1992,13 @@ int main(int argc, char **argv) struct buffer buf = { }; char *kernel_read = NULL, *module_read = NULL; char *dump_write = NULL; + const char *supported = NULL; int opt; int err; struct ext_sym_list *extsym_iter; struct ext_sym_list *extsym_start = NULL; - while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) { + while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:N:")) != -1) { switch (opt) { case 'i': kernel_read = optarg; @@ -1979,11 +2036,16 @@ int main(int argc, char **argv) case 'w': warn_unresolved = 1; break; + case 'N': + supported = optarg; + break; default: exit(1); } } + if (supported) + read_supported(supported); if (kernel_read) read_dump(kernel_read, 1); if (module_read) @@ -2016,6 +2078,7 @@ int main(int argc, char **argv) add_header(&buf, mod); add_staging_flag(&buf, mod->name); + add_supported_flag(&buf, mod); err |= add_versions(&buf, mod); add_depends(&buf, mod, modules); add_moddevtable(&buf, mod);