qubes-linux-kernel/patches.suse/supported-flag
2010-07-07 13:12:45 +02:00

344 lines
9.9 KiB
Plaintext

From: Andreas Gruenbacher <agruen@suse.de>
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 <agruen@suse.de>
---
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:
* 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>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);