]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - kernel/module.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / kernel / module.c
index 0e54d5bf0097f57954d4848db6a830f5a0bc7072..3d8f126208e3ae04eeff3fd1b1e00044c0e3d0d2 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/string.h>
 #include <linux/mutex.h>
 #include <linux/rculist.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/mmu_context.h>
 #include <linux/license.h>
@@ -313,8 +313,11 @@ struct load_info {
        } index;
 };
 
-/* We require a truly strong try_module_get(): 0 means failure due to
-   ongoing or failed initialization etc. */
+/*
+ * We require a truly strong try_module_get(): 0 means success.
+ * Otherwise an error is returned due to ongoing or failed
+ * initialization etc.
+ */
 static inline int strong_try_module_get(struct module *mod)
 {
        BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);
@@ -330,7 +333,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag,
                                    enum lockdep_ok lockdep_ok)
 {
        add_taint(flag, lockdep_ok);
-       mod->taints |= (1U << flag);
+       set_bit(flag, &mod->taints);
 }
 
 /*
@@ -386,16 +389,16 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const struct kernel_symbol __start___ksymtab_gpl_future[];
 extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
-extern const unsigned long __start___kcrctab[];
-extern const unsigned long __start___kcrctab_gpl[];
-extern const unsigned long __start___kcrctab_gpl_future[];
+extern const s32 __start___kcrctab[];
+extern const s32 __start___kcrctab_gpl[];
+extern const s32 __start___kcrctab_gpl_future[];
 #ifdef CONFIG_UNUSED_SYMBOLS
 extern const struct kernel_symbol __start___ksymtab_unused[];
 extern const struct kernel_symbol __stop___ksymtab_unused[];
 extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
-extern const unsigned long __start___kcrctab_unused[];
-extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const s32 __start___kcrctab_unused[];
+extern const s32 __start___kcrctab_unused_gpl[];
 #endif
 
 #ifndef CONFIG_MODVERSIONS
@@ -494,7 +497,7 @@ struct find_symbol_arg {
 
        /* Output */
        struct module *owner;
-       const unsigned long *crc;
+       const s32 *crc;
        const struct kernel_symbol *sym;
 };
 
@@ -560,7 +563,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,
  * (optional) module which owns it.  Needs preempt disabled or module_mutex. */
 const struct kernel_symbol *find_symbol(const char *name,
                                        struct module **owner,
-                                       const unsigned long **crc,
+                                       const s32 **crc,
                                        bool gplok,
                                        bool warn)
 {
@@ -1138,24 +1141,13 @@ static inline int module_unload_init(struct module *mod)
 static size_t module_flags_taint(struct module *mod, char *buf)
 {
        size_t l = 0;
+       int i;
+
+       for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
+               if (taint_flags[i].module && test_bit(i, &mod->taints))
+                       buf[l++] = taint_flags[i].c_true;
+       }
 
-       if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
-               buf[l++] = 'P';
-       if (mod->taints & (1 << TAINT_OOT_MODULE))
-               buf[l++] = 'O';
-       if (mod->taints & (1 << TAINT_FORCED_MODULE))
-               buf[l++] = 'F';
-       if (mod->taints & (1 << TAINT_CRAP))
-               buf[l++] = 'C';
-       if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
-               buf[l++] = 'E';
-       if (mod->taints & (1 << TAINT_LIVEPATCH))
-               buf[l++] = 'K';
-       /*
-        * TAINT_FORCED_RMMOD: could be added.
-        * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
-        * apply to modules.
-        */
        return l;
 }
 
@@ -1257,23 +1249,17 @@ static int try_to_force_load(struct module *mod, const char *reason)
 }
 
 #ifdef CONFIG_MODVERSIONS
-/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
-static unsigned long maybe_relocated(unsigned long crc,
-                                    const struct module *crc_owner)
+
+static u32 resolve_rel_crc(const s32 *crc)
 {
-#ifdef ARCH_RELOCATES_KCRCTAB
-       if (crc_owner == NULL)
-               return crc - (unsigned long)reloc_start;
-#endif
-       return crc;
+       return *(u32 *)((void *)crc + *crc);
 }
 
 static int check_version(Elf_Shdr *sechdrs,
                         unsigned int versindex,
                         const char *symname,
                         struct module *mod,
-                        const unsigned long *crc,
-                        const struct module *crc_owner)
+                        const s32 *crc)
 {
        unsigned int i, num_versions;
        struct modversion_info *versions;
@@ -1291,13 +1277,19 @@ static int check_version(Elf_Shdr *sechdrs,
                / sizeof(struct modversion_info);
 
        for (i = 0; i < num_versions; i++) {
+               u32 crcval;
+
                if (strcmp(versions[i].name, symname) != 0)
                        continue;
 
-               if (versions[i].crc == maybe_relocated(*crc, crc_owner))
+               if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
+                       crcval = resolve_rel_crc(crc);
+               else
+                       crcval = *crc;
+               if (versions[i].crc == crcval)
                        return 1;
-               pr_debug("Found checksum %lX vs module %lX\n",
-                      maybe_relocated(*crc, crc_owner), versions[i].crc);
+               pr_debug("Found checksum %X vs module %lX\n",
+                        crcval, versions[i].crc);
                goto bad_version;
        }
 
@@ -1315,7 +1307,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
                                          unsigned int versindex,
                                          struct module *mod)
 {
-       const unsigned long *crc;
+       const s32 *crc;
 
        /*
         * Since this should be found in kernel (which can't be removed), no
@@ -1329,8 +1321,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
        }
        preempt_enable();
        return check_version(sechdrs, versindex,
-                            VMLINUX_SYMBOL_STR(module_layout), mod, crc,
-                            NULL);
+                            VMLINUX_SYMBOL_STR(module_layout), mod, crc);
 }
 
 /* First part is kernel version, which we ignore if module has crcs. */
@@ -1348,8 +1339,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
                                unsigned int versindex,
                                const char *symname,
                                struct module *mod,
-                               const unsigned long *crc,
-                               const struct module *crc_owner)
+                               const s32 *crc)
 {
        return 1;
 }
