Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Move builtin modules to a list in init and load them fro...



details:   https://anonhg.NetBSD.org/src/rev/08ec8fa701a7
branches:  trunk
changeset: 752746:08ec8fa701a7
user:      pooka <pooka%NetBSD.org@localhost>
date:      Fri Mar 05 18:35:01 2010 +0000

description:
Move builtin modules to a list in init and load them from there
instead of using linksets directly.  This has two implications:

1) It is now possible to "unload" a builtin module provided it is
   not busy.  This is useful e.g. to disable a kernel feature as
   an immediate workaround to a security problem.  To re-initialize
   the module, modload -f <name> is required.
2) It is possible to use builtin modules which were linked at
   runtime with an external linker (dlopen + rump).

diffstat:

 sys/kern/kern_module.c |  285 ++++++++++++++++++++++++++++++++++++++----------
 sys/kern/sys_module.c  |   24 +++-
 sys/sys/module.h       |    6 +-
 3 files changed, 249 insertions(+), 66 deletions(-)

diffs (truncated from 503 to 300 lines):

diff -r 43d7135c6944 -r 08ec8fa701a7 sys/kern/kern_module.c
--- a/sys/kern/kern_module.c    Fri Mar 05 17:58:15 2010 +0000
+++ b/sys/kern/kern_module.c    Fri Mar 05 18:35:01 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_module.c,v 1.58 2010/03/03 17:58:36 pooka Exp $   */
+/*     $NetBSD: kern_module.c,v 1.59 2010/03/05 18:35:01 pooka Exp $   */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_module.c,v 1.58 2010/03/03 17:58:36 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_module.c,v 1.59 2010/03/05 18:35:01 pooka Exp $");
 
 #define _MODULE_INTERNAL
 
@@ -63,12 +63,15 @@
 struct vm_map *module_map;
 char   module_base[MODULE_BASE_SIZE];
 
-struct modlist module_list = TAILQ_HEAD_INITIALIZER(module_list);
-struct modlist module_bootlist = TAILQ_HEAD_INITIALIZER(module_bootlist);
+struct modlist        module_list = TAILQ_HEAD_INITIALIZER(module_list);
+struct modlist        module_builtins = TAILQ_HEAD_INITIALIZER(module_builtins);
+static struct modlist module_bootlist = TAILQ_HEAD_INITIALIZER(module_bootlist);
+
 static module_t        *module_active;
 static int     module_verbose_on;
 static int     module_autoload_on = 1;
 u_int          module_count;
+u_int          module_builtinlist;
 kmutex_t       module_lock;
 u_int          module_autotime = 10;
 u_int          module_gen = 1;
@@ -155,6 +158,141 @@
 }
 
 /*
+ * Add modules to the builtin list.  This can done at boottime or
+ * at runtime if the module is linked into the kernel with an
+ * external linker.  All or none of the input will be handled.
+ * Optionally, the modules can be initialized.  If they are not
+ * initialized, module_init_class() or module_load() can be used
+ * later, but these are not guaranteed to give atomic results.
+ */
+int
+module_builtin_add(modinfo_t *const *mip, size_t nmodinfo, bool init)
+{
+       struct module **modp = NULL, *mod_iter;
+       int rv = 0, i, mipskip;
+
+       if (init) {
+               rv = kauth_authorize_system(kauth_cred_get(),
+                   KAUTH_SYSTEM_MODULE, 0, (void *)(uintptr_t)MODCTL_LOAD,
+                   (void *)(uintptr_t)1, NULL);
+               if (rv) {
+                       return rv;
+               }
+       }
+
+       for (i = 0, mipskip = 0; i < nmodinfo; i++) {
+               if (mip[i] == &module_dummy) {
+                       KASSERT(nmodinfo > 0);
+                       nmodinfo--;
+               }
+       }
+       if (nmodinfo == 0)
+               return 0;
+
+       modp = kmem_zalloc(sizeof(*modp) * nmodinfo, KM_SLEEP);
+       for (i = 0, mipskip = 0; i < nmodinfo; i++) {
+               if (mip[i+mipskip] == &module_dummy) {
+                       mipskip++;
+                       continue;
+               }
+               modp[i] = kmem_zalloc(sizeof(*modp[i]), KM_SLEEP);
+               modp[i]->mod_info = mip[i+mipskip];
+               modp[i]->mod_source = MODULE_SOURCE_KERNEL;
+       }
+       mutex_enter(&module_lock);
+
+       /* do this in three stages for error recovery and atomicity */
+
+       /* first check for presence */
+       for (i = 0; i < nmodinfo; i++) {
+               TAILQ_FOREACH(mod_iter, &module_builtins, mod_chain) {
+                       if (strcmp(mod_iter->mod_info->mi_name,
+                           modp[i]->mod_info->mi_name) == 0)
+                               break;
+               }
+               if (mod_iter) {
+                       rv = EEXIST;
+                       goto out;
+               }
+
+               if (module_lookup(modp[i]->mod_info->mi_name) != NULL) {
+                       rv = EEXIST;
+                       goto out;
+               }
+       }
+
+       /* then add to list */
+       for (i = 0; i < nmodinfo; i++) {
+               TAILQ_INSERT_TAIL(&module_builtins, modp[i], mod_chain);
+               module_builtinlist++;
+       }
+
+       /* finally, init (if required) */
+       if (init) {
+               for (i = 0; i < nmodinfo; i++) {
+                       rv = module_do_builtin(modp[i]->mod_info->mi_name,NULL);
+                       /* throw in the towel, recovery hard & not worth it */
+                       if (rv)
+                               panic("builtin module \"%s\" init failed: %d",
+                                   modp[i]->mod_info->mi_name, rv);
+               }
+       }
+
+ out:
+       mutex_exit(&module_lock);
+       if (rv != 0) {
+               for (i = 0; i < nmodinfo; i++) {
+                       if (modp[i])
+                               kmem_free(modp[i], sizeof(*modp[i]));
+               }
+       }
+       kmem_free(modp, sizeof(*modp) * nmodinfo);
+       return rv;
+}
+
+/*
+ * Optionally fini and remove builtin module from the kernel.
+ * Note: the module will now be unreachable except via mi && builtin_add.
+ */
+int
+module_builtin_remove(modinfo_t *mi, bool fini)
+{
+       struct module *mod;
+       int rv = 0;
+
+       if (fini) {
+               rv = kauth_authorize_system(kauth_cred_get(),
+                   KAUTH_SYSTEM_MODULE, 0, (void *)(uintptr_t)MODCTL_UNLOAD,
+                   NULL, NULL);
+               if (rv)
+                       return rv;
+
+               mutex_enter(&module_lock);
+               rv = module_do_unload(mi->mi_name);
+               if (rv) {
+                       goto out;
+               }
+       } else {
+               mutex_enter(&module_lock);
+       }
+       TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+               if (strcmp(mod->mod_info->mi_name, mi->mi_name) == 0)
+                       break;
+       }
+       if (mod) {
+               TAILQ_REMOVE(&module_builtins, mod, mod_chain);
+               module_builtinlist--;
+       } else {
+               KASSERT(fini == false);
+               rv = ENOENT;
+       }
+
+ out:
+       mutex_exit(&module_lock);
+       return rv;
+}
+
+/*
  * module_init:
  *
  *     Initialize the module subsystem.
@@ -162,7 +300,10 @@
 void
 module_init(void)
 {
+       __link_set_decl(modules, modinfo_t);
        extern struct vm_map *module_map;
+       modinfo_t *const *mip;
+       int rv;
 
        if (module_map == NULL) {
                module_map = kernel_map;
@@ -185,6 +326,12 @@
 
        module_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
            module_listener_cb, NULL);
+
+       __link_set_foreach(mip, modules) {
+               if ((rv = module_builtin_add(mip, 1, false) != 0))
+                       module_error("builtin %s failed: %d\n",
+                           (*mip)->mi_name, rv);
+       }
 }
 
 /*
@@ -245,34 +392,32 @@
 void
 module_init_class(modclass_t class)
 {
-       __link_set_decl(modules, modinfo_t);
-       modinfo_t *const *mip, *mi;
-       module_t *mod, *mod_next;
+       module_t *mod;
+       modinfo_t *mi;
 
        mutex_enter(&module_lock);
        /*
-        * Builtins first.  These can't depend on pre-loaded modules.
+        * Builtins first.  These will not depend on pre-loaded modules
+        * (because the kernel would not link).
         */
