Merge tag 'modules-for-v5.4-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / kernel / module.c
index 9ee9342..ff2d735 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/export.h>
 #include <linux/extable.h>
 #include <linux/moduleloader.h>
+#include <linux/module_signature.h>
 #include <linux/trace_events.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
@@ -544,12 +545,20 @@ static const char *kernel_symbol_name(const struct kernel_symbol *sym)
 #endif
 }
 
-static int cmp_name(const void *va, const void *vb)
+static const char *kernel_symbol_namespace(const struct kernel_symbol *sym)
 {
-       const char *a;
-       const struct kernel_symbol *b;
-       a = va; b = vb;
-       return strcmp(a, kernel_symbol_name(b));
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+       if (!sym->namespace_offset)
+               return NULL;
+       return offset_to_ptr(&sym->namespace_offset);
+#else
+       return sym->namespace;
+#endif
+}
+
+static int cmp_name(const void *name, const void *sym)
+{
+       return strcmp(name, kernel_symbol_name(sym));
 }
 
 static bool find_exported_symbol_in_section(const struct symsearch *syms,
@@ -1379,6 +1388,41 @@ static inline int same_magic(const char *amagic, const char *bmagic,
 }
 #endif /* CONFIG_MODVERSIONS */
 
+static char *get_modinfo(const struct load_info *info, const char *tag);
+static char *get_next_modinfo(const struct load_info *info, const char *tag,
+                             char *prev);
+
+static int verify_namespace_is_imported(const struct load_info *info,
+                                       const struct kernel_symbol *sym,
+                                       struct module *mod)
+{
+       const char *namespace;
+       char *imported_namespace;
+
+       namespace = kernel_symbol_namespace(sym);
+       if (namespace) {
+               imported_namespace = get_modinfo(info, "import_ns");
+               while (imported_namespace) {
+                       if (strcmp(namespace, imported_namespace) == 0)
+                               return 0;
+                       imported_namespace = get_next_modinfo(
+                               info, "import_ns", imported_namespace);
+               }
+#ifdef CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
+               pr_warn(
+#else
+               pr_err(
+#endif
+                       "%s: module uses symbol (%s) from namespace %s, but does not import it.\n",
+                       mod->name, kernel_symbol_name(sym), namespace);
+#ifndef CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
+               return -EINVAL;
+#endif
+       }
+       return 0;
+}
+
+
 /* Resolve a symbol for this module.  I.e. if we find one, record usage. */
 static const struct kernel_symbol *resolve_symbol(struct module *mod,
                                                  const struct load_info *info,
@@ -1407,6 +1451,12 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
                goto getname;
        }
 
+       err = verify_namespace_is_imported(info, sym, mod);
+       if (err) {
+               sym = ERR_PTR(err);
+               goto getname;
+       }
+
        err = ref_module(mod, owner);
        if (err) {
                sym = ERR_PTR(err);
@@ -2481,7 +2531,8 @@ static char *next_string(char *string, unsigned long *secsize)
        return string;
 }
 
-static char *get_modinfo(struct load_info *info, const char *tag)
+static char *get_next_modinfo(const struct load_info *info, const char *tag,
+                             char *prev)
 {
        char *p;
        unsigned int taglen = strlen(tag);
@@ -2492,13 +2543,25 @@ static char *get_modinfo(struct load_info *info, const char *tag)
         * get_modinfo() calls made before rewrite_section_headers()
         * must use sh_offset, as sh_addr isn't set!
         */
-       for (p = (char *)info->hdr + infosec->sh_offset; p; p = next_string(p, &size)) {
+       char *modinfo = (char *)info->hdr + infosec->sh_offset;
+
+       if (prev) {
+               size -= prev - modinfo;
+               modinfo = next_string(prev, &size);
+       }
+
+       for (p = modinfo; p; p = next_string(p, &size)) {
                if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
                        return p + taglen + 1;
        }
        return NULL;
 }
 
+static char *get_modinfo(const struct load_info *info, const char *tag)
+{
+       return get_next_modinfo(info, tag, NULL);
+}
+
 static void setup_modinfo(struct module *mod, struct load_info *info)
 {
        struct module_attribute *attr;
@@ -2776,8 +2839,9 @@ static inline void kmemleak_load_module(const struct module *mod,
 #ifdef CONFIG_MODULE_SIG
 static int module_sig_check(struct load_info *info, int flags)
 {
-       int err = -ENOKEY;
+       int err = -ENODATA;
        const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+       const char *reason;
        const void *mod = info->hdr;
 
        /*
@@ -2792,16 +2856,38 @@ static int module_sig_check(struct load_info *info, int flags)
                err = mod_verify_sig(mod, info);
        }
 
-       if (!err) {
+       switch (err) {
+       case 0:
                info->sig_ok = true;
                return 0;
-       }
 
-       /* Not having a signature is only an error if we're strict. */
-       if (err == -ENOKEY && !is_module_sig_enforced())
-               err = 0;
+               /* We don't permit modules to be loaded into trusted kernels
+                * without a valid signature on them, but if we're not
+                * enforcing, certain errors are non-fatal.
+                */
+       case -ENODATA:
+               reason = "Loading of unsigned module";
+               goto decide;
+       case -ENOPKG:
+               reason = "Loading of module with unsupported crypto";
+               goto decide;
+       case -ENOKEY:
+               reason = "Loading of module with unavailable key";
+       decide:
+               if (is_module_sig_enforced()) {
+                       pr_notice("%s is rejected\n", reason);
+                       return -EKEYREJECTED;
+               }
 
-       return err;
+               return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
+
+               /* All other errors are fatal, including nomem, unparseable
+                * signatures and signature check failures - even if signatures
+                * aren't required.
+                */
+       default:
+               return err;
+       }
 }
 #else /* !CONFIG_MODULE_SIG */
 static int module_sig_check(struct load_info *info, int flags)