@@ -1376,7 +1366,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
 {
        struct module *owner;
        const struct kernel_symbol *sym;
-       const unsigned long *crc;
+       const s32 *crc;
        int err;
 
        /*
@@ -1391,8 +1381,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
        if (!sym)
                goto unlock;
 
-       if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
-                          owner)) {
+       if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
                sym = ERR_PTR(-EINVAL);
                goto getname;
        }
@@ -1911,6 +1900,9 @@ static void frob_writable_data(const struct module_layout *layout,
 /* livepatching wants to disable read-only so it can frob module. */
 void module_disable_ro(const struct module *mod)
 {
+       if (!rodata_enabled)
+               return;
+
        frob_text(&mod->core_layout, set_memory_rw);
        frob_rodata(&mod->core_layout, set_memory_rw);
        frob_ro_after_init(&mod->core_layout, set_memory_rw);
@@ -1920,6 +1912,9 @@ void module_disable_ro(const struct module *mod)
 
 void module_enable_ro(const struct module *mod, bool after_init)
 {
+       if (!rodata_enabled)
+               return;
+
        frob_text(&mod->core_layout, set_memory_ro);
        frob_rodata(&mod->core_layout, set_memory_ro);
        frob_text(&mod->init_layout, set_memory_ro);
@@ -1952,6 +1947,9 @@ void set_all_modules_text_rw(void)
 {
        struct module *mod;
 
+       if (!rodata_enabled)
+               return;
+
        mutex_lock(&module_mutex);
        list_for_each_entry_rcu(mod, &modules, list) {
                if (mod->state == MODULE_STATE_UNFORMED)
@@ -1968,9 +1966,18 @@ void set_all_modules_text_ro(void)
 {
        struct module *mod;
 
+       if (!rodata_enabled)
+               return;
+
        mutex_lock(&module_mutex);
        list_for_each_entry_rcu(mod, &modules, list) {
-               if (mod->state == MODULE_STATE_UNFORMED)
+               /*
+                * Ignore going modules since it's possible that ro
+                * protection has already been disabled, otherwise we'll
+                * run into protection faults at module deallocation.
+                */
+               if (mod->state == MODULE_STATE_UNFORMED ||
+                       mod->state == MODULE_STATE_GOING)
                        continue;
 
                frob_text(&mod->core_layout, set_memory_ro);
@@ -1981,10 +1988,12 @@ void set_all_modules_text_ro(void)
 
 static void disable_ro_nx(const struct module_layout *layout)
 {
-       frob_text(layout, set_memory_rw);
-       frob_rodata(layout, set_memory_rw);
+       if (rodata_enabled) {
+               frob_text(layout, set_memory_rw);
+               frob_rodata(layout, set_memory_rw);
+               frob_ro_after_init(layout, set_memory_rw);
+       }
        frob_rodata(layout, set_memory_x);
-       frob_ro_after_init(layout, set_memory_rw);
        frob_ro_after_init(layout, set_memory_x);
        frob_writable_data(layout, set_memory_x);
 }
@@ -3709,6 +3718,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
  sysfs_cleanup:
        mod_sysfs_teardown(mod);
  coming_cleanup:
+       mod->state = MODULE_STATE_GOING;
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
        klp_module_going(mod);
@@ -4042,6 +4052,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
 }
 #endif /* CONFIG_KALLSYMS */
 
+/* Maximum number of characters written by module_flags() */
+#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
+
+/* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
 static char *module_flags(struct module *mod, char *buf)
 {
        int bx = 0;
@@ -4086,7 +4100,7 @@ static void m_stop(struct seq_file *m, void *p)
 static int m_show(struct seq_file *m, void *p)
 {
        struct module *mod = list_entry(p, struct module, list);
-       char buf[8];
+       char buf[MODULE_FLAGS_BUF_SIZE];
 
        /* We always ignore unformed modules. */
        if (mod->state == MODULE_STATE_UNFORMED)
@@ -4257,7 +4271,7 @@ EXPORT_SYMBOL_GPL(__module_text_address);
 void print_modules(void)
 {
        struct module *mod;
-       char buf[8];
+       char buf[MODULE_FLAGS_BUF_SIZE];
 
        printk(KERN_DEFAULT "Modules linked in:");
        /* Most callers should already have preempt disabled, but make sure */