-       __link_set_foreach(mip, modules) {
-               mi = *mip;
-               if (mi == &module_dummy) {
-                       continue;
+       do {
+               TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+                       mi = mod->mod_info;
+                       if (class != MODULE_CLASS_ANY && class != mi->mi_class)
+                               continue;
+                       (void)module_do_builtin(mi->mi_name, NULL);
+                       break;
                }
-               if (class != MODULE_CLASS_ANY && class != mi->mi_class) {
-                       continue;
-               }
-               (void)module_do_builtin(mi->mi_name, NULL);
-       }
+       } while (mod != NULL);
+
        /*
         * Now preloaded modules.  These will be pulled off the
         * list as we call module_do_load();
         */
        do {
-               for (mod = TAILQ_FIRST(&module_bootlist); mod; mod = mod_next) {
-                       mod_next = TAILQ_NEXT(mod, mod_chain);
+               TAILQ_FOREACH(mod, &module_bootlist, mod_chain) {
                        mi = mod->mod_info;
-                       if (class != MODULE_CLASS_ANY &&
-                           class != mi->mi_class)
+                       if (class != MODULE_CLASS_ANY && class != mi->mi_class)
                                continue;
                        module_do_load(mi->mi_name, false, 0, NULL, NULL,
                            class, false);
@@ -485,63 +630,49 @@
 /*
  * module_do_builtin:
  *
- *     Initialize a single module from the list of modules that are
- *     built into the kernel (linked into the kernel image).
+ *     Initialize a module from the list of modules that are
+ *     already linked into the kernel.
  */
 static int
 module_do_builtin(const char *name, module_t **modp)
 {
-       __link_set_decl(modules, modinfo_t);
-       modinfo_t *const *mip;
        const char *p, *s;
        char buf[MAXMODNAME];
-       modinfo_t *mi;
-       module_t *mod, *mod2;
+       modinfo_t *mi = NULL;
+       module_t *mod, *mod2, *mod_loaded;
        size_t len;
        int error;
 
        KASSERT(mutex_owned(&module_lock));
 
        /*
-        * Check to see if already loaded.
+        * Search the list to see if we have a module by this name.
         */
-       if ((mod = module_lookup(name)) != NULL) {
-               if (modp != NULL) {
-                       *modp = mod;
+       TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+               if (strcmp(mod->mod_info->mi_name, name) == 0) {
+                       mi = mod->mod_info;
+                       break;
                }
-               return 0;
        }
 
        /*
-        * Search the list to see if we have a module by this name.
+        * Check to see if already loaded.  This might happen if we
+        * were already loaded as a dependency.
         */
-       error = ENOENT;
-       __link_set_foreach(mip, modules) {
-               mi = *mip;



Home | Main Index | Thread Index | Old Index