📄 module.c
字号:
&& !__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 intqm_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 intqm_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 intqm_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 intqm_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 intqm_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 longsys_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 longsys_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] = '\0'; 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] = '\0'; 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. */voidfree_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 %s\t[%s]\n", (int)(2*sizeof(void*)), sym->value, sym->name, v->mod->name); else seq_printf(m, "%0*lx %s\n", (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 longsys_create_module(const char *name_user, size_t size){ return -ENOSYS;}asmlinkage longsys_init_module(const char *name_user, struct module *mod_user){ return -ENOSYS;}asmlinkage longsys_delete_module(const char *name_user){ return -ENOSYS;}asmlinkage longsys_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 longsys_get_kernel_syms(struct kernel_sym *table){ return -ENOSYS;}int try_inc_mod_count(struct module *mod){ return 1;}#endif /* CONFIG_MODULES */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -