Centralize .modinfo detection and property validation.

Signed-off-by: Matthew Maurer <mmau...@google.com>
---
 kernel/module/main.c | 82 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 68 insertions(+), 14 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 6a9159afca02..511d645ac577 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -195,6 +195,38 @@ static unsigned int find_sec(const struct load_info *info, 
const char *name)
        return 0;
 }
 
+/**
+ * find_any_unique_sec() - Find a unique section index by name
+ * @info: Load info for the module to scan
+ * @name: Name of the section we're looking for
+ *
+ * Locates a unique section by name. Ignores SHF_ALLOC.
+ *
+ * Return: Section index if found uniquely, zero if absent, negative count
+ *         of total instances if multiple were found.
+ */
+static int find_any_unique_sec(const struct load_info *info, const char *name)
+{
+       unsigned int idx;
+       unsigned int count = 0;
+       int i;
+
+       for (i = 1; i < info->hdr->e_shnum; i++) {
+               if (strcmp(info->secstrings + info->sechdrs[i].sh_name,
+                          name) == 0) {
+                       count++;
+                       idx = i;
+               }
+       }
+       if (count == 1) {
+               return idx;
+       } else if (count == 0) {
+               return 0;
+       } else {
+               return -count;
+       }
+}
+
 /* Find a module section, or NULL. */
 static void *section_addr(const struct load_info *info, const char *name)
 {
@@ -1854,6 +1886,39 @@ static int elf_validity_cache_secstrings(struct 
load_info *info)
        return 0;
 }
 
+/**
+ * elf_validity_cache_index_info() - Validate and cache modinfo section
+ * @info: Load info to populate the modinfo index on.
+ *        Must have &load_info->sechdrs and &load_info->secstrings populated
+ *
+ * Checks that if there is a .modinfo section, it is unique.
+ * Then, it caches its index in &load_info->index.info.
+ * Finally, it tries to populate the name to improve error messages.
+ *
+ * Return: %0 if valid, %-ENOEXEC if multiple modinfo sections were found.
+ */
+static int elf_validity_cache_index_info(struct load_info *info)
+{
+       int info_idx;
+
+       info_idx = find_any_unique_sec(info, ".modinfo");
+
+       if (info_idx == 0)
+               /* Early return, no .modinfo */
+               return 0;
+
+       if (info_idx < 0) {
+               pr_err("Only one .modinfo section must exist.\n");
+               return -ENOEXEC;
+       }
+
+       info->index.info = info_idx;
+       /* Try to find a name early so we can log errors with a module name */
+       info->name = get_modinfo(info, "name");
+
+       return 0;
+}
+
 /*
  * Check userspace passed ELF module against our expectations, and cache
  * useful variables for further processing as we go.
@@ -1880,13 +1945,15 @@ static int elf_validity_cache_copy(struct load_info 
*info, int flags)
        Elf_Shdr *shdr;
        int err;
        unsigned int num_mod_secs = 0, mod_idx;
-       unsigned int num_info_secs = 0, info_idx;
        unsigned int num_sym_secs = 0, sym_idx;
 
        err = elf_validity_cache_sechdrs(info);
        if (err < 0)
                return err;
        err = elf_validity_cache_secstrings(info);
+       if (err < 0)
+               return err;
+       err = elf_validity_cache_index_info(info);
        if (err < 0)
                return err;
 
@@ -1912,24 +1979,11 @@ static int elf_validity_cache_copy(struct load_info 
*info, int flags)
                                   ".gnu.linkonce.this_module") == 0) {
                                num_mod_secs++;
                                mod_idx = i;
-                       } else if (strcmp(info->secstrings + shdr->sh_name,
-                                  ".modinfo") == 0) {
-                               num_info_secs++;
-                               info_idx = i;
                        }
                        break;
                }
        }
 
-       if (num_info_secs > 1) {
-               pr_err("Only one .modinfo section must exist.\n");
-               goto no_exec;
-       } else if (num_info_secs == 1) {
-               /* Try to find a name early so we can log errors with a module 
name */
-               info->index.info = info_idx;
-               info->name = get_modinfo(info, "name");
-       }
-
        if (num_sym_secs != 1) {
                pr_warn("%s: module has no symbols (stripped?)\n",
                        info->name ?: "(missing .modinfo section or name 
field)");
-- 
2.46.1.824.gd892dcdcdd-goog


Reply via email to