aboutsummaryrefslogtreecommitdiffstats
path: root/ns
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2008-06-30 10:51:47 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2008-06-30 10:51:47 -0700
commit33f43d082d6ea41c8c90e3b64f99b1b072180fad (patch)
treebc5fb96519ba37d0c928ed2b5a6b9133719c743c /ns
parentaf94d897d09cf05550c2a4caabcad68a51534005 (diff)
downloadpatches-33f43d082d6ea41c8c90e3b64f99b1b072180fad.tar.gz
move some files around
Diffstat (limited to 'ns')
-rw-r--r--ns/modpost590
-rw-r--r--ns/module-usb-serial.patch23
-rw-r--r--ns/namespace237
-rw-r--r--ns/namespace_module.c253
-rw-r--r--ns/ns-debug45
5 files changed, 1148 insertions, 0 deletions
diff --git a/ns/modpost b/ns/modpost
new file mode 100644
index 00000000000000..99a819532268bb
--- /dev/null
+++ b/ns/modpost
@@ -0,0 +1,590 @@
+Implement namespace checking in modpost
+
+This checks the namespaces at build time in modpost
+
+---
+ scripts/mod/modpost.c | 360 +++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 324 insertions(+), 36 deletions(-)
+
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -1,8 +1,9 @@
+-/* Postprocess module symbol versions
++/* Postprocess module symbol versions and do various other module checks.
+ *
+ * Copyright 2003 Kai Germaschewski
+ * Copyright 2002-2004 Rusty Russell, IBM Corporation
+ * Copyright 2006-2008 Sam Ravnborg
++ * Copyright 2007 Andi Kleen, SUSE Labs (changes licensed GPLv2 only)
+ * Based in part on module-init-tools/depmod.c,file2alias
+ *
+ * This software may be used and distributed according to the terms
+@@ -14,9 +15,13 @@
+ #define _GNU_SOURCE
+ #include <stdio.h>
+ #include <ctype.h>
++#include <assert.h>
+ #include "modpost.h"
+ #include "../../include/linux/license.h"
+
++#define NS_SEPARATOR '.'
++#define NS_SEPARATOR_STRING "."
++
+ /* Are we using CONFIG_MODVERSIONS? */
+ int modversions = 0;
+ /* Warn about undefined symbols? (do so if we have vmlinux) */
+@@ -29,6 +34,9 @@ static int external_module = 0;
+ static int vmlinux_section_warnings = 1;
+ /* Only warn about unresolved symbols */
+ static int warn_unresolved = 0;
++/* Fixing those would cause too many ifdefs -- off by default. */
++static int warn_missing_modules = 0;
++
+ /* How a symbol is exported */
+ static int sec_mismatch_count = 0;
+ static int sec_mismatch_verbose = 1;
+@@ -110,20 +118,44 @@ static struct module *find_module(char *
+ return mod;
+ }
+
+-static struct module *new_module(char *modname)
++static const char *my_basename(const char *s)
++{
++ char *p = strrchr(s, '/');
++ if (p)
++ return p + 1;
++ return s;
++}
++
++static struct module *find_module_base(char *modname)
+ {
+ struct module *mod;
+- char *p, *s;
+
+- mod = NOFAIL(malloc(sizeof(*mod)));
+- memset(mod, 0, sizeof(*mod));
+- p = NOFAIL(strdup(modname));
++ for (mod = modules; mod; mod = mod->next) {
++ if (strcmp(my_basename(mod->name), modname) == 0)
++ break;
++ }
++ return mod;
++}
+
++static void strip_o(char *p)
++{
++ char *s;
+ /* strip trailing .o */
+ s = strrchr(p, '.');
+ if (s != NULL)
+ if (strcmp(s, ".o") == 0)
+ *s = '\0';
++}
++
++static struct module *new_module(char *modname)
++{
++ struct module *mod;
++ char *p;
++
++ mod = NOFAIL(malloc(sizeof(*mod)));
++ memset(mod, 0, sizeof(*mod));
++ p = NOFAIL(strdup(modname));
++ strip_o(p);
+
+ /* add to list */
+ mod->name = p;
+@@ -138,10 +170,12 @@ static struct module *new_module(char *m
+ * struct symbol is also used for lists of unresolved symbols */
+
+ #define SYMBOL_HASH_SIZE 1024
++#define NSALLOW_HASH_SIZE 64
+
+ struct symbol {
+ struct symbol *next;
+ struct module *module;
++ const char *namespace;
+ unsigned int crc;
+ int crc_valid;
+ unsigned int weak:1;
+@@ -153,10 +187,19 @@ struct symbol {
+ char name[0];
+ };
+
++struct nsallow {
++ struct nsallow *next;
++ struct module *mod;
++ struct module *orig;
++ int ref;
++ char name[0];
++};
++
+ static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
++static struct nsallow *nsallowhash[NSALLOW_HASH_SIZE];
+
+ /* This is based on the hash agorithm from gdbm, via tdb */
+-static inline unsigned int tdb_hash(const char *name)
++static unsigned int tdb_hash(const char *name)
+ {
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+@@ -198,21 +241,66 @@ static struct symbol *new_symbol(const c
+ return new;
+ }
+
+-static struct symbol *find_symbol(const char *name)
++static struct symbol *find_symbol(const char *name, const char *ns)
+ {
+- struct symbol *s;
++ struct symbol *s, *match;
+
+ /* For our purposes, .foo matches foo. PPC64 needs this. */
+ if (name[0] == '.')
+ name++;
++ match = NULL;
++ for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s=s->next) {
++ if (strcmp(s->name, name) == 0) {
++ match = s;
++ if (ns && s->namespace && strcmp(s->namespace, ns))
++ continue;
++ return s;
++ }
++ }
++ return ns ? NULL : match;
++}
++
++static struct nsallow *find_nsallow(const char *name, struct module *mod)
++{
++ struct nsallow *s;
+
+- for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
++ for (s = nsallowhash[tdb_hash(name)%NSALLOW_HASH_SIZE]; s; s = s->next) {
++ if (strcmp(s->name, name) == 0 && s->mod == mod)
++ return s;
++ }
++ return NULL;
++}
++
++static struct nsallow *find_nsallow_name(const char *name)
++{
++ struct nsallow *s;
++
++ for (s = nsallowhash[tdb_hash(name)%NSALLOW_HASH_SIZE]; s; s=s->next) {
+ if (strcmp(s->name, name) == 0)
+ return s;
+ }
+ return NULL;
+ }
+
++static struct nsallow *
++new_nsallow(const char *name, struct module *module, struct module *orig)
++{
++ unsigned int hash;
++ struct nsallow *new;
++ unsigned len;
++
++ len = sizeof(struct nsallow) + strlen(name) + 1;
++ new = NOFAIL(malloc(len));
++ new->mod = module;
++ new->orig = orig;
++ new->ref = 0;
++ strcpy(new->name, name);
++ hash = tdb_hash(name) % NSALLOW_HASH_SIZE;
++ new->next = nsallowhash[hash];
++ nsallowhash[hash] = new;
++ return new;
++}
++
+ static struct {
+ const char *str;
+ enum export export;
+@@ -260,27 +348,103 @@ static enum export export_from_sec(struc
+ return export_unknown;
+ }
+
++/* Check if all the name space that allows referencing the symbol's
++ namespace is in the same module as the export. This makes sure a
++ module doesn't allow itself into a namespace (the kernel checks
++ this too) */
++static void check_export_namespace(struct symbol *s)
++{
++ const char *namespace = s->namespace;
++ struct nsallow *nsa = find_nsallow_name(namespace);
++ if (!nsa) {
++ warn("%s: namespace %s used for export `%s', but no module "
++ "for it allowed\n", s->module->name, namespace, s->name);
++ }
++ for (; nsa; nsa = nsa->next) {
++ if (strcmp(nsa->name, namespace))
++ continue;
++ if (nsa->orig == s->module) {
++ nsa->ref++;
++ return;
++ }
++ }
++ merror("No module allowed for namespace %s in %s exporting %s\n",
++ namespace,
++ s->module->name,
++ s->name);
++}
++
++static void check_nsallow_referenced(void)
++{
++ int i;
++ struct nsallow *nsa;
++ for (i = 0; i < NSALLOW_HASH_SIZE; i++) {
++ for (nsa = nsallowhash[i]; nsa; nsa = nsa->next)
++ if (nsa->ref == 0 && !nsa->mod->skip) {
++ warn("%s: namespace %s allowed for module %s, "
++ "but no exports using it\n",
++ nsa->orig->name,
++ nsa->name,
++ nsa->mod->name);
++ }
++ }
++}
++
++static const char *sep_ns(const char **name)
++{
++ char *p;
++ const char *s = strchr(*name, NS_SEPARATOR);
++ if (!s)
++ return NULL;
++ *name = NOFAIL(strdup(*name));
++ p = strchr(*name, NS_SEPARATOR);
++ *p = '\0';
++ return p + 1;
++}
++
++static int deep_streq(const char *a, const char *b)
++{
++ if (a == b)
++ return 1;
++ if (!a || !b)
++ return 0;
++ return !strcmp(a, b);
++}
++
+ /**
+ * Add an exported symbol - it may have already been added without a
+ * CRC, in this case just update the CRC
+ **/
+-static struct symbol *sym_add_exported(const char *name, struct module *mod,
++static struct symbol *sym_add_exported(const char *oname, struct module *mod,
+ enum export export)
+ {
+- struct symbol *s = find_symbol(name);
++ const char *name = oname;
++ const char *namespace = sep_ns(&name);
++ struct symbol *s = find_symbol(name, namespace);
+
+ if (!s) {
+ s = new_symbol(name, mod, export);
++ s->namespace = namespace;
+ } else {
+ if (!s->preloaded) {
+ warn("%s: '%s' exported twice. Previous export "
+- "was in %s%s\n", mod->name, name,
++ "was in %s%s\n", mod->name, oname,
+ s->module->name,
+ is_vmlinux(s->module->name) ?"":".ko");
++ if (!deep_streq(s->namespace, namespace)) {
++ warn("%s: New namespace '%s' of '%s' doesn't "
++ "match existing namespace '%s'\n",
++ s->module->name,
++ namespace ?: "",
++ s->name ?: "???",
++ s->namespace ?: "");
++ }
+ } else {
+ /* In case Modules.symvers was out of date */
+ s->module = mod;
+ }
++ if (name != oname)
++ free((char *)name);
+ }
+ s->preloaded = 0;
+ s->vmlinux = is_vmlinux(mod->name);
+@@ -289,13 +453,58 @@ static struct symbol *sym_add_exported(c
+ return s;
+ }
+
+-static void sym_update_crc(const char *name, struct module *mod,
++static struct module *
++nsmodule(const char *name, int sep, const char *namespace, struct module *orig)
++{
++ struct module *mod;
++ char *modname = NOFAIL(malloc(sep + 1));
++
++ memcpy(modname, name, sep);
++ modname[sep] = 0;
++ mod = find_module_base(modname);
++ if (!mod) {
++ if (warn_missing_modules)
++ warn("%s: Namespace allow for %s references unknown"
++ " module %.*s\n", orig->name, namespace, sep, name);
++ mod = new_module(modname);
++ mod->skip = 1;
++ } else {
++ free(modname);
++ }
++ return mod;
++}
++
++static void sym_add_nsallow(const char *name, struct module *orig)
++{
++ struct module *mod;
++ int sep;
++ const char *namespace;
++
++ sep = strcspn(name, NS_SEPARATOR_STRING);
++ if (name[sep] == 0 || sep == 0) {
++ warn("%s: Namespace allow '%s' incorrectly formatted\n",
++ orig->name, name);
++ return;
++ }
++ namespace = name + sep + 1;
++ mod = nsmodule(name, sep, namespace, orig);
++ if (!find_nsallow(namespace, mod))
++ new_nsallow(namespace, mod, orig);
++}
++
++static void sym_update_crc(const char *oname, struct module *mod,
+ unsigned int crc, enum export export)
+ {
+- struct symbol *s = find_symbol(name);
++ const char *name = oname;
++ const char *namespace = sep_ns(&name);
++ struct symbol *s = find_symbol(name, namespace);
+
+- if (!s)
++ if (!s) {
+ s = new_symbol(name, mod, export);
++ } else if (oname != name) {
++ assert(deep_streq(s->namespace, namespace));
++ free((char *)name);
++ }
+ s->crc = crc;
+ s->crc_valid = 1;
+ }
+@@ -488,6 +697,22 @@ static int ignore_undef_symbol(struct el
+
+ #define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_"
+ #define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_"
++#define NSALLOW_PFX MODULE_SYMBOL_PREFIX "__knamespace_"
++
++
++static void handle_nsallow(struct module *mod, struct elf_info *info,
++ Elf_Sym *sym, const char *symname)
++{
++ switch (sym->st_shndx) {
++ case SHN_COMMON:
++ case SHN_ABS:
++ case SHN_UNDEF:
++ break;
++ default:
++ if (!strncmp(symname, NSALLOW_PFX, sizeof(NSALLOW_PFX)-1))
++ sym_add_nsallow(symname + sizeof(NSALLOW_PFX) - 1, mod);
++ }
++}
+
+ static void handle_modversions(struct module *mod, struct elf_info *info,
+ Elf_Sym *sym, const char *symname)
+@@ -536,18 +761,24 @@ static void handle_modversions(struct mo
+
+ if (memcmp(symname, MODULE_SYMBOL_PREFIX,
+ strlen(MODULE_SYMBOL_PREFIX)) == 0) {
+- mod->unres =
+- alloc_symbol(symname +
+- strlen(MODULE_SYMBOL_PREFIX),
+- ELF_ST_BIND(sym->st_info) == STB_WEAK,
+- mod->unres);
++ const int plen = strlen(MODULE_SYMBOL_PREFIX);
++ const char *name = symname + plen;
++ const char *namespace = sep_ns(&name);
++
++ mod->unres = alloc_symbol(name,
++ ELF_ST_BIND(sym->st_info) == STB_WEAK,
++ mod->unres);
++ mod->unres->namespace = namespace;
+ }
+ break;
+ default:
+ /* All exported symbols */
+ if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
+- sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
+- export);
++ struct symbol *s;
++ s = sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
++ export);
++ if (s->namespace)
++ check_export_namespace(s);
+ }
+ if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
+ mod->has_init = 1;
+@@ -1554,11 +1785,16 @@ static void read_symbols(char *modname)
+ struct elf_info info = { };
+ Elf_Sym *sym;
+
++ char m[strlen(modname) + 1];
++ strcpy(m, modname);
++ strip_o(m);
++
++ mod = find_module(m);
++ assert(mod != NULL);
++
+ if (!parse_elf(&info, modname))
+ return;
+
+- mod = new_module(modname);
+-
+ /* When there's no vmlinux, don't print warnings about
+ * unresolved symbols (since there'll be too many ;) */
+ if (is_vmlinux(modname)) {
+@@ -1582,6 +1818,12 @@ static void read_symbols(char *modname)
+ "license", license);
+ }
+
++ /* First process all nsallows to check them against the symbols */
++ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
++ symname = info.strtab + sym->st_name;
++ handle_nsallow(mod, &info, sym, symname);
++ }
++
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = info.strtab + sym->st_name;
+
+@@ -1682,13 +1924,39 @@ static void check_for_unused(enum export
+ }
+ }
+
++/* Check if symbol reference to S from module SYMMOD is allowed in namespace */
++static void check_symbol_ns(struct symbol *s, struct module *symmod,
++ const char *symmodname)
++{
++ const char *namespace = s->namespace;
++ struct nsallow *nsa;
++ int sep;
++
++ if (is_vmlinux(symmodname))
++ return;
++ nsa = find_nsallow(namespace, symmod);
++ if (nsa)
++ return;
++ sep = strcspn(s->name, NS_SEPARATOR_STRING);
++ if (!find_nsallow_name(namespace)) {
++ warn("%s: Unknown namespace %s referenced from `%.*s'\n",
++ symmodname, namespace, sep, s->name);
++ } else {
++ merror("%s: module not allowed to reference symbol "
++ "'%.*s' in namespace %s\n",
++ symmodname,
++ sep, s->name,
++ namespace);
++ }
++}
++
+ static void check_exports(struct module *mod)
+ {
+ struct symbol *s, *exp;
+
+ for (s = mod->unres; s; s = s->next) {
+ const char *basename;
+- exp = find_symbol(s->name);
++ exp = find_symbol(s->name, s->namespace);
+ if (!exp || exp->module == mod)
+ continue;
+ basename = strrchr(mod->name, '/');
+@@ -1696,6 +1964,8 @@ static void check_exports(struct module
+ basename++;
+ else
+ basename = mod->name;
++ if (s->namespace)
++ check_symbol_ns(s, mod, basename);
+ if (!mod->gpl_compatible)
+ check_for_gpl_usage(exp->export, basename, exp->name);
+ check_for_unused(exp->export, basename, exp->name);
+@@ -1735,14 +2005,18 @@ static int add_versions(struct buffer *b
+ int err = 0;
+
+ for (s = mod->unres; s; s = s->next) {
+- exp = find_symbol(s->name);
++ exp = find_symbol(s->name, s->namespace);
+ if (!exp || exp->module == mod) {
+ if (have_vmlinux && !s->weak) {
+ if (warn_unresolved) {
+- warn("\"%s\" [%s.ko] undefined!\n",
++ warn("\"%s%s%s\" [%s.ko] undefined!\n",
++ s->namespace ?: "",
++ s->namespace ? ":" : "",
+ s->name, mod->name);
+ } else {
+- merror("\"%s\" [%s.ko] undefined!\n",
++ merror("\"%s%s%s\" [%s.ko] undefined!\n",
++ s->namespace ?: "",
++ s->namespace ? ":" : "",
+ s->name, mod->name);
+ err = 1;
+ }
+@@ -1902,7 +2176,7 @@ static void read_dump(const char *fname,
+ if (!mod) {
+ if (is_vmlinux(modname))
+ have_vmlinux = 1;
+- mod = new_module(NOFAIL(strdup(modname)));
++ mod = new_module(modname);
+ mod->skip = 1;
+ }
+ s = sym_add_exported(symname, mod, export_no(export));
+@@ -2049,6 +2323,7 @@ int main(int argc, char **argv)
+ char *markers_write = NULL;
+ int opt;
+ int err;
++ int c;
+ struct ext_sym_list *extsym_iter;
+ struct ext_sym_list *extsym_start = NULL;
+
+@@ -2090,12 +2365,15 @@ int main(int argc, char **argv)
+ case 'w':
+ warn_unresolved = 1;
+ break;
+- case 'M':
+- markers_write = optarg;
+- break;
+- case 'K':
+- markers_read = optarg;
+- break;
++ case 'M':
++ markers_write = optarg;
++ break;
++ case 'K':
++ markers_read = optarg;
++ break;
++ case 'X':
++ warn_missing_modules = 1;
++ break;
+ default:
+ exit(1);
+ }
+@@ -2105,6 +2383,13 @@ int main(int argc, char **argv)
+ read_dump(kernel_read, 1);
+ if (module_read)
+ read_dump(module_read, 0);
++
++ for (c = optind; c < argc; c++) {
++ char s[strlen(argv[c]) + 1];
++ strcpy(s, argv[c]);
++ new_module(s);
++ }
++
+ while (extsym_start) {
+ read_dump(extsym_start->file, 0);
+ extsym_iter = extsym_start->next;
+@@ -2121,6 +2406,9 @@ int main(int argc, char **argv)
+ check_exports(mod);
+ }
+
++ if (warn_unresolved)
++ check_nsallow_referenced();
++
+ err = 0;
+
+ for (mod = modules; mod; mod = mod->next) {
diff --git a/ns/module-usb-serial.patch b/ns/module-usb-serial.patch
new file mode 100644
index 00000000000000..6a01e430cf148b
--- /dev/null
+++ b/ns/module-usb-serial.patch
@@ -0,0 +1,23 @@
+---
+ drivers/usb/serial/usb-serial.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -1212,12 +1212,15 @@ void usb_serial_deregister(struct usb_se
+
+ /* If the usb-serial core is built into the core, the usb-serial drivers
+ need these symbols to load properly as modules. */
+-EXPORT_SYMBOL_GPL(usb_serial_register);
++//EXPORT_SYMBOL_GPL(usb_serial_register);
++EXPORT_SYMBOL_NS(usb, usb_serial_register);
+ EXPORT_SYMBOL_GPL(usb_serial_deregister);
+ EXPORT_SYMBOL_GPL(usb_serial_probe);
+ EXPORT_SYMBOL_GPL(usb_serial_disconnect);
+ EXPORT_SYMBOL_GPL(usb_serial_port_softint);
+
++MODULE_NAMESPACE_ALLOW(usb, visor);
++MODULE_NAMESPACE_ALLOW(usb, sierra);
+
+ /* Module information */
+ MODULE_AUTHOR( DRIVER_AUTHOR );
diff --git a/ns/namespace b/ns/namespace
new file mode 100644
index 00000000000000..dc466df6b69412
--- /dev/null
+++ b/ns/namespace
@@ -0,0 +1,237 @@
+Core module symbol namespaces code and intro.
+
+There seems to be rough consensus that the kernel currently has too many
+exported symbols. A lot of these exports are generally usable utility
+functions or important driver interfaces; but another large part are
+functions intended by only one or two very specific modules for a very
+specific purpose. One example is the TCP code. It has most of its
+internals exported, but only for use by tcp_ipv6.c (and now a few more
+by the TCP/IP congestion modules) But it doesn't make sense to include
+these exported for a specific module functions into a broader "kernel
+interface". External modules assume they can use these functions, but
+they were never intended for that.
+
+This patch allows to export symbols only for specific modules by
+introducing symbol name spaces. A module name space has a white list of
+modules that are allowed to import symbols for it; all others can't use
+the symbols.
+
+It adds two new macros:
+
+MODULE_NAMESPACE_ALLOW(namespace, module);
+
+Allow module to import symbols from namespace. module is the module name
+without .ko as displayed by lsmod. Must be in the same module as the
+export (and be duplicated if there are multiple modules exporting
+symbols to a namespace). Multiple allows for the same name space are
+allowed.
+
+EXPORT_SYMBOL_NS(namespace, symbol);
+
+Export symbol into namespace. Only modules allowed for the namespace
+will be able to use them. EXPORT_SYMBOL_NS implies GPL only because it
+is only for "internal" interfaces.
+
+The name spaces only work for module loading. I didn't find a nice way
+to make them work inside the main kernel binary. This means the name
+space is not enforced for modules that are built in.
+
+The biggest amount of work is of course still open: to go over all the
+existing exports and figure for which ones it makes sense to define a
+namespace. I did it for TCP and UDP so far, but the kernel right now
+has nearly 10k exports (with some dups) that would need to be checked
+and turned into name spaces. I would expect any symbol that is only used
+by one or two other modules is a strong candidate for a namespace; in
+some cases even more with modules that are tightly coupled.
+
+I am optimistic that in the end we will have a much more manageable
+kernel interface.
+
+Caveats:
+
+Exports need one long word more memory.
+
+I had to add some alignment magic to the existing EXPORT_SYMBOLs to get
+the sections right. Tested on i386/x86-64, but I hope it also still
+works on architectures with stricter alignment requirements like ARM.
+Any testers for that?
+
+---
+ arch/arm/kernel/armksyms.c | 2 -
+ include/asm-generic/vmlinux.lds.h | 7 +++
+ include/linux/module.h | 69 ++++++++++++++++++++++++++++++--------
+ kernel/module.c | 2 -
+ 4 files changed, 65 insertions(+), 15 deletions(-)
+
+--- a/arch/arm/kernel/armksyms.c
++++ b/arch/arm/kernel/armksyms.c
+@@ -52,7 +52,7 @@ extern void fp_enter(void);
+ * This has a special calling convention; it doesn't
+ * modify any of the usual registers, except for LR.
+ */
+-#define EXPORT_CRC_ALIAS(sym) __CRC_SYMBOL(sym, "")
++#define EXPORT_CRC_ALIAS(sym) __CRC_SYMBOL(sym, "", "", "")
+
+ #define EXPORT_SYMBOL_ALIAS(sym,orig) \
+ EXPORT_CRC_ALIAS(sym) \
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -163,6 +163,13 @@
+ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
+ } \
+ \
++ /* Kernel symbol table: namespaces */ \
++ __knamespace : AT(ADDR(__knamespace) - LOAD_OFFSET) { \
++ VMLINUX_SYMBOL(__start___knamespace) = .; \
++ *(__knamespace) \
++ VMLINUX_SYMBOL(__stop___knamespace) = .; \
++ } \
++ \
+ /* Kernel symbol table: strings */ \
+ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
+ *(__ksymtab_strings) \
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -34,6 +34,7 @@ struct kernel_symbol
+ {
+ unsigned long value;
+ const char *name;
++ const char *namespace;
+ };
+
+ struct modversion_info
+@@ -169,47 +170,81 @@ struct notifier_block;
+ /* Get/put a kernel symbol (calls must be symmetric) */
+ void *__symbol_get(const char *symbol);
+ void *__symbol_get_gpl(const char *symbol);
++//extern void *do_symbol_get(const char *symbol, struct module *caller);
++//#define __symbol_get(sym) do_symbol_get(sym, THIS_MODULE)
+ #define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x)))
+
++struct module_ns {
++ char *name;
++ char *allowed;
++};
++
++#define NS_SEPARATOR "."
++
++/*
++ * Allow module MODULE to reference namespace NS.
++ * MODULE is just the base module name with suffix or path.
++ * This must be declared in the module (or main kernel) as where the
++ * symbols are defined. When multiple modules export symbols from
++ * a single namespace all modules need to contain a full set
++ * of MODULE_NAMESPACE_ALLOWs.
++ */
++#define MODULE_NAMESPACE_ALLOW(ns, module) \
++ static const struct module_ns __knamespace_##module##_##_##ns \
++ asm("__knamespace_" #module NS_SEPARATOR #ns) \
++ __used \
++ __attribute__((section("__knamespace"), unused)) \
++ = { #ns, #module }
++
+ #ifndef __GENKSYMS__
+ #ifdef CONFIG_MODVERSIONS
+ /* Mark the CRC weak since genksyms apparently decides not to
+ * generate a checksums for some symbols */
+-#define __CRC_SYMBOL(sym, sec) \
++#define __CRC_SYMBOL(sym, sec, post, post2) \
+ extern void *__crc_##sym __attribute__((weak)); \
+- static const unsigned long __kcrctab_##sym \
++ static const unsigned long __kcrctab_##sym##post \
++ asm("__kcrctab_" #sym post2) \
+ __used \
+ __attribute__((section("__kcrctab" sec), unused)) \
+ = (unsigned long) &__crc_##sym;
+ #else
+-#define __CRC_SYMBOL(sym, sec)
++#define __CRC_SYMBOL(sym, sec, post, post2)
+ #endif
+
+ /* For every exported symbol, place a struct in the __ksymtab section */
+-#define __EXPORT_SYMBOL(sym, sec) \
++#define __EXPORT_SYMBOL(sym, sec, post, post2, ns) \
+ extern typeof(sym) sym; \
+- __CRC_SYMBOL(sym, sec) \
+- static const char __kstrtab_##sym[] \
++ __CRC_SYMBOL(sym, sec, post, post2) \
++ static const char __kstrtab_##sym##post[] \
++ asm("__kstrtab_" #sym post2) \
+ __attribute__((section("__ksymtab_strings"), aligned(1))) \
+ = MODULE_SYMBOL_PREFIX #sym; \
+- static const struct kernel_symbol __ksymtab_##sym \
++ static const struct kernel_symbol __ksymtab_##sym##post \
++ asm("__ksymtab_" #sym post2) \
+ __used \
+ __attribute__((section("__ksymtab" sec), unused)) \
+- = { (unsigned long)&sym, __kstrtab_##sym }
++ __attribute__((aligned(sizeof(void *)))) \
++ = { (unsigned long)&sym, __kstrtab_##sym##post, ns }
+
+ #define EXPORT_SYMBOL(sym) \
+- __EXPORT_SYMBOL(sym, "")
++ __EXPORT_SYMBOL(sym, "",,, NULL)
+
+ #define EXPORT_SYMBOL_GPL(sym) \
+- __EXPORT_SYMBOL(sym, "_gpl")
++ __EXPORT_SYMBOL(sym, "_gpl",,, NULL)
+
+ #define EXPORT_SYMBOL_GPL_FUTURE(sym) \
+- __EXPORT_SYMBOL(sym, "_gpl_future")
++ __EXPORT_SYMBOL(sym, "_gpl_future",,, NULL)
+
+
++/* Export symbol into namespace ns
++ * No _GPL variants because namespaces imply GPL only
++ */
++#define EXPORT_SYMBOL_NS(ns, sym) \
++ __EXPORT_SYMBOL(sym, "_gpl",__##ns, NS_SEPARATOR #ns, #ns)
++
+ #ifdef CONFIG_UNUSED_SYMBOLS
+-#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
+-#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
++#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused",,,NULL)
++#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl",,,NULL)
+ #else
+ #define EXPORT_UNUSED_SYMBOL(sym)
+ #define EXPORT_UNUSED_SYMBOL_GPL(sym)
+@@ -271,6 +306,10 @@ struct module
+ unsigned int num_gpl_future_syms;
+ const unsigned long *gpl_future_crcs;
+
++ /* Namespaces */
++ struct module_ns *knamespace;
++ unsigned num_knamespaces;
++
+ /* Exception table */
+ unsigned int num_exentries;
+ const struct exception_table_entry *extable;
+@@ -375,6 +414,8 @@ extern void __module_put_and_exit(struct
+ #ifdef CONFIG_MODULE_UNLOAD
+ unsigned int module_refcount(struct module *mod);
+ void __symbol_put(const char *symbol);
++//extern void do_symbol_put(const char *symbol, struct module *caller);
++//#define __symbol_put(symbol) do_symbol_put(symbol, THIS_MODULE)
+ #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x)
+ void symbol_put_addr(void *addr);
+
+@@ -456,6 +497,8 @@ extern void module_update_markers(void);
+ #define EXPORT_SYMBOL_GPL_FUTURE(sym)
+ #define EXPORT_UNUSED_SYMBOL(sym)
+ #define EXPORT_UNUSED_SYMBOL_GPL(sym)
++#define EXPORT_SYMBOL_NS(sym, ns)
++#define MODULE_NAMESPACE_ALLOW(ns, allow)
+
+ /* Given an address, look for it in the exception tables. */
+ static inline const struct exception_table_entry *
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -47,7 +47,7 @@
+ #include <linux/license.h>
+ #include <asm/sections.h>
+
+-#if 0
++#if 1
+ #define DEBUGP printk
+ #else
+ #define DEBUGP(fmt , a...)
diff --git a/ns/namespace_module.c b/ns/namespace_module.c
new file mode 100644
index 00000000000000..103a0f6cd2fbcb
--- /dev/null
+++ b/ns/namespace_module.c
@@ -0,0 +1,253 @@
+
+---
+ kernel/module.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 112 insertions(+), 19 deletions(-)
+
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -47,7 +47,7 @@
+ #include <linux/license.h>
+ #include <asm/sections.h>
+
+-#if 0
++#if 1
+ #define DEBUGP printk
+ #else
+ #define DEBUGP(fmt , a...)
+@@ -145,6 +145,8 @@ extern const unsigned long __start___kcr
+ extern const unsigned long __start___kcrctab_gpl_future[];
+ extern const unsigned long __start___kcrctab_unused[];
+ extern const unsigned long __start___kcrctab_unused_gpl[];
++extern const struct module_ns __start___knamespace[];
++extern const struct module_ns __stop___knamespace[];
+
+ #ifndef CONFIG_MODVERSIONS
+ #define symversion(base, idx) NULL
+@@ -242,11 +244,10 @@ static const struct kernel_symbol *searc
+
+ /* Find a symbol, return value, (optional) crc and (optional) module
+ * which owns it */
+-static unsigned long find_symbol(const char *name,
+- struct module **owner,
+- const unsigned long **crc,
+- bool gplok,
+- bool warn)
++static const struct kernel_symbol *do_find_symbol(const char *name,
++ struct module **owner,
++ const unsigned long **crc,
++ bool gplok, bool warn)
+ {
+ struct module *mod;
+ const struct kernel_symbol *ks;
+@@ -268,7 +269,7 @@ static unsigned long find_symbol(const c
+ if (ks) {
+ if (owner)
+ *owner = NULL;
+- return ks->value;
++ return ks;
+ }
+
+ /* Now try modules. */
+@@ -294,12 +295,95 @@ static unsigned long find_symbol(const c
+ if (ks) {
+ if (owner)
+ *owner = mod;
+- return ks->value;
++ return ks;
+ }
+ }
+
+ DEBUGP("Failed to find symbol %s\n", name);
+- return -ENOENT;
++ return NULL;
++}
++
++/* Find namespace in a single namespace table */
++static const struct module_ns *lookup_namespace(const struct module_ns *start,
++ const struct module_ns *stop,
++ const char *name,
++ const char *reqname, int *n)
++{
++ const struct module_ns *ns;
++ for (ns = start; ns < stop; ns++)
++ if (!strcmp(name, ns->name)) {
++ (*n)++;
++ if (!strcmp(reqname, ns->allowed))
++ return ns;
++ }
++ return NULL;
++}
++
++/* Search all namespace tables for a namespace */
++static const struct module_ns *find_namespace(const char *name,
++ const char *reqname, int *n,
++ const struct module **modp)
++{
++ const struct module_ns *ns;
++ struct module *mod;
++ *modp = NULL;
++ ns = lookup_namespace(__start___knamespace, __stop___knamespace,
++ name, reqname, n);
++ if (ns)
++ return ns;
++ list_for_each_entry(mod, &modules, list) {
++ ns = lookup_namespace(mod->knamespace,
++ mod->knamespace + mod->num_knamespaces,
++ name, reqname, n);
++ if (ns) {
++ *modp = mod;
++ return ns;
++ }
++ }
++ return NULL;
++}
++
++/* Look up a symbol and check namespace */
++static unsigned long find_symbol(const char *name,
++ struct module **owner,
++ const unsigned long **crc,
++ bool gplok, bool warn,
++ struct module *requester)
++{
++ const struct kernel_symbol *ks;
++ const struct module_ns *ns;
++ const struct module *mod;
++ int n = 0;
++
++ ks = do_find_symbol(name, owner, crc, gplok, warn);
++ if (!ks)
++ return 0;
++
++ /* When the symbol has a name space check if the requesting module
++ is white listed as allowed. */
++ if (ks->namespace) {
++ ns = find_namespace(ks->namespace, requester->name, &n, &mod);
++ if (!ns) {
++ if (n > 0)
++ printk(KERN_WARNING "module %s not allowed "
++ "to reference namespace `%s' for %s\n",
++ requester->name, ks->namespace, name);
++ else
++ printk(KERN_WARNING "%s referencing "
++ "undeclared namespace `%s' for %s\n",
++ requester->name, ks->namespace, name);
++ return 0;
++ }
++ /* Only allow name space declarations in the symbol's own
++ module. */
++ if (mod != *owner) {
++ printk(KERN_WARNING "namespace `%s' for symbol `%s' "
++ "defined in wrong module `%s'\n",
++ name, name, mod->name);
++ return 0;
++ }
++ }
++ return ks->value;
+ }
+
+ /* Search for module by name: must hold module_mutex. */
+@@ -784,17 +868,17 @@ static void print_unload_info(struct seq
+ seq_printf(m, "-");
+ }
+
+-void __symbol_put(const char *symbol)
++void do_symbol_put(const char *symbol, struct module *caller)
+ {
+ struct module *owner;
+
+ preempt_disable();
+- if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false)))
++ if (!find_symbol(symbol, &owner, NULL, true, false, caller))
+ BUG();
+ module_put(owner);
+ preempt_enable();
+ }
+-EXPORT_SYMBOL(__symbol_put);
++EXPORT_SYMBOL(do_symbol_put);
+
+ void symbol_put_addr(void *addr)
+ {
+@@ -952,7 +1036,8 @@ static inline int check_modstruct_versio
+ {
+ const unsigned long *crc;
+
+- if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false)))
++ if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc,
++ true, false, mod)))
+ BUG();
+ return check_version(sechdrs, versindex, "struct_module", mod, crc);
+ }
+@@ -1003,7 +1088,7 @@ static unsigned long resolve_symbol(Elf_
+ const unsigned long *crc;
+
+ ret = find_symbol(name, &owner, &crc,
+- !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
++ !(mod->taints & TAINT_PROPRIETARY_MODULE), true, mod);
+ if (!IS_ERR_VALUE(ret)) {
+ /* use_module can fail due to OOM,
+ or module initialization or unloading */
+@@ -1412,13 +1497,13 @@ static void free_module(struct module *m
+ module_free(mod, mod->module_core);
+ }
+
+-void *__symbol_get(const char *symbol)
++void *do_symbol_get(const char *symbol, struct module *caller)
+ {
+ struct module *owner;
+ unsigned long value;
+
+ preempt_disable();
+- value = find_symbol(symbol, &owner, NULL, true, true);
++ value = find_symbol(symbol, &owner, NULL, true, true, caller);
+ if (IS_ERR_VALUE(value))
+ value = 0;
+ else if (strong_try_module_get(owner))
+@@ -1427,7 +1512,7 @@ void *__symbol_get(const char *symbol)
+
+ return (void *)value;
+ }
+-EXPORT_SYMBOL_GPL(__symbol_get);
++EXPORT_SYMBOL_GPL(do_symbol_get);
+
+ /*
+ * Ensure that an exported symbol [global namespace] does not already exist
+@@ -1451,8 +1536,8 @@ static int verify_export_symbols(struct
+
+ for (i = 0; i < ARRAY_SIZE(arr); i++) {
+ for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
+- if (!IS_ERR_VALUE(find_symbol(s->name, &owner,
+- NULL, true, false))) {
++ if (!IS_ERR_VALUE(find_symbol(s->name, &owner, NULL,
++ true, false, mod))) {
+ printk(KERN_ERR
+ "%s: exports duplicate symbol %s"
+ " (owned by %s)\n",
+@@ -1770,6 +1855,7 @@ static struct module *load_module(void _
+ unsigned int unusedgplcrcindex;
+ unsigned int markersindex;
+ unsigned int markersstringsindex;
++ unsigned int namespaceindex;
+ struct module *mod;
+ long err = 0;
+ void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
+@@ -1866,6 +1952,7 @@ static struct module *load_module(void _
+ #ifdef ARCH_UNWIND_SECTION_NAME
+ unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
+ #endif
++ namespaceindex = find_sec(hdr, sechdrs, secstrings, "__knamespace");
+
+ /* Don't keep modinfo and version sections. */
+ sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+@@ -2034,6 +2121,12 @@ static struct module *load_module(void _
+ mod->unused_gpl_crcs
+ = (void *)sechdrs[unusedgplcrcindex].sh_addr;
+
++ if (namespaceindex) {
++ mod->knamespace = (void *)sechdrs[namespaceindex].sh_addr;
++ mod->num_knamespaces = sechdrs[namespaceindex].sh_size /
++ sizeof(*mod->knamespace);
++ }
++
+ #ifdef CONFIG_MODVERSIONS
+ if ((mod->num_syms && !crcindex) ||
+ (mod->num_gpl_syms && !gplcrcindex) ||
diff --git a/ns/ns-debug b/ns/ns-debug
new file mode 100644
index 00000000000000..1f98cdfbb1aa24
--- /dev/null
+++ b/ns/ns-debug
@@ -0,0 +1,45 @@
+---
+ arch/x86/Makefile | 2 +-
+ kernel/module.c | 11 +++++++++--
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -65,7 +65,7 @@ else
+
+ # -funit-at-a-time shrinks the kernel .text considerably
+ # unfortunately it makes reading oopses harder.
+- KBUILD_CFLAGS += $(call cc-option,-funit-at-a-time)
++ KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time)
+
+ # this works around some issues with generating unwind tables in older gccs
+ # newer gccs do it by default
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -47,7 +47,7 @@
+ #include <linux/license.h>
+ #include <asm/sections.h>
+
+-#if 0
++#if 1
+ #define DEBUGP printk
+ #else
+ #define DEBUGP(fmt , a...)
+@@ -160,9 +160,16 @@ static const struct kernel_symbol *looku
+ const struct kernel_symbol *stop)
+ {
+ const struct kernel_symbol *ks = start;
+- for (; ks < stop; ks++)
++ for (; ks < stop; ks++) {
++ if (ks->name == NULL) {
++ printk("%ld name NULL (prev %s %lx %s)\n",
++ (unsigned long)ks-(unsigned long)start,
++ ks[-1].name, ks[-1].value, ks[-1].namespace);
++ return NULL;
++ }
+ if (strcmp(ks->name, name) == 0)
+ return ks;
++ }
+ return NULL;
+ }
+