/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software developed for The NetBSD Foundation
* by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Require the -f (force) flag to load a module
*/
static void
module_require_force(struct module *mod)
{
SET(mod->mod_flags, MODFLG_MUST_FORCE);
}
/*
* 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] = module_newmodule(MODULE_SOURCE_KERNEL);
modp[i]->mod_info = mip[i+mipskip];
}
kernconfig_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;
}
/* 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],
modp[i]->mod_info->mi_name, NULL, NULL);
/* throw in the towel, recovery hard & not worth it */
if (rv)
panic("%s: builtin module \"%s\" init failed:"
" %d", __func__,
modp[i]->mod_info->mi_name, rv);
}
}
out:
kernconfig_unlock();
if (rv != 0) {
for (i = 0; i < nmodinfo; i++) {
if (modp[i])
module_free(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;
/*
* module_builtin_require_force
*
* Require MODCTL_MUST_FORCE to load any built-in modules that have
* not yet been initialized
*/
void
module_builtin_require_force(void)
{
module_t *mod;
/*
* module_init_class:
*
* Initialize all built-in and pre-loaded modules of the
* specified class.
*/
void
module_init_class(modclass_t modclass)
{
TAILQ_HEAD(, module) bi_fail = TAILQ_HEAD_INITIALIZER(bi_fail);
module_t *mod;
modinfo_t *mi;
kernconfig_lock();
/*
* Builtins first. These will not depend on pre-loaded modules
* (because the kernel would not link).
*/
do {
TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
mi = mod->mod_info;
if (!MODULE_CLASS_MATCH(mi, modclass))
continue;
/*
* If initializing a builtin module fails, don't try
* to load it again. But keep it around and queue it
* on the builtins list after we're done with module
* init. Don't set it to MODFLG_MUST_FORCE in case a
* future attempt to initialize can be successful.
* (If the module has previously been set to
* MODFLG_MUST_FORCE, don't try to override that!)
*/
if (ISSET(mod->mod_flags, MODFLG_MUST_FORCE) ||
module_do_builtin(mod, mi->mi_name, NULL,
NULL) != 0) {
TAILQ_REMOVE(&module_builtins, mod, mod_chain);
TAILQ_INSERT_TAIL(&bi_fail, mod, mod_chain);
}
break;
}
} while (mod != NULL);
/*
* Now preloaded modules. These will be pulled off the
* list as we call module_do_load();
*/
do {
TAILQ_FOREACH(mod, &module_bootlist, mod_chain) {
mi = mod->mod_info;
if (!MODULE_CLASS_MATCH(mi, modclass))
continue;
module_do_load(mi->mi_name, false, 0, NULL, NULL,
modclass, false);
break;
}
} while (mod != NULL);
/* return failed builtin modules to builtin list */
while ((mod = TAILQ_FIRST(&bi_fail)) != NULL) {
TAILQ_REMOVE(&bi_fail, mod, mod_chain);
TAILQ_INSERT_TAIL(&module_builtins, mod, mod_chain);
}
kernconfig_unlock();
}
/*
* module_compatible:
*
* Return true if the two supplied kernel versions are said to
* have the same binary interface for kernel code. The entire
* version is significant for the development tree (-current),
* major and minor versions are significant for official
* releases of the system.
*/
bool
module_compatible(int v1, int v2)
{
/*
* module_load:
*
* Load a single module from the file system.
*/
int
module_load(const char *filename, int flags, prop_dictionary_t props,
modclass_t modclass)
{
module_t *mod;
int error;
/* Test if we already have the module loaded before
* authorizing so we have the opportunity to return EEXIST. */
kernconfig_lock();
mod = module_lookup(filename);
if (mod != NULL) {
module_print("%s module `%s' already loaded",
"Requested", filename);
error = EEXIST;
goto out;
}
/*
* module_autoload:
*
* Load a single module from the file system, system initiated.
*/
int
module_autoload(const char *filename, modclass_t modclass)
{
int error;
struct proc *p = curlwp->l_proc;
kernconfig_lock();
module_print("Autoload for `%s' requested by pid %d (%s)",
filename, p->p_pid, p->p_comm);
/* Nothing if the user has disabled it. */
if (!module_autoload_on) {
module_print("Autoload disabled for `%s' ", filename);
kernconfig_unlock();
return EPERM;
}
/*
* module_hold:
*
* Add a single reference to a module. It's the caller's
* responsibility to ensure that the reference is dropped
* later.
*/
void
module_hold(module_t *mod)
{
/*
* module_enqueue:
*
* Put a module onto the global list and update counters.
*/
void
module_enqueue(module_t *mod)
{
int i;
KASSERT(kernconfig_is_held());
/*
* Put new entry at the head of the queue so autounload can unload
* requisite modules with only one pass through the queue.
*/
TAILQ_INSERT_HEAD(&module_list, mod, mod_chain);
if (mod->mod_nrequired) {
/* Add references to the requisite modules. */
for (i = 0; i < mod->mod_nrequired; i++) {
KASSERT((*mod->mod_required)[i] != NULL);
(*mod->mod_required)[i]->mod_refcnt++;
}
}
module_count++;
module_gen++;
}
/*
* Our array of required module pointers starts with zero entries. If we
* need to add a new entry, and the list is already full, we reallocate a
* larger array, adding MAXMODDEPS entries.
*/
static void
alloc_required(module_t *mod)
{
module_t *(*new)[], *(*old)[];
int areq;
int i;
if (mod->mod_nrequired >= mod->mod_arequired) {
areq = mod->mod_arequired + MAXMODDEPS;
old = mod->mod_required;
new = kmem_zalloc(areq * sizeof(module_t *), KM_SLEEP);
for (i = 0; i < mod->mod_arequired; i++)
(*new)[i] = (*old)[i];
mod->mod_required = new;
if (old)
kmem_free(old, mod->mod_arequired * sizeof(module_t *));
mod->mod_arequired = areq;
}
}
/*
* module_do_builtin:
*
* Initialize a module from the list of modules that are
* already linked into the kernel.
*/
static int
module_do_builtin(const module_t *pmod, const char *name, module_t **modp,
prop_dictionary_t props)
{
const char *p, *s;
char buf[MAXMODNAME];
modinfo_t *mi = NULL;
module_t *mod, *mod2, *mod_loaded, *prev_active;
size_t len;
int error;
KASSERT(kernconfig_is_held());
/*
* Search the list to see if we have a module by this name.
*/
TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
if (strcmp(mod->mod_info->mi_name, name) == 0) {
mi = mod->mod_info;
break;
}
}
/*
* Check to see if already loaded. This might happen if we
* were already loaded as a dependency.
*/
if ((mod_loaded = module_lookup(name)) != NULL) {
KASSERT(mod == NULL);
if (modp)
*modp = mod_loaded;
return 0;
}
/* Note! This is from TAILQ, not immediate above */
if (mi == NULL) {
/*
* XXX: We'd like to panic here, but currently in some
* cases (such as nfsserver + nfs), the dependee can be
* successfully linked without the dependencies.
*/
module_error("Built-in module `%s' can't find built-in "
"dependency `%s'", pmod->mod_info->mi_name, name);
return ENOENT;
}
/*
* Initialize pre-requisites.
*/
KASSERT(mod->mod_required == NULL);
KASSERT(mod->mod_arequired == 0);
KASSERT(mod->mod_nrequired == 0);
if (mi->mi_required != NULL) {
for (s = mi->mi_required; *s != '\0'; s = p) {
if (*s == ',')
s++;
p = s;
while (*p != '\0' && *p != ',')
p++;
len = uimin(p - s + 1, sizeof(buf));
strlcpy(buf, s, len);
if (buf[0] == '\0')
break;
alloc_required(mod);
error = module_do_builtin(mod, buf, &mod2, NULL);
if (error != 0) {
module_error("Built-in module `%s' prerequisite "
"`%s' failed, error %d", name, buf, error);
goto fail;
}
(*mod->mod_required)[mod->mod_nrequired++] = mod2;
}
}
/*
* Try to initialize the module.
*/
prev_active = module_active;
module_active = mod;
error = (*mi->mi_modcmd)(MODULE_CMD_INIT, props);
module_active = prev_active;
if (error != 0) {
module_error("Built-in module `%s' failed its MODULE_CMD_INIT, "
"error %d", mi->mi_name, error);
goto fail;
}
/*
* Built-in modules don't have a mod_kobj so we cannot search
* for their link_set_sysctl_funcs
*/
if (mod->mod_source == MODULE_SOURCE_KERNEL)
return;
/*
* Built-in modules' static evcnt stuff will be handled
* automatically as part of general kernel initialization
*/
if (mod->mod_source == MODULE_SOURCE_KERNEL)
return;
/*
* Built-in modules' static evcnt stuff will be handled
* automatically as part of general kernel initialization
*/
if (mod->mod_source == MODULE_SOURCE_KERNEL)
return;
/*
* module_do_load:
*
* Helper routine: load a module from the file system, or one
* pushed by the boot loader.
*/
static int
module_do_load(const char *name, bool isdep, int flags,
prop_dictionary_t props, module_t **modp, modclass_t modclass,
bool autoload)
{
/* The pending list for this level of recursion */
TAILQ_HEAD(pending_t, module);
struct pending_t *pending;
struct pending_t new_pending = TAILQ_HEAD_INITIALIZER(new_pending);
/*
* Set up the pending list for this entry. If this is an
* internal entry (for a dependency), then use the same list
* as for the outer call; otherwise, it's an external entry
* (possibly recursive, ie a module's xxx_modcmd(init, ...)
* routine called us), so use the locally allocated list. In
* either case, add it to our stack.
*/
if (isdep) {
KASSERT(SLIST_FIRST(&pend_stack) != NULL);
pending = SLIST_FIRST(&pend_stack)->pe_pending;
} else
pending = &new_pending;
my_pend_entry.pe_pending = pending;
SLIST_INSERT_HEAD(&pend_stack, &my_pend_entry, pe_entry);
/*
* Search the list of disabled builtins first.
*/
TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
if (strcmp(mod->mod_info->mi_name, name) == 0) {
break;
}
}
if (mod) {
if (ISSET(mod->mod_flags, MODFLG_MUST_FORCE) &&
!ISSET(flags, MODCTL_LOAD_FORCE)) {
if (!autoload) {
module_error("Use -f to reinstate "
"builtin module `%s'", name);
}
SLIST_REMOVE_HEAD(&pend_stack, pe_entry);
return EPERM;
} else {
SLIST_REMOVE_HEAD(&pend_stack, pe_entry);
error = module_do_builtin(mod, name, modp, props);
module_print("module_do_builtin() returned %d", error);
return error;
}
}
/*
* Load the module and link. Before going to the file system,
* scan the list of modules loaded by the boot loader.
*/
TAILQ_FOREACH(mod, &module_bootlist, mod_chain) {
if (strcmp(mod->mod_info->mi_name, name) == 0) {
TAILQ_REMOVE(&module_bootlist, mod, mod_chain);
break;
}
}
if (mod != NULL) {
TAILQ_INSERT_TAIL(pending, mod, mod_chain);
} else {
/*
* Check to see if module is already present.
*/
mod = module_lookup(name);
if (mod != NULL) {
if (modp != NULL) {
*modp = mod;
}
module_print("%s module `%s' already loaded",
isdep ? "Dependent" : "Requested", name);
SLIST_REMOVE_HEAD(&pend_stack, pe_entry);
return EEXIST;
}
mod = module_newmodule(MODULE_SOURCE_FILESYS);
if (mod == NULL) {
module_error("Out of memory for `%s'", name);
SLIST_REMOVE_HEAD(&pend_stack, pe_entry);
return ENOMEM;
}
error = module_load_vfs_vec(name, flags, autoload, mod,
&filedict);
if (error != 0) {
#ifdef DEBUG
/*
* The exec class of modules contains a list of
* modules that is the union of all the modules
* available for each architecture, so we don't
* print an error if they are missing.
*/
if ((modclass != MODULE_CLASS_EXEC || error != ENOENT)
&& root_device != NULL)
module_error("module_load_vfs_vec() failed "
"for `%s', error %d", name, error);
else
#endif
module_print("module_load_vfs_vec() failed "
"for `%s', error %d", name, error);
SLIST_REMOVE_HEAD(&pend_stack, pe_entry);
module_free(mod);
return error;
}
TAILQ_INSERT_TAIL(pending, mod, mod_chain);
error = module_fetch_info(mod);
if (error != 0) {
module_error("Cannot fetch info for `%s', error %d",
name, error);
goto fail;
}
}
/*
* Check compatibility.
*/
mi = mod->mod_info;
if (strnlen(mi->mi_name, MAXMODNAME) >= MAXMODNAME) {
error = EINVAL;
module_error("Module name `%s' longer than %d", mi->mi_name,
MAXMODNAME);
goto fail;
}
if (mi->mi_class <= MODULE_CLASS_ANY ||
mi->mi_class >= MODULE_CLASS_MAX) {
error = EINVAL;
module_error("Module `%s' has invalid class %d",
mi->mi_name, mi->mi_class);
goto fail;
}
if (!module_compatible(mi->mi_version, __NetBSD_Version__)) {
module_error("Module `%s' built for `%d', system `%d'",
mi->mi_name, mi->mi_version, __NetBSD_Version__);
if (ISSET(flags, MODCTL_LOAD_FORCE)) {
module_error("Forced load, system may be unstable");
} else {
error = EPROGMISMATCH;
goto fail;
}
}
/*
* If a specific kind of module was requested, ensure that we have
* a match.
*/
if (!MODULE_CLASS_MATCH(mi, modclass)) {
module_incompat(mi, modclass);
error = ENOENT;
goto fail;
}
/*
* If loading a dependency, `name' is a plain module name.
* The name must match.
*/
if (isdep && strcmp(mi->mi_name, name) != 0) {
module_error("Dependency name mismatch (`%s' != `%s')",
name, mi->mi_name);
error = ENOENT;
goto fail;
}
/*
* If we loaded a module from the filesystem, check the actual
* module name (from the modinfo_t) to ensure another module
* with the same name doesn't already exist. (There's no
* guarantee the filename will match the module name, and the
* dup-symbols check may not be sufficient.)
*/
if (mod->mod_source == MODULE_SOURCE_FILESYS) {
mod2 = module_lookup(mod->mod_info->mi_name);
if ( mod2 && mod2 != mod) {
module_error("Module with name `%s' already loaded",
mod2->mod_info->mi_name);
error = EEXIST;
if (modp != NULL)
*modp = mod2;
goto fail;
}
}
if (filedict) {
if (!module_merge_dicts(filedict, props)) {
module_error("Module properties failed for %s", name);
error = EINVAL;
goto fail;
}
}
prev_active = module_active;
module_active = mod;
/*
* Note that we handle sysctl and evcnt setup _before_ we
* initialize the module itself. This maintains a consistent
* order between built-in and run-time-loaded modules. If
* initialization then fails, we'll need to undo these, too.
*/
module_load_sysctl(mod); /* Set-up module's sysctl if any */
module_load_evcnt(mod); /* Attach any static evcnt needed */
/*
* If a recursive load already added a module with the same
* name, abort.
*/
mod2 = module_lookup(mi->mi_name);
if (mod2 && mod2 != mod) {
module_error("Recursive load causes duplicate module `%s'",
mi->mi_name);
error = EEXIST;
goto fail1;
}
/*
* Good, the module loaded successfully. Put it onto the
* list and add references to its requisite modules.
*/
TAILQ_REMOVE(pending, mod, mod_chain);
module_enqueue(mod);
if (modp != NULL) {
*modp = mod;
}
if (autoload && module_autotime > 0) {
/*
* Arrange to try unloading the module after
* a short delay unless auto-unload is disabled.
*/
mod->mod_autotime = time_second + module_autotime;
SET(mod->mod_flags, MODFLG_AUTO_LOADED);
module_thread_kick();
}
SLIST_REMOVE_HEAD(&pend_stack, pe_entry);
module_print("Module `%s' loaded successfully", mi->mi_name);
module_callback_load(mod);
return 0;
fail1:
(*mi->mi_modcmd)(MODULE_CMD_FINI, NULL);
fail3:
/*
* If there were any registered SYSCTL_SETUP funcs, make sure
* we release the sysctl entries
*/
if (mod->mod_sysctllog) {
sysctl_teardown(&mod->mod_sysctllog);
}
/* Also detach any static evcnt's */
module_unload_evcnt(mod);
fail:
kobj_unload(mod->mod_kobj);
fail2:
if (filedict != NULL) {
prop_object_release(filedict);
filedict = NULL;
}
TAILQ_REMOVE(pending, mod, mod_chain);
SLIST_REMOVE_HEAD(&pend_stack, pe_entry);
module_free(mod);
module_print("Load failed, error %d", error);
return error;
}
/*
* module_do_unload:
*
* Helper routine: do the dirty work of unloading a module.
*/
static int
module_do_unload(const char *name, bool load_requires_force)
{
module_t *mod, *prev_active;
int error;
u_int i;
/*
* module_fetch_into:
*
* Fetch modinfo record from a loaded module.
*/
static int
module_fetch_info(module_t *mod)
{
int error;
void *addr;
size_t size;
/*
* module_find_section:
*
* Allows a module that is being initialized to look up a section
* within its ELF object.
*/
int
module_find_section(const char *name, void **addr, size_t *size)
{
/*
* module_thread:
*
* Automatically unload modules. We try once to unload autoloaded
* modules after module_autotime seconds. If the system is under
* severe memory pressure, we'll try unloading all modules, else if
* module_autotime is zero, we don't try to unload, even if the
* module was previously scheduled for unload.
*/
static void
module_thread(void *cookie)
{
module_t *mod, *next;
modinfo_t *mi;
int error;
for (;;) {
kernconfig_lock();
for (mod = TAILQ_FIRST(&module_list); mod != NULL; mod = next) {
next = TAILQ_NEXT(mod, mod_chain);
/* skip built-in modules */
if (mod->mod_source == MODULE_SOURCE_KERNEL)
continue;
/* skip modules that weren't auto-loaded */
if (!ISSET(mod->mod_flags, MODFLG_AUTO_LOADED))
continue;
/*
* Ask the module if it can be safely unloaded.
*
* - Modules which have been audited to be OK
* with that will return 0.
*
* - Modules which have not been audited for
* safe autounload will return ENOTTY.
*
* => With kern.module.autounload_unsafe=1,
* we treat ENOTTY as acceptance.
*
* - Some modules would ping-ping in and out
* because their use is transient but often.
* Example: exec_script. Other modules may
* still be in use. These modules can
* prevent autounload in all cases by
* returning EBUSY or some other error code.
*/
mi = mod->mod_info;
error = (*mi->mi_modcmd)(MODULE_CMD_AUTOUNLOAD, NULL);
if (error == 0 ||
(error == ENOTTY && module_autounload_unsafe)) {
module_print("Requesting autounload for"
"`%s'", mi->mi_name);
(void)module_do_unload(mi->mi_name, false);
} else
module_print("Module `%s' declined to be "
"auto-unloaded error=%d", mi->mi_name,
error);
}
kernconfig_unlock();
/*
* module_register_callbacks:
*
* Register a new set of callbacks to be called on module load/unload.
* Call the load callback on each existing module.
* Return an opaque handle for unregistering these later.
*/
void *
module_register_callbacks(void (*load)(struct module *),
void (*unload)(struct module *))
{
struct module_callbacks *modcb;
struct module *mod;