diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-06-30 10:51:47 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-06-30 10:51:47 -0700 |
| commit | 33f43d082d6ea41c8c90e3b64f99b1b072180fad (patch) | |
| tree | bc5fb96519ba37d0c928ed2b5a6b9133719c743c /ns | |
| parent | af94d897d09cf05550c2a4caabcad68a51534005 (diff) | |
| download | patches-33f43d082d6ea41c8c90e3b64f99b1b072180fad.tar.gz | |
move some files around
Diffstat (limited to 'ns')
| -rw-r--r-- | ns/modpost | 590 | ||||
| -rw-r--r-- | ns/module-usb-serial.patch | 23 | ||||
| -rw-r--r-- | ns/namespace | 237 | ||||
| -rw-r--r-- | ns/namespace_module.c | 253 | ||||
| -rw-r--r-- | ns/ns-debug | 45 |
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; + } + |
