module.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:29k
- #include <linux/config.h>
- #include <linux/mm.h>
- #include <linux/module.h>
- #include <asm/module.h>
- #include <asm/uaccess.h>
- #include <linux/vmalloc.h>
- #include <linux/smp_lock.h>
- #include <asm/pgalloc.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/kmod.h>
- #include <linux/seq_file.h>
- /*
- * Originally by Anonymous (as far as I know...)
- * Linux version by Bas Laarhoven <bas@vimec.nl>
- * 0.99.14 version by Jon Tombs <jon@gtex02.us.es>,
- * Heavily modified by Bjorn Ekwall <bj0rn@blox.se> May 1994 (C)
- * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
- * Add MOD_INITIALIZING Keith Owens <kaos@ocs.com.au> Nov 1999
- * Add kallsyms support, Keith Owens <kaos@ocs.com.au> Apr 2000
- * Add asm/module support, IA64 has special requirements. Keith Owens <kaos@ocs.com.au> Sep 2000
- * Fix assorted bugs in module verification. Keith Owens <kaos@ocs.com.au> Sep 2000
- * Fix sys_init_module race, Andrew Morton <andrewm@uow.edu.au> Oct 2000
- * http://www.uwsg.iu.edu/hypermail/linux/kernel/0008.3/0379.html
- * Replace xxx_module_symbol with inter_module_xxx. Keith Owens <kaos@ocs.com.au> Oct 2000
- * Add a module list lock for kernel fault race fixing. Alan Cox <alan@redhat.com>
- *
- * This source is covered by the GNU GPL, the same as all kernel sources.
- */
- #if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
- extern struct module_symbol __start___ksymtab[];
- extern struct module_symbol __stop___ksymtab[];
- extern const struct exception_table_entry __start___ex_table[];
- extern const struct exception_table_entry __stop___ex_table[];
- extern const char __start___kallsyms[] __attribute__ ((weak));
- extern const char __stop___kallsyms[] __attribute__ ((weak));
- struct module kernel_module =
- {
- size_of_struct: sizeof(struct module),
- name: "",
- uc: {ATOMIC_INIT(1)},
- flags: MOD_RUNNING,
- syms: __start___ksymtab,
- ex_table_start: __start___ex_table,
- ex_table_end: __stop___ex_table,
- kallsyms_start: __start___kallsyms,
- kallsyms_end: __stop___kallsyms,
- };
- struct module *module_list = &kernel_module;
- #endif /* defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) */
- /* inter_module functions are always available, even when the kernel is
- * compiled without modules. Consumers of inter_module_xxx routines
- * will always work, even when both are built into the kernel, this
- * approach removes lots of #ifdefs in mainline code.
- */
- static struct list_head ime_list = LIST_HEAD_INIT(ime_list);
- static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED;
- static int kmalloc_failed;
- /*
- * This lock prevents modifications that might race the kernel fault
- * fixups. It does not prevent reader walks that the modules code
- * does. The kernel lock does that.
- *
- * Since vmalloc fault fixups occur in any context this lock is taken
- * irqsave at all times.
- */
-
- spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED;
- /**
- * inter_module_register - register a new set of inter module data.
- * @im_name: an arbitrary string to identify the data, must be unique
- * @owner: module that is registering the data, always use THIS_MODULE
- * @userdata: pointer to arbitrary userdata to be registered
- *
- * Description: Check that the im_name has not already been registered,
- * complain if it has. For new data, add it to the inter_module_entry
- * list.
- */
- void inter_module_register(const char *im_name, struct module *owner, const void *userdata)
- {
- struct list_head *tmp;
- struct inter_module_entry *ime, *ime_new;
- if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
- /* Overloaded kernel, not fatal */
- printk(KERN_ERR
- "Aiee, inter_module_register: cannot kmalloc entry for '%s'n",
- im_name);
- kmalloc_failed = 1;
- return;
- }
- memset(ime_new, 0, sizeof(*ime_new));
- ime_new->im_name = im_name;
- ime_new->owner = owner;
- ime_new->userdata = userdata;
- spin_lock(&ime_lock);
- list_for_each(tmp, &ime_list) {
- ime = list_entry(tmp, struct inter_module_entry, list);
- if (strcmp(ime->im_name, im_name) == 0) {
- spin_unlock(&ime_lock);
- kfree(ime_new);
- /* Program logic error, fatal */
- printk(KERN_ERR "inter_module_register: duplicate im_name '%s'", im_name);
- BUG();
- }
- }
- list_add(&(ime_new->list), &ime_list);
- spin_unlock(&ime_lock);
- }
- /**
- * inter_module_unregister - unregister a set of inter module data.
- * @im_name: an arbitrary string to identify the data, must be unique
- *
- * Description: Check that the im_name has been registered, complain if
- * it has not. For existing data, remove it from the
- * inter_module_entry list.
- */
- void inter_module_unregister(const char *im_name)
- {
- struct list_head *tmp;
- struct inter_module_entry *ime;
- spin_lock(&ime_lock);
- list_for_each(tmp, &ime_list) {
- ime = list_entry(tmp, struct inter_module_entry, list);
- if (strcmp(ime->im_name, im_name) == 0) {
- list_del(&(ime->list));
- spin_unlock(&ime_lock);
- kfree(ime);
- return;
- }
- }
- spin_unlock(&ime_lock);
- if (kmalloc_failed) {
- printk(KERN_ERR
- "inter_module_unregister: no entry for '%s', "
- "probably caused by previous kmalloc failuren",
- im_name);
- return;
- }
- else {
- /* Program logic error, fatal */
- printk(KERN_ERR "inter_module_unregister: no entry for '%s'", im_name);
- BUG();
- }
- }
- /**
- * inter_module_get - return arbitrary userdata from another module.
- * @im_name: an arbitrary string to identify the data, must be unique
- *
- * Description: If the im_name has not been registered, return NULL.
- * Try to increment the use count on the owning module, if that fails
- * then return NULL. Otherwise return the userdata.
- */
- const void *inter_module_get(const char *im_name)
- {
- struct list_head *tmp;
- struct inter_module_entry *ime;
- const void *result = NULL;
- spin_lock(&ime_lock);
- list_for_each(tmp, &ime_list) {
- ime = list_entry(tmp, struct inter_module_entry, list);
- if (strcmp(ime->im_name, im_name) == 0) {
- if (try_inc_mod_count(ime->owner))
- result = ime->userdata;
- break;
- }
- }
- spin_unlock(&ime_lock);
- return(result);
- }
- /**
- * inter_module_get_request - im get with automatic request_module.
- * @im_name: an arbitrary string to identify the data, must be unique
- * @modname: module that is expected to register im_name
- *
- * Description: If inter_module_get fails, do request_module then retry.
- */
- const void *inter_module_get_request(const char *im_name, const char *modname)
- {
- const void *result = inter_module_get(im_name);
- if (!result) {
- request_module(modname);
- result = inter_module_get(im_name);
- }
- return(result);
- }
- /**
- * inter_module_put - release use of data from another module.
- * @im_name: an arbitrary string to identify the data, must be unique
- *
- * Description: If the im_name has not been registered, complain,
- * otherwise decrement the use count on the owning module.
- */
- void inter_module_put(const char *im_name)
- {
- struct list_head *tmp;
- struct inter_module_entry *ime;
- spin_lock(&ime_lock);
- list_for_each(tmp, &ime_list) {
- ime = list_entry(tmp, struct inter_module_entry, list);
- if (strcmp(ime->im_name, im_name) == 0) {
- if (ime->owner)
- __MOD_DEC_USE_COUNT(ime->owner);
- spin_unlock(&ime_lock);
- return;
- }
- }
- spin_unlock(&ime_lock);
- printk(KERN_ERR "inter_module_put: no entry for '%s'", im_name);
- BUG();
- }
- #if defined(CONFIG_MODULES) /* The rest of the source */
- static long get_mod_name(const char *user_name, char **buf);
- static void put_mod_name(char *buf);
- struct module *find_module(const char *name);
- void free_module(struct module *, int tag_freed);
- /*
- * Called at boot time
- */
- void __init init_modules(void)
- {
- kernel_module.nsyms = __stop___ksymtab - __start___ksymtab;
- arch_init_modules(&kernel_module);
- }
- /*
- * Copy the name of a module from user space.
- */
- static inline long
- get_mod_name(const char *user_name, char **buf)
- {
- unsigned long page;
- long retval;
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
- if (retval > 0) {
- if (retval < PAGE_SIZE) {
- *buf = (char *)page;
- return retval;
- }
- retval = -ENAMETOOLONG;
- } else if (!retval)
- retval = -EINVAL;
- free_page(page);
- return retval;
- }
- static inline void
- put_mod_name(char *buf)
- {
- free_page((unsigned long)buf);
- }
- /*
- * Allocate space for a module.
- */
- asmlinkage unsigned long
- sys_create_module(const char *name_user, size_t size)
- {
- char *name;
- long namelen, error;
- struct module *mod;
- unsigned long flags;
- if (!capable(CAP_SYS_MODULE))
- return -EPERM;
- lock_kernel();
- if ((namelen = get_mod_name(name_user, &name)) < 0) {
- error = namelen;
- goto err0;
- }
- if (size < sizeof(struct module)+namelen) {
- error = -EINVAL;
- goto err1;
- }
- if (find_module(name) != NULL) {
- error = -EEXIST;
- goto err1;
- }
- if ((mod = (struct module *)module_map(size)) == NULL) {
- error = -ENOMEM;
- goto err1;
- }
- memset(mod, 0, sizeof(*mod));
- mod->size_of_struct = sizeof(*mod);
- mod->name = (char *)(mod + 1);
- mod->size = size;
- memcpy((char*)(mod+1), name, namelen+1);
- put_mod_name(name);
- spin_lock_irqsave(&modlist_lock, flags);
- mod->next = module_list;
- module_list = mod; /* link it in */
- spin_unlock_irqrestore(&modlist_lock, flags);
- error = (long) mod;
- goto err0;
- err1:
- put_mod_name(name);
- err0:
- unlock_kernel();
- return error;
- }
- /*
- * Initialize a module.
- */
- asmlinkage long
- sys_init_module(const char *name_user, struct module *mod_user)
- {
- struct module mod_tmp, *mod;
- char *name, *n_name, *name_tmp = NULL;
- long namelen, n_namelen, i, error;
- unsigned long mod_user_size;
- struct module_ref *dep;
- if (!capable(CAP_SYS_MODULE))
- return -EPERM;
- lock_kernel();
- if ((namelen = get_mod_name(name_user, &name)) < 0) {
- error = namelen;
- goto err0;
- }
- if ((mod = find_module(name)) == NULL) {
- error = -ENOENT;
- goto err1;
- }
- /* Check module header size. We allow a bit of slop over the
- size we are familiar with to cope with a version of insmod
- for a newer kernel. But don't over do it. */
- if ((error = get_user(mod_user_size, &mod_user->size_of_struct)) != 0)
- goto err1;
- if (mod_user_size < (unsigned long)&((struct module *)0L)->persist_start
- || mod_user_size > sizeof(struct module) + 16*sizeof(void*)) {
- printk(KERN_ERR "init_module: Invalid module header size.n"
- KERN_ERR "A new version of the modutils is likely "
- "needed.n");
- error = -EINVAL;
- goto err1;
- }
- /* Hold the current contents while we play with the user's idea
- of righteousness. */
- mod_tmp = *mod;
- name_tmp = kmalloc(strlen(mod->name) + 1, GFP_KERNEL); /* Where's kstrdup()? */
- if (name_tmp == NULL) {
- error = -ENOMEM;
- goto err1;
- }
- strcpy(name_tmp, mod->name);
- error = copy_from_user(mod, mod_user, mod_user_size);
- if (error) {
- error = -EFAULT;
- goto err2;
- }
- /* Sanity check the size of the module. */
- error = -EINVAL;
- if (mod->size > mod_tmp.size) {
- printk(KERN_ERR "init_module: Size of initialized module "
- "exceeds size of created module.n");
- goto err2;
- }
- /* Make sure all interesting pointers are sane. */
- if (!mod_bound(mod->name, namelen, mod)) {
- printk(KERN_ERR "init_module: mod->name out of bounds.n");
- goto err2;
- }
- if (mod->nsyms && !mod_bound(mod->syms, mod->nsyms, mod)) {
- printk(KERN_ERR "init_module: mod->syms out of bounds.n");
- goto err2;
- }
- if (mod->ndeps && !mod_bound(mod->deps, mod->ndeps, mod)) {
- printk(KERN_ERR "init_module: mod->deps out of bounds.n");
- goto err2;
- }
- if (mod->init && !mod_bound(mod->init, 0, mod)) {
- printk(KERN_ERR "init_module: mod->init out of bounds.n");
- goto err2;
- }
- if (mod->cleanup && !mod_bound(mod->cleanup, 0, mod)) {
- printk(KERN_ERR "init_module: mod->cleanup out of bounds.n");
- goto err2;
- }
- if (mod->ex_table_start > mod->ex_table_end
- || (mod->ex_table_start &&
- !((unsigned long)mod->ex_table_start >= ((unsigned long)mod + mod->size_of_struct)
- && ((unsigned long)mod->ex_table_end
- < (unsigned long)mod + mod->size)))
- || (((unsigned long)mod->ex_table_start
- - (unsigned long)mod->ex_table_end)
- % sizeof(struct exception_table_entry))) {
- printk(KERN_ERR "init_module: mod->ex_table_* invalid.n");
- goto err2;
- }
- if (mod->flags & ~MOD_AUTOCLEAN) {
- printk(KERN_ERR "init_module: mod->flags invalid.n");
- goto err2;
- }
- if (mod_member_present(mod, can_unload)
- && mod->can_unload && !mod_bound(mod->can_unload, 0, mod)) {
- printk(KERN_ERR "init_module: mod->can_unload out of bounds.n");
- goto err2;
- }
- if (mod_member_present(mod, kallsyms_end)) {
- if (mod->kallsyms_end &&
- (!mod_bound(mod->kallsyms_start, 0, mod) ||
- !mod_bound(mod->kallsyms_end, 0, mod))) {
- printk(KERN_ERR "init_module: mod->kallsyms out of bounds.n");
- goto err2;
- }
- if (mod->kallsyms_start > mod->kallsyms_end) {
- printk(KERN_ERR "init_module: mod->kallsyms invalid.n");
- goto err2;
- }
- }
- if (mod_member_present(mod, archdata_end)) {
- if (mod->archdata_end &&
- (!mod_bound(mod->archdata_start, 0, mod) ||
- !mod_bound(mod->archdata_end, 0, mod))) {
- printk(KERN_ERR "init_module: mod->archdata out of bounds.n");
- goto err2;
- }
- if (mod->archdata_start > mod->archdata_end) {
- printk(KERN_ERR "init_module: mod->archdata invalid.n");
- goto err2;
- }
- }
- if (mod_member_present(mod, kernel_data) && mod->kernel_data) {
- printk(KERN_ERR "init_module: mod->kernel_data must be zero.n");
- goto err2;
- }
- /* Check that the user isn't doing something silly with the name. */
- if ((n_namelen = get_mod_name(mod->name - (unsigned long)mod
- + (unsigned long)mod_user,
- &n_name)) < 0) {
- printk(KERN_ERR "init_module: get_mod_name failure.n");
- error = n_namelen;
- goto err2;
- }
- if (namelen != n_namelen || strcmp(n_name, mod_tmp.name) != 0) {
- printk(KERN_ERR "init_module: changed module name to "
- "`%s' from `%s'n",
- n_name, mod_tmp.name);
- goto err3;
- }
- /* Ok, that's about all the sanity we can stomach; copy the rest. */
- if (copy_from_user((char *)mod+mod_user_size,
- (char *)mod_user+mod_user_size,
- mod->size-mod_user_size)) {
- error = -EFAULT;
- goto err3;
- }
- if (module_arch_init(mod))
- goto err3;
- /* On some machines it is necessary to do something here
- to make the I and D caches consistent. */
- flush_icache_range((unsigned long)mod, (unsigned long)mod + mod->size);
- mod->next = mod_tmp.next;
- mod->refs = NULL;
- /* Sanity check the module's dependents */
- for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
- struct module *o, *d = dep->dep;
- /* Make sure the indicated dependencies are really modules. */
- if (d == mod) {
- printk(KERN_ERR "init_module: self-referential "
- "dependency in mod->deps.n");
- goto err3;
- }
- /* Scan the current modules for this dependency */
- for (o = module_list; o != &kernel_module && o != d; o = o->next)
- ;
- if (o != d) {
- printk(KERN_ERR "init_module: found dependency that is "
- "(no longer?) a module.n");
- goto err3;
- }
- }
- /* Update module references. */
- for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
- struct module *d = dep->dep;
- dep->ref = mod;
- dep->next_ref = d->refs;
- d->refs = dep;
- /* Being referenced by a dependent module counts as a
- use as far as kmod is concerned. */
- d->flags |= MOD_USED_ONCE;
- }
- /* Free our temporary memory. */
- put_mod_name(n_name);
- put_mod_name(name);
- /* Initialize the module. */
- atomic_set(&mod->uc.usecount,1);
- mod->flags |= MOD_INITIALIZING;
- if (mod->init && (error = mod->init()) != 0) {
- atomic_set(&mod->uc.usecount,0);
- mod->flags &= ~MOD_INITIALIZING;
- if (error > 0) /* Buggy module */
- error = -EBUSY;
- goto err0;
- }
- atomic_dec(&mod->uc.usecount);
- /* And set it running. */
- mod->flags = (mod->flags | MOD_RUNNING) & ~MOD_INITIALIZING;
- error = 0;
- goto err0;
- err3:
- put_mod_name(n_name);
- err2:
- *mod = mod_tmp;
- strcpy((char *)mod->name, name_tmp); /* We know there is room for this */
- err1:
- put_mod_name(name);
- err0:
- unlock_kernel();
- kfree(name_tmp);
- return error;
- }
- static spinlock_t unload_lock = SPIN_LOCK_UNLOCKED;
- int try_inc_mod_count(struct module *mod)
- {
- int res = 1;
- if (mod) {
- spin_lock(&unload_lock);
- if (mod->flags & MOD_DELETED)
- res = 0;
- else
- __MOD_INC_USE_COUNT(mod);
- spin_unlock(&unload_lock);
- }
- return res;
- }
- asmlinkage long
- sys_delete_module(const char *name_user)
- {
- struct module *mod, *next;
- char *name;
- long error;
- int something_changed;
- if (!capable(CAP_SYS_MODULE))
- return -EPERM;
- lock_kernel();
- if (name_user) {
- if ((error = get_mod_name(name_user, &name)) < 0)
- goto out;
- error = -ENOENT;
- if ((mod = find_module(name)) == NULL) {
- put_mod_name(name);
- goto out;
- }
- put_mod_name(name);
- error = -EBUSY;
- if (mod->refs != NULL)
- goto out;
- spin_lock(&unload_lock);
- if (!__MOD_IN_USE(mod)) {
- mod->flags |= MOD_DELETED;
- spin_unlock(&unload_lock);
- free_module(mod, 0);
- error = 0;
- } else {
- spin_unlock(&unload_lock);
- }
- goto out;
- }
- /* Do automatic reaping */
- restart:
- something_changed = 0;
-
- for (mod = module_list; mod != &kernel_module; mod = next) {
- next = mod->next;
- spin_lock(&unload_lock);
- if (mod->refs == NULL
- && (mod->flags & MOD_AUTOCLEAN)
- && (mod->flags & MOD_RUNNING)
- && !(mod->flags & MOD_DELETED)
- && (mod->flags & MOD_USED_ONCE)
- && !__MOD_IN_USE(mod)) {
- if ((mod->flags & MOD_VISITED)
- && !(mod->flags & MOD_JUST_FREED)) {
- spin_unlock(&unload_lock);
- mod->flags &= ~MOD_VISITED;
- } else {
- mod->flags |= MOD_DELETED;
- spin_unlock(&unload_lock);
- free_module(mod, 1);
- something_changed = 1;
- }
- } else {
- spin_unlock(&unload_lock);
- }
- }
-
- if (something_changed)
- goto restart;
-
- for (mod = module_list; mod != &kernel_module; mod = mod->next)
- mod->flags &= ~MOD_JUST_FREED;
-
- error = 0;
- out:
- unlock_kernel();
- return error;
- }
- /* Query various bits about modules. */
- static int
- qm_modules(char *buf, size_t bufsize, size_t *ret)
- {
- struct module *mod;
- size_t nmod, space, len;
- nmod = space = 0;
- for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
- len = strlen(mod->name)+1;
- if (len > bufsize)
- goto calc_space_needed;
- if (copy_to_user(buf, mod->name, len))
- return -EFAULT;
- buf += len;
- bufsize -= len;
- space += len;
- }
- if (put_user(nmod, ret))
- return -EFAULT;
- else
- return 0;
- calc_space_needed:
- space += len;
- while ((mod = mod->next) != &kernel_module)
- space += strlen(mod->name)+1;
- if (put_user(space, ret))
- return -EFAULT;
- else
- return -ENOSPC;
- }
- static int
- qm_deps(struct module *mod, char *buf, size_t bufsize, size_t *ret)
- {
- size_t i, space, len;
- if (mod == &kernel_module)
- return -EINVAL;
- if (!MOD_CAN_QUERY(mod))
- if (put_user(0, ret))
- return -EFAULT;
- else
- return 0;
- space = 0;
- for (i = 0; i < mod->ndeps; ++i) {
- const char *dep_name = mod->deps[i].dep->name;
- len = strlen(dep_name)+1;
- if (len > bufsize)
- goto calc_space_needed;
- if (copy_to_user(buf, dep_name, len))
- return -EFAULT;
- buf += len;
- bufsize -= len;
- space += len;
- }
- if (put_user(i, ret))
- return -EFAULT;
- else
- return 0;
- calc_space_needed:
- space += len;
- while (++i < mod->ndeps)
- space += strlen(mod->deps[i].dep->name)+1;
- if (put_user(space, ret))
- return -EFAULT;
- else
- return -ENOSPC;
- }
- static int
- qm_refs(struct module *mod, char *buf, size_t bufsize, size_t *ret)
- {
- size_t nrefs, space, len;
- struct module_ref *ref;
- if (mod == &kernel_module)
- return -EINVAL;
- if (!MOD_CAN_QUERY(mod))
- if (put_user(0, ret))
- return -EFAULT;
- else
- return 0;
- space = 0;
- for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
- const char *ref_name = ref->ref->name;
- len = strlen(ref_name)+1;
- if (len > bufsize)
- goto calc_space_needed;
- if (copy_to_user(buf, ref_name, len))
- return -EFAULT;
- buf += len;
- bufsize -= len;
- space += len;
- }
- if (put_user(nrefs, ret))
- return -EFAULT;
- else
- return 0;
- calc_space_needed:
- space += len;
- while ((ref = ref->next_ref) != NULL)
- space += strlen(ref->ref->name)+1;
- if (put_user(space, ret))
- return -EFAULT;
- else
- return -ENOSPC;
- }
- static int
- qm_symbols(struct module *mod, char *buf, size_t bufsize, size_t *ret)
- {
- size_t i, space, len;
- struct module_symbol *s;
- char *strings;
- unsigned long *vals;
- if (!MOD_CAN_QUERY(mod))
- if (put_user(0, ret))
- return -EFAULT;
- else
- return 0;
- space = mod->nsyms * 2*sizeof(void *);
- i = len = 0;
- s = mod->syms;
- if (space > bufsize)
- goto calc_space_needed;
- if (!access_ok(VERIFY_WRITE, buf, space))
- return -EFAULT;
- bufsize -= space;
- vals = (unsigned long *)buf;
- strings = buf+space;
- for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
- len = strlen(s->name)+1;
- if (len > bufsize)
- goto calc_space_needed;
- if (copy_to_user(strings, s->name, len)
- || __put_user(s->value, vals+0)
- || __put_user(space, vals+1))
- return -EFAULT;
- strings += len;
- bufsize -= len;
- space += len;
- }
- if (put_user(i, ret))
- return -EFAULT;
- else
- return 0;
- calc_space_needed:
- for (; i < mod->nsyms; ++i, ++s)
- space += strlen(s->name)+1;
- if (put_user(space, ret))
- return -EFAULT;
- else
- return -ENOSPC;
- }
- static int
- qm_info(struct module *mod, char *buf, size_t bufsize, size_t *ret)
- {
- int error = 0;
- if (mod == &kernel_module)
- return -EINVAL;
- if (sizeof(struct module_info) <= bufsize) {
- struct module_info info;
- info.addr = (unsigned long)mod;
- info.size = mod->size;
- info.flags = mod->flags;
-
- /* usecount is one too high here - report appropriately to
- compensate for locking */
- info.usecount = (mod_member_present(mod, can_unload)
- && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount)-1);
- if (copy_to_user(buf, &info, sizeof(struct module_info)))
- return -EFAULT;
- } else
- error = -ENOSPC;
- if (put_user(sizeof(struct module_info), ret))
- return -EFAULT;
- return error;
- }
- asmlinkage long
- sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
- size_t *ret)
- {
- struct module *mod;
- int err;
- lock_kernel();
- if (name_user == NULL)
- mod = &kernel_module;
- else {
- long namelen;
- char *name;
- if ((namelen = get_mod_name(name_user, &name)) < 0) {
- err = namelen;
- goto out;
- }
- err = -ENOENT;
- if ((mod = find_module(name)) == NULL) {
- put_mod_name(name);
- goto out;
- }
- put_mod_name(name);
- }
- /* __MOD_ touches the flags. We must avoid that */
-
- atomic_inc(&mod->uc.usecount);
-
- switch (which)
- {
- case 0:
- err = 0;
- break;
- case QM_MODULES:
- err = qm_modules(buf, bufsize, ret);
- break;
- case QM_DEPS:
- err = qm_deps(mod, buf, bufsize, ret);
- break;
- case QM_REFS:
- err = qm_refs(mod, buf, bufsize, ret);
- break;
- case QM_SYMBOLS:
- err = qm_symbols(mod, buf, bufsize, ret);
- break;
- case QM_INFO:
- err = qm_info(mod, buf, bufsize, ret);
- break;
- default:
- err = -EINVAL;
- break;
- }
- atomic_dec(&mod->uc.usecount);
-
- out:
- unlock_kernel();
- return err;
- }
- /*
- * Copy the kernel symbol table to user space. If the argument is
- * NULL, just return the size of the table.
- *
- * This call is obsolete. New programs should use query_module+QM_SYMBOLS
- * which does not arbitrarily limit the length of symbols.
- */
- asmlinkage long
- sys_get_kernel_syms(struct kernel_sym *table)
- {
- struct module *mod;
- int i;
- struct kernel_sym ksym;
- lock_kernel();
- for (mod = module_list, i = 0; mod; mod = mod->next) {
- /* include the count for the module name! */
- i += mod->nsyms + 1;
- }
- if (table == NULL)
- goto out;
- /* So that we don't give the user our stack content */
- memset (&ksym, 0, sizeof (ksym));
- for (mod = module_list, i = 0; mod; mod = mod->next) {
- struct module_symbol *msym;
- unsigned int j;
- if (!MOD_CAN_QUERY(mod))
- continue;
- /* magic: write module info as a pseudo symbol */
- ksym.value = (unsigned long)mod;
- ksym.name[0] = '#';
- strncpy(ksym.name+1, mod->name, sizeof(ksym.name)-1);
- ksym.name[sizeof(ksym.name)-1] = ' ';
- if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
- goto out;
- ++i, ++table;
- if (mod->nsyms == 0)
- continue;
- for (j = 0, msym = mod->syms; j < mod->nsyms; ++j, ++msym) {
- ksym.value = msym->value;
- strncpy(ksym.name, msym->name, sizeof(ksym.name));
- ksym.name[sizeof(ksym.name)-1] = ' ';
- if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
- goto out;
- ++i, ++table;
- }
- }
- out:
- unlock_kernel();
- return i;
- }
- /*
- * Look for a module by name, ignoring modules marked for deletion.
- */
- struct module *
- find_module(const char *name)
- {
- struct module *mod;
- for (mod = module_list; mod ; mod = mod->next) {
- if (mod->flags & MOD_DELETED)
- continue;
- if (!strcmp(mod->name, name))
- break;
- }
- return mod;
- }
- /*
- * Free the given module.
- */
- void
- free_module(struct module *mod, int tag_freed)
- {
- struct module_ref *dep;
- unsigned i;
- unsigned long flags;
- /* Let the module clean up. */
- if (mod->flags & MOD_RUNNING)
- {
- if(mod->cleanup)
- mod->cleanup();
- mod->flags &= ~MOD_RUNNING;
- }
- /* Remove the module from the dependency lists. */
- for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
- struct module_ref **pp;
- for (pp = &dep->dep->refs; *pp != dep; pp = &(*pp)->next_ref)
- continue;
- *pp = dep->next_ref;
- if (tag_freed && dep->dep->refs == NULL)
- dep->dep->flags |= MOD_JUST_FREED;
- }
- /* And from the main module list. */
- spin_lock_irqsave(&modlist_lock, flags);
- if (mod == module_list) {
- module_list = mod->next;
- } else {
- struct module *p;
- for (p = module_list; p->next != mod; p = p->next)
- continue;
- p->next = mod->next;
- }
- spin_unlock_irqrestore(&modlist_lock, flags);
- /* And free the memory. */
- module_unmap(mod);
- }
- /*
- * Called by the /proc file system to return a current list of modules.
- */
- int get_module_list(char *p)
- {
- size_t left = PAGE_SIZE;
- struct module *mod;
- char tmpstr[64];
- struct module_ref *ref;
- for (mod = module_list; mod != &kernel_module; mod = mod->next) {
- long len;
- const char *q;
- #define safe_copy_str(str, len)
- do {
- if (left < len)
- goto fini;
- memcpy(p, str, len); p += len, left -= len;
- } while (0)
- #define safe_copy_cstr(str) safe_copy_str(str, sizeof(str)-1)
- len = strlen(mod->name);
- safe_copy_str(mod->name, len);
- if ((len = 20 - len) > 0) {
- if (left < len)
- goto fini;
- memset(p, ' ', len);
- p += len;
- left -= len;
- }
- len = sprintf(tmpstr, "%8lu", mod->size);
- safe_copy_str(tmpstr, len);
- if (mod->flags & MOD_RUNNING) {
- len = sprintf(tmpstr, "%4ld",
- (mod_member_present(mod, can_unload)
- && mod->can_unload
- ? -1L : (long)atomic_read(&mod->uc.usecount)));
- safe_copy_str(tmpstr, len);
- }
- if (mod->flags & MOD_DELETED)
- safe_copy_cstr(" (deleted)");
- else if (mod->flags & MOD_RUNNING) {
- if (mod->flags & MOD_AUTOCLEAN)
- safe_copy_cstr(" (autoclean)");
- if (!(mod->flags & MOD_USED_ONCE))
- safe_copy_cstr(" (unused)");
- }
- else if (mod->flags & MOD_INITIALIZING)
- safe_copy_cstr(" (initializing)");
- else
- safe_copy_cstr(" (uninitialized)");
- if ((ref = mod->refs) != NULL) {
- safe_copy_cstr(" [");
- while (1) {
- q = ref->ref->name;
- len = strlen(q);
- safe_copy_str(q, len);
- if ((ref = ref->next_ref) != NULL)
- safe_copy_cstr(" ");
- else
- break;
- }
- safe_copy_cstr("]");
- }
- safe_copy_cstr("n");
- #undef safe_copy_str
- #undef safe_copy_cstr
- }
- fini:
- return PAGE_SIZE - left;
- }
- /*
- * Called by the /proc file system to return a current list of ksyms.
- */
- struct mod_sym {
- struct module *mod;
- int index;
- };
- /* iterator */
- static void *s_start(struct seq_file *m, loff_t *pos)
- {
- struct mod_sym *p = kmalloc(sizeof(*p), GFP_KERNEL);
- struct module *v;
- loff_t n = *pos;
- if (!p)
- return ERR_PTR(-ENOMEM);
- lock_kernel();
- for (v = module_list, n = *pos; v; n -= v->nsyms, v = v->next) {
- if (n < v->nsyms) {
- p->mod = v;
- p->index = n;
- return p;
- }
- }
- unlock_kernel();
- kfree(p);
- return NULL;
- }
- static void *s_next(struct seq_file *m, void *p, loff_t *pos)
- {
- struct mod_sym *v = p;
- (*pos)++;
- if (++v->index >= v->mod->nsyms) {
- do {
- v->mod = v->mod->next;
- if (!v->mod) {
- unlock_kernel();
- kfree(p);
- return NULL;
- }
- } while (!v->mod->nsyms);
- v->index = 0;
- }
- return p;
- }
- static void s_stop(struct seq_file *m, void *p)
- {
- if (p && !IS_ERR(p)) {
- unlock_kernel();
- kfree(p);
- }
- }
- static int s_show(struct seq_file *m, void *p)
- {
- struct mod_sym *v = p;
- struct module_symbol *sym;
- if (!MOD_CAN_QUERY(v->mod))
- return 0;
- sym = &v->mod->syms[v->index];
- if (*v->mod->name)
- seq_printf(m, "%0*lx %st[%s]n", (int)(2*sizeof(void*)),
- sym->value, sym->name, v->mod->name);
- else
- seq_printf(m, "%0*lx %sn", (int)(2*sizeof(void*)),
- sym->value, sym->name);
- return 0;
- }
- struct seq_operations ksyms_op = {
- start: s_start,
- next: s_next,
- stop: s_stop,
- show: s_show
- };
- #else /* CONFIG_MODULES */
- /* Dummy syscalls for people who don't want modules */
- asmlinkage unsigned long
- sys_create_module(const char *name_user, size_t size)
- {
- return -ENOSYS;
- }
- asmlinkage long
- sys_init_module(const char *name_user, struct module *mod_user)
- {
- return -ENOSYS;
- }
- asmlinkage long
- sys_delete_module(const char *name_user)
- {
- return -ENOSYS;
- }
- asmlinkage long
- sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
- size_t *ret)
- {
- /* Let the program know about the new interface. Not that
- it'll do them much good. */
- if (which == 0)
- return 0;
- return -ENOSYS;
- }
- asmlinkage long
- sys_get_kernel_syms(struct kernel_sym *table)
- {
- return -ENOSYS;
- }
- int try_inc_mod_count(struct module *mod)
- {
- return 1;
- }
- #endif /* CONFIG_MODULES */