Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module update from Rusty Russell: "Nothing all that exciting; a new module-from-fd syscall for those who want to verify the source of the module (ChromeOS) and/or use standard IMA on it or other security hooks." * tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: MODSIGN: Fix kbuild output when using default extra_certificates MODSIGN: Avoid using .incbin in C source modules: don't hand 0 to vmalloc. module: Remove a extra null character at the top of module->strtab. ASN.1: Use the ASN1_LONG_TAG and ASN1_INDEFINITE_LENGTH constants ASN.1: Define indefinite length marker constant moduleparam: use __UNIQUE_ID() __UNIQUE_ID() MODSIGN: Add modules_sign make target powerpc: add finit_module syscall. ima: support new kernel module syscall add finit_module syscall to asm-generic ARM: add finit_module syscall to ARM security: introduce kernel_module_from_file hook module: add flags arg to sys_finit_module() module: add syscall to load module from fd
This commit is contained in:
565
kernel/module.c
565
kernel/module.c
@@ -21,6 +21,7 @@
|
||||
#include <linux/ftrace_event.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -28,6 +29,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/fcntl.h>
|
||||
@@ -59,6 +61,7 @@
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/fips.h>
|
||||
#include <uapi/linux/module.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
@@ -2279,7 +2282,7 @@ static void layout_symtab(struct module *mod, struct load_info *info)
|
||||
Elf_Shdr *symsect = info->sechdrs + info->index.sym;
|
||||
Elf_Shdr *strsect = info->sechdrs + info->index.str;
|
||||
const Elf_Sym *src;
|
||||
unsigned int i, nsrc, ndst, strtab_size;
|
||||
unsigned int i, nsrc, ndst, strtab_size = 0;
|
||||
|
||||
/* Put symbol section at end of init part of module. */
|
||||
symsect->sh_flags |= SHF_ALLOC;
|
||||
@@ -2290,9 +2293,6 @@ static void layout_symtab(struct module *mod, struct load_info *info)
|
||||
src = (void *)info->hdr + symsect->sh_offset;
|
||||
nsrc = symsect->sh_size / sizeof(*src);
|
||||
|
||||
/* strtab always starts with a nul, so offset 0 is the empty string. */
|
||||
strtab_size = 1;
|
||||
|
||||
/* Compute total space required for the core symbols' strtab. */
|
||||
for (ndst = i = 0; i < nsrc; i++) {
|
||||
if (i == 0 ||
|
||||
@@ -2334,7 +2334,6 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
|
||||
mod->core_symtab = dst = mod->module_core + info->symoffs;
|
||||
mod->core_strtab = s = mod->module_core + info->stroffs;
|
||||
src = mod->symtab;
|
||||
*s++ = 0;
|
||||
for (ndst = i = 0; i < mod->num_symtab; i++) {
|
||||
if (i == 0 ||
|
||||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
|
||||
@@ -2375,7 +2374,7 @@ static void dynamic_debug_remove(struct _ddebug *debug)
|
||||
|
||||
void * __weak module_alloc(unsigned long size)
|
||||
{
|
||||
return size == 0 ? NULL : vmalloc_exec(size);
|
||||
return vmalloc_exec(size);
|
||||
}
|
||||
|
||||
static void *module_alloc_update_bounds(unsigned long size)
|
||||
@@ -2422,18 +2421,17 @@ static inline void kmemleak_load_module(const struct module *mod,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
static int module_sig_check(struct load_info *info,
|
||||
const void *mod, unsigned long *_len)
|
||||
static int module_sig_check(struct load_info *info)
|
||||
{
|
||||
int err = -ENOKEY;
|
||||
unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
|
||||
unsigned long len = *_len;
|
||||
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
|
||||
const void *mod = info->hdr;
|
||||
|
||||
if (len > markerlen &&
|
||||
memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
|
||||
if (info->len > markerlen &&
|
||||
memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
|
||||
/* We truncate the module to discard the signature */
|
||||
*_len -= markerlen;
|
||||
err = mod_verify_sig(mod, _len);
|
||||
info->len -= markerlen;
|
||||
err = mod_verify_sig(mod, &info->len);
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
@@ -2451,59 +2449,107 @@ static int module_sig_check(struct load_info *info,
|
||||
return err;
|
||||
}
|
||||
#else /* !CONFIG_MODULE_SIG */
|
||||
static int module_sig_check(struct load_info *info,
|
||||
void *mod, unsigned long *len)
|
||||
static int module_sig_check(struct load_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* !CONFIG_MODULE_SIG */
|
||||
|
||||
/* Sets info->hdr, info->len and info->sig_ok. */
|
||||
static int copy_and_check(struct load_info *info,
|
||||
const void __user *umod, unsigned long len,
|
||||
const char __user *uargs)
|
||||
/* Sanity checks against invalid binaries, wrong arch, weird elf version. */
|
||||
static int elf_header_check(struct load_info *info)
|
||||
{
|
||||
int err;
|
||||
Elf_Ehdr *hdr;
|
||||
|
||||
if (len < sizeof(*hdr))
|
||||
if (info->len < sizeof(*(info->hdr)))
|
||||
return -ENOEXEC;
|
||||
|
||||
if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
|
||||
|| info->hdr->e_type != ET_REL
|
||||
|| !elf_check_arch(info->hdr)
|
||||
|| info->hdr->e_shentsize != sizeof(Elf_Shdr))
|
||||
return -ENOEXEC;
|
||||
|
||||
if (info->hdr->e_shoff >= info->len
|
||||
|| (info->hdr->e_shnum * sizeof(Elf_Shdr) >
|
||||
info->len - info->hdr->e_shoff))
|
||||
return -ENOEXEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sets info->hdr and info->len. */
|
||||
static int copy_module_from_user(const void __user *umod, unsigned long len,
|
||||
struct load_info *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
info->len = len;
|
||||
if (info->len < sizeof(*(info->hdr)))
|
||||
return -ENOEXEC;
|
||||
|
||||
err = security_kernel_module_from_file(NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Suck in entire file: we'll want most of it. */
|
||||
if ((hdr = vmalloc(len)) == NULL)
|
||||
info->hdr = vmalloc(info->len);
|
||||
if (!info->hdr)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(hdr, umod, len) != 0) {
|
||||
err = -EFAULT;
|
||||
goto free_hdr;
|
||||
if (copy_from_user(info->hdr, umod, info->len) != 0) {
|
||||
vfree(info->hdr);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
err = module_sig_check(info, hdr, &len);
|
||||
if (err)
|
||||
goto free_hdr;
|
||||
|
||||
/* Sanity checks against insmoding binaries or wrong arch,
|
||||
weird elf version */
|
||||
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
|
||||
|| hdr->e_type != ET_REL
|
||||
|| !elf_check_arch(hdr)
|
||||
|| hdr->e_shentsize != sizeof(Elf_Shdr)) {
|
||||
err = -ENOEXEC;
|
||||
goto free_hdr;
|
||||
}
|
||||
|
||||
if (hdr->e_shoff >= len ||
|
||||
hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) {
|
||||
err = -ENOEXEC;
|
||||
goto free_hdr;
|
||||
}
|
||||
|
||||
info->hdr = hdr;
|
||||
info->len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
free_hdr:
|
||||
vfree(hdr);
|
||||
/* Sets info->hdr and info->len. */
|
||||
static int copy_module_from_fd(int fd, struct load_info *info)
|
||||
{
|
||||
struct file *file;
|
||||
int err;
|
||||
struct kstat stat;
|
||||
loff_t pos;
|
||||
ssize_t bytes = 0;
|
||||
|
||||
file = fget(fd);
|
||||
if (!file)
|
||||
return -ENOEXEC;
|
||||
|
||||
err = security_kernel_module_from_file(file);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (stat.size > INT_MAX) {
|
||||
err = -EFBIG;
|
||||
goto out;
|
||||
}
|
||||
info->hdr = vmalloc(stat.size);
|
||||
if (!info->hdr) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
while (pos < stat.size) {
|
||||
bytes = kernel_read(file, pos, (char *)(info->hdr) + pos,
|
||||
stat.size - pos);
|
||||
if (bytes < 0) {
|
||||
vfree(info->hdr);
|
||||
err = bytes;
|
||||
goto out;
|
||||
}
|
||||
if (bytes == 0)
|
||||
break;
|
||||
pos += bytes;
|
||||
}
|
||||
info->len = pos;
|
||||
|
||||
out:
|
||||
fput(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2512,7 +2558,7 @@ static void free_copy(struct load_info *info)
|
||||
vfree(info->hdr);
|
||||
}
|
||||
|
||||
static int rewrite_section_headers(struct load_info *info)
|
||||
static int rewrite_section_headers(struct load_info *info, int flags)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -2540,7 +2586,10 @@ static int rewrite_section_headers(struct load_info *info)
|
||||
}
|
||||
|
||||
/* Track but don't keep modinfo and version sections. */
|
||||
info->index.vers = find_sec(info, "__versions");
|
||||
if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
|
||||
info->index.vers = 0; /* Pretend no __versions section! */
|
||||
else
|
||||
info->index.vers = find_sec(info, "__versions");
|
||||
info->index.info = find_sec(info, ".modinfo");
|
||||
info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
||||
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
||||
@@ -2555,7 +2604,7 @@ static int rewrite_section_headers(struct load_info *info)
|
||||
* Return the temporary module pointer (we'll replace it with the final
|
||||
* one when we move the module sections around).
|
||||
*/
|
||||
static struct module *setup_load_info(struct load_info *info)
|
||||
static struct module *setup_load_info(struct load_info *info, int flags)
|
||||
{
|
||||
unsigned int i;
|
||||
int err;
|
||||
@@ -2566,7 +2615,7 @@ static struct module *setup_load_info(struct load_info *info)
|
||||
info->secstrings = (void *)info->hdr
|
||||
+ info->sechdrs[info->hdr->e_shstrndx].sh_offset;
|
||||
|
||||
err = rewrite_section_headers(info);
|
||||
err = rewrite_section_headers(info, flags);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
@@ -2604,11 +2653,14 @@ static struct module *setup_load_info(struct load_info *info)
|
||||
return mod;
|
||||
}
|
||||
|
||||
static int check_modinfo(struct module *mod, struct load_info *info)
|
||||
static int check_modinfo(struct module *mod, struct load_info *info, int flags)
|
||||
{
|
||||
const char *modmagic = get_modinfo(info, "vermagic");
|
||||
int err;
|
||||
|
||||
if (flags & MODULE_INIT_IGNORE_VERMAGIC)
|
||||
modmagic = NULL;
|
||||
|
||||
/* This is allowed: modprobe --force will invalidate it. */
|
||||
if (!modmagic) {
|
||||
err = try_to_force_load(mod, "bad vermagic");
|
||||
@@ -2738,20 +2790,23 @@ static int move_module(struct module *mod, struct load_info *info)
|
||||
memset(ptr, 0, mod->core_size);
|
||||
mod->module_core = ptr;
|
||||
|
||||
ptr = module_alloc_update_bounds(mod->init_size);
|
||||
/*
|
||||
* The pointer to this block is stored in the module structure
|
||||
* which is inside the block. This block doesn't need to be
|
||||
* scanned as it contains data and code that will be freed
|
||||
* after the module is initialized.
|
||||
*/
|
||||
kmemleak_ignore(ptr);
|
||||
if (!ptr && mod->init_size) {
|
||||
module_free(mod, mod->module_core);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ptr, 0, mod->init_size);
|
||||
mod->module_init = ptr;
|
||||
if (mod->init_size) {
|
||||
ptr = module_alloc_update_bounds(mod->init_size);
|
||||
/*
|
||||
* The pointer to this block is stored in the module structure
|
||||
* which is inside the block. This block doesn't need to be
|
||||
* scanned as it contains data and code that will be freed
|
||||
* after the module is initialized.
|
||||
*/
|
||||
kmemleak_ignore(ptr);
|
||||
if (!ptr) {
|
||||
module_free(mod, mod->module_core);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ptr, 0, mod->init_size);
|
||||
mod->module_init = ptr;
|
||||
} else
|
||||
mod->module_init = NULL;
|
||||
|
||||
/* Transfer each section which specifies SHF_ALLOC */
|
||||
pr_debug("final section addresses:\n");
|
||||
@@ -2844,18 +2899,18 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct module *layout_and_allocate(struct load_info *info)
|
||||
static struct module *layout_and_allocate(struct load_info *info, int flags)
|
||||
{
|
||||
/* Module within temporary copy. */
|
||||
struct module *mod;
|
||||
Elf_Shdr *pcpusec;
|
||||
int err;
|
||||
|
||||
mod = setup_load_info(info);
|
||||
mod = setup_load_info(info, flags);
|
||||
if (IS_ERR(mod))
|
||||
return mod;
|
||||
|
||||
err = check_modinfo(mod, info);
|
||||
err = check_modinfo(mod, info, flags);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
@@ -2942,156 +2997,6 @@ static bool finished_loading(const char *name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allocate and load the module: note that size of section 0 is always
|
||||
zero, and we rely on this for optional sections. */
|
||||
static struct module *load_module(void __user *umod,
|
||||
unsigned long len,
|
||||
const char __user *uargs)
|
||||
{
|
||||
struct load_info info = { NULL, };
|
||||
struct module *mod, *old;
|
||||
long err;
|
||||
|
||||
pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
|
||||
umod, len, uargs);
|
||||
|
||||
/* Copy in the blobs from userspace, check they are vaguely sane. */
|
||||
err = copy_and_check(&info, umod, len, uargs);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/* Figure out module layout, and allocate all the memory. */
|
||||
mod = layout_and_allocate(&info);
|
||||
if (IS_ERR(mod)) {
|
||||
err = PTR_ERR(mod);
|
||||
goto free_copy;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
mod->sig_ok = info.sig_ok;
|
||||
if (!mod->sig_ok)
|
||||
add_taint_module(mod, TAINT_FORCED_MODULE);
|
||||
#endif
|
||||
|
||||
/* Now module is in final location, initialize linked lists, etc. */
|
||||
err = module_unload_init(mod);
|
||||
if (err)
|
||||
goto free_module;
|
||||
|
||||
/* Now we've got everything in the final locations, we can
|
||||
* find optional sections. */
|
||||
find_module_sections(mod, &info);
|
||||
|
||||
err = check_module_license_and_versions(mod);
|
||||
if (err)
|
||||
goto free_unload;
|
||||
|
||||
/* Set up MODINFO_ATTR fields */
|
||||
setup_modinfo(mod, &info);
|
||||
|
||||
/* Fix up syms, so that st_value is a pointer to location. */
|
||||
err = simplify_symbols(mod, &info);
|
||||
if (err < 0)
|
||||
goto free_modinfo;
|
||||
|
||||
err = apply_relocations(mod, &info);
|
||||
if (err < 0)
|
||||
goto free_modinfo;
|
||||
|
||||
err = post_relocation(mod, &info);
|
||||
if (err < 0)
|
||||
goto free_modinfo;
|
||||
|
||||
flush_module_icache(mod);
|
||||
|
||||
/* Now copy in args */
|
||||
mod->args = strndup_user(uargs, ~0UL >> 1);
|
||||
if (IS_ERR(mod->args)) {
|
||||
err = PTR_ERR(mod->args);
|
||||
goto free_arch_cleanup;
|
||||
}
|
||||
|
||||
/* Mark state as coming so strong_try_module_get() ignores us. */
|
||||
mod->state = MODULE_STATE_COMING;
|
||||
|
||||
/* Now sew it into the lists so we can get lockdep and oops
|
||||
* info during argument parsing. No one should access us, since
|
||||
* strong_try_module_get() will fail.
|
||||
* lockdep/oops can run asynchronous, so use the RCU list insertion
|
||||
* function to insert in a way safe to concurrent readers.
|
||||
* The mutex protects against concurrent writers.
|
||||
*/
|
||||
again:
|
||||
mutex_lock(&module_mutex);
|
||||
if ((old = find_module(mod->name)) != NULL) {
|
||||
if (old->state == MODULE_STATE_COMING) {
|
||||
/* Wait in case it fails to load. */
|
||||
mutex_unlock(&module_mutex);
|
||||
err = wait_event_interruptible(module_wq,
|
||||
finished_loading(mod->name));
|
||||
if (err)
|
||||
goto free_arch_cleanup;
|
||||
goto again;
|
||||
}
|
||||
err = -EEXIST;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* This has to be done once we're sure module name is unique. */
|
||||
dynamic_debug_setup(info.debug, info.num_debug);
|
||||
|
||||
/* Find duplicate symbols */
|
||||
err = verify_export_symbols(mod);
|
||||
if (err < 0)
|
||||
goto ddebug;
|
||||
|
||||
module_bug_finalize(info.hdr, info.sechdrs, mod);
|
||||
list_add_rcu(&mod->list, &modules);
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
/* Module is ready to execute: parsing args may do that. */
|
||||
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
|
||||
-32768, 32767, &ddebug_dyndbg_module_param_cb);
|
||||
if (err < 0)
|
||||
goto unlink;
|
||||
|
||||
/* Link in to syfs. */
|
||||
err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
|
||||
if (err < 0)
|
||||
goto unlink;
|
||||
|
||||
/* Get rid of temporary copy. */
|
||||
free_copy(&info);
|
||||
|
||||
/* Done! */
|
||||
trace_module_load(mod);
|
||||
return mod;
|
||||
|
||||
unlink:
|
||||
mutex_lock(&module_mutex);
|
||||
/* Unlink carefully: kallsyms could be walking list. */
|
||||
list_del_rcu(&mod->list);
|
||||
module_bug_cleanup(mod);
|
||||
wake_up_all(&module_wq);
|
||||
ddebug:
|
||||
dynamic_debug_remove(info.debug);
|
||||
unlock:
|
||||
mutex_unlock(&module_mutex);
|
||||
synchronize_sched();
|
||||
kfree(mod->args);
|
||||
free_arch_cleanup:
|
||||
module_arch_cleanup(mod);
|
||||
free_modinfo:
|
||||
free_modinfo(mod);
|
||||
free_unload:
|
||||
module_unload_free(mod);
|
||||
free_module:
|
||||
module_deallocate(mod, &info);
|
||||
free_copy:
|
||||
free_copy(&info);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/* Call module constructors. */
|
||||
static void do_mod_ctors(struct module *mod)
|
||||
{
|
||||
@@ -3104,21 +3009,10 @@ static void do_mod_ctors(struct module *mod)
|
||||
}
|
||||
|
||||
/* This is where the real work happens */
|
||||
SYSCALL_DEFINE3(init_module, void __user *, umod,
|
||||
unsigned long, len, const char __user *, uargs)
|
||||
static int do_init_module(struct module *mod)
|
||||
{
|
||||
struct module *mod;
|
||||
int ret = 0;
|
||||
|
||||
/* Must have permission */
|
||||
if (!capable(CAP_SYS_MODULE) || modules_disabled)
|
||||
return -EPERM;
|
||||
|
||||
/* Do all the hard work */
|
||||
mod = load_module(umod, len, uargs);
|
||||
if (IS_ERR(mod))
|
||||
return PTR_ERR(mod);
|
||||
|
||||
blocking_notifier_call_chain(&module_notify_list,
|
||||
MODULE_STATE_COMING, mod);
|
||||
|
||||
@@ -3188,6 +3082,205 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int may_init_module(void)
|
||||
{
|
||||
if (!capable(CAP_SYS_MODULE) || modules_disabled)
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate and load the module: note that size of section 0 is always
|
||||
zero, and we rely on this for optional sections. */
|
||||
static int load_module(struct load_info *info, const char __user *uargs,
|
||||
int flags)
|
||||
{
|
||||
struct module *mod, *old;
|
||||
long err;
|
||||
|
||||
err = module_sig_check(info);
|
||||
if (err)
|
||||
goto free_copy;
|
||||
|
||||
err = elf_header_check(info);
|
||||
if (err)
|
||||
goto free_copy;
|
||||
|
||||
/* Figure out module layout, and allocate all the memory. */
|
||||
mod = layout_and_allocate(info, flags);
|
||||
if (IS_ERR(mod)) {
|
||||
err = PTR_ERR(mod);
|
||||
goto free_copy;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
mod->sig_ok = info->sig_ok;
|
||||
if (!mod->sig_ok)
|
||||
add_taint_module(mod, TAINT_FORCED_MODULE);
|
||||
#endif
|
||||
|
||||
/* Now module is in final location, initialize linked lists, etc. */
|
||||
err = module_unload_init(mod);
|
||||
if (err)
|
||||
goto free_module;
|
||||
|
||||
/* Now we've got everything in the final locations, we can
|
||||
* find optional sections. */
|
||||
find_module_sections(mod, info);
|
||||
|
||||
err = check_module_license_and_versions(mod);
|
||||
if (err)
|
||||
goto free_unload;
|
||||
|
||||
/* Set up MODINFO_ATTR fields */
|
||||
setup_modinfo(mod, info);
|
||||
|
||||
/* Fix up syms, so that st_value is a pointer to location. */
|
||||
err = simplify_symbols(mod, info);
|
||||
if (err < 0)
|
||||
goto free_modinfo;
|
||||
|
||||
err = apply_relocations(mod, info);
|
||||
if (err < 0)
|
||||
goto free_modinfo;
|
||||
|
||||
err = post_relocation(mod, info);
|
||||
if (err < 0)
|
||||
goto free_modinfo;
|
||||
|
||||
flush_module_icache(mod);
|
||||
|
||||
/* Now copy in args */
|
||||
mod->args = strndup_user(uargs, ~0UL >> 1);
|
||||
if (IS_ERR(mod->args)) {
|
||||
err = PTR_ERR(mod->args);
|
||||
goto free_arch_cleanup;
|
||||
}
|
||||
|
||||
/* Mark state as coming so strong_try_module_get() ignores us. */
|
||||
mod->state = MODULE_STATE_COMING;
|
||||
|
||||
/* Now sew it into the lists so we can get lockdep and oops
|
||||
* info during argument parsing. No one should access us, since
|
||||
* strong_try_module_get() will fail.
|
||||
* lockdep/oops can run asynchronous, so use the RCU list insertion
|
||||
* function to insert in a way safe to concurrent readers.
|
||||
* The mutex protects against concurrent writers.
|
||||
*/
|
||||
again:
|
||||
mutex_lock(&module_mutex);
|
||||
if ((old = find_module(mod->name)) != NULL) {
|
||||
if (old->state == MODULE_STATE_COMING) {
|
||||
/* Wait in case it fails to load. */
|
||||
mutex_unlock(&module_mutex);
|
||||
err = wait_event_interruptible(module_wq,
|
||||
finished_loading(mod->name));
|
||||
if (err)
|
||||
goto free_arch_cleanup;
|
||||
goto again;
|
||||
}
|
||||
err = -EEXIST;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* This has to be done once we're sure module name is unique. */
|
||||
dynamic_debug_setup(info->debug, info->num_debug);
|
||||
|
||||
/* Find duplicate symbols */
|
||||
err = verify_export_symbols(mod);
|
||||
if (err < 0)
|
||||
goto ddebug;
|
||||
|
||||
module_bug_finalize(info->hdr, info->sechdrs, mod);
|
||||
list_add_rcu(&mod->list, &modules);
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
/* Module is ready to execute: parsing args may do that. */
|
||||
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
|
||||
-32768, 32767, &ddebug_dyndbg_module_param_cb);
|
||||
if (err < 0)
|
||||
goto unlink;
|
||||
|
||||
/* Link in to syfs. */
|
||||
err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
|
||||
if (err < 0)
|
||||
goto unlink;
|
||||
|
||||
/* Get rid of temporary copy. */
|
||||
free_copy(info);
|
||||
|
||||
/* Done! */
|
||||
trace_module_load(mod);
|
||||
|
||||
return do_init_module(mod);
|
||||
|
||||
unlink:
|
||||
mutex_lock(&module_mutex);
|
||||
/* Unlink carefully: kallsyms could be walking list. */
|
||||
list_del_rcu(&mod->list);
|
||||
module_bug_cleanup(mod);
|
||||
wake_up_all(&module_wq);
|
||||
ddebug:
|
||||
dynamic_debug_remove(info->debug);
|
||||
unlock:
|
||||
mutex_unlock(&module_mutex);
|
||||
synchronize_sched();
|
||||
kfree(mod->args);
|
||||
free_arch_cleanup:
|
||||
module_arch_cleanup(mod);
|
||||
free_modinfo:
|
||||
free_modinfo(mod);
|
||||
free_unload:
|
||||
module_unload_free(mod);
|
||||
free_module:
|
||||
module_deallocate(mod, info);
|
||||
free_copy:
|
||||
free_copy(info);
|
||||
return err;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(init_module, void __user *, umod,
|
||||
unsigned long, len, const char __user *, uargs)
|
||||
{
|
||||
int err;
|
||||
struct load_info info = { };
|
||||
|
||||
err = may_init_module();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
|
||||
umod, len, uargs);
|
||||
|
||||
err = copy_module_from_user(umod, len, &info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return load_module(&info, uargs, 0);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
|
||||
{
|
||||
int err;
|
||||
struct load_info info = { };
|
||||
|
||||
err = may_init_module();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
|
||||
|
||||
if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
|
||||
|MODULE_INIT_IGNORE_VERMAGIC))
|
||||
return -EINVAL;
|
||||
|
||||
err = copy_module_from_fd(fd, &info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return load_module(&info, uargs, flags);
|
||||
}
|
||||
|
||||
static inline int within(unsigned long addr, void *start, unsigned long size)
|
||||
{
|
||||
return ((void *)addr >= start && (void *)addr < start + size);
|
||||
|
Reference in New Issue
Block a user