Combines three duplicate and almost-duplicate implementations in
modinfo.c, modprobe.c and moduleops_core.c

The new version gets endianness swapping from the implementation in
modinfo.c and bounds checking from the implementation in modprobe.

Signed-off-by: Andreas Robinson <[email protected]>
---
 elf_core.c       |   43 ++++++++++++++++++++++++++++++
 modinfo.c        |   53 +-------------------------------------
 modprobe.c       |   76 +++---------------------------------------------------
 moduleops_core.c |   21 +-------------
 util.c           |   28 ++++++++++++++++++++
 util.h           |    6 ++++
 6 files changed, 84 insertions(+), 143 deletions(-)
 create mode 100644 elf_core.c

diff --git a/elf_core.c b/elf_core.c
new file mode 100644
index 0000000..1525c36
--- /dev/null
+++ b/elf_core.c
@@ -0,0 +1,43 @@
+void *PERBIT(get_section)(void *file,
+                         unsigned long fsize,
+                         const char *secname,
+                         unsigned long *secsize,
+                         int conv)
+{
+       ElfPERBIT(Ehdr) *hdr;
+       ElfPERBIT(Shdr) *sechdrs;
+       ElfPERBIT(Off) e_shoff;
+       ElfPERBIT(Half) e_shnum, e_shstrndx;
+
+       const char *secnames;
+       unsigned int i;
+
+       if (fsize > 0 && fsize < sizeof(*hdr))
+               return NULL;
+
+       hdr = file;
+       e_shoff = END(hdr->e_shoff, conv);
+       e_shnum = END(hdr->e_shnum, conv);
+       e_shstrndx = END(hdr->e_shstrndx, conv);
+
+       if (fsize > 0 && fsize < e_shoff + e_shnum * sizeof(sechdrs[0]))
+               return NULL;
+
+       sechdrs = file + e_shoff;
+ 
+       if (fsize > 0 && fsize < END(sechdrs[e_shstrndx].sh_offset, conv))
+               return NULL;
+
+       /* Find section by name, return pointer and size. */
+
+       secnames = file + END(sechdrs[e_shstrndx].sh_offset, conv);
+       for (i = 1; i < e_shnum; i++) {
+               if (streq(secnames + END(sechdrs[i].sh_name, conv), secname)) {
+                       *secsize = END(sechdrs[i].sh_size, conv);
+                       return file + END(sechdrs[i].sh_offset, conv);
+               }
+       }
+       *secsize = 0;
+       return NULL;
+}
+
diff --git a/modinfo.c b/modinfo.c
index 81e40f4..07199c2 100644
--- a/modinfo.c
+++ b/modinfo.c
@@ -21,57 +21,6 @@
 #define MODULE_DIR "/lib/modules"
 #endif
 
-static int elf_conv;
-
-#define TO_NATIVE(x) END(x, elf_conv)
-
-static void *get_section32(void *file, unsigned long *size, const char *name)
-{
-       Elf32_Ehdr *hdr = file;
-       Elf32_Shdr *sechdrs = file + TO_NATIVE(hdr->e_shoff);
-       const char *secnames;
-       unsigned int i;
-
-       secnames = file
-               + TO_NATIVE(sechdrs[TO_NATIVE(hdr->e_shstrndx)].sh_offset);
-       for (i = 1; i < TO_NATIVE(hdr->e_shnum); i++)
-               if (streq(secnames + TO_NATIVE(sechdrs[i].sh_name), name)) {
-                       *size = TO_NATIVE(sechdrs[i].sh_size);
-                       return file + TO_NATIVE(sechdrs[i].sh_offset);
-               }
-       return NULL;
-}
-
-static void *get_section64(void *file, unsigned long *size, const char *name)
-{
-       Elf64_Ehdr *hdr = file;
-       Elf64_Shdr *sechdrs = file + TO_NATIVE(hdr->e_shoff);
-       const char *secnames;
-       unsigned int i;
-
-       secnames = file
-               + TO_NATIVE(sechdrs[TO_NATIVE(hdr->e_shstrndx)].sh_offset);
-       for (i = 1; i < TO_NATIVE(hdr->e_shnum); i++)
-               if (streq(secnames + TO_NATIVE(sechdrs[i].sh_name), name)) {
-                       *size = TO_NATIVE(sechdrs[i].sh_size);
-                       return file + TO_NATIVE(sechdrs[i].sh_offset);
-               }
-       return NULL;
-}
-
-static void *get_section(void *file, unsigned long filesize,
-                        unsigned long *size, const char *name)
-{
-       switch (elf_ident(file, filesize, &elf_conv)) {
-       case ELFCLASS32:
-               return get_section32(file, size, name);
-       case ELFCLASS64:
-               return get_section64(file, size, name);
-       default:
-               return NULL;
-       }
-}
-
 struct param
 {
        struct param *next;
@@ -367,7 +316,7 @@ int main(int argc, char *argv[])
                        continue;
                }
 
-               info = get_section(mod, modulesize, &infosize, ".modinfo");
+               info = get_section(mod, modulesize, ".modinfo", &infosize);
                if (!info) {
                        release_file(mod, modulesize);
                        free(filename);
diff --git a/modprobe.c b/modprobe.c
index 9d7153e..c2d0ef6 100644
--- a/modprobe.c
+++ b/modprobe.c
@@ -303,75 +303,6 @@ static void replace_modname(struct module *module,
        warn("Could not find old name in %s to replace!\n", module->filename);
 }
 
-static void *get_section32(void *file,
-                          unsigned long size,
-                          const char *name,
-                          unsigned long *secsize)
-{
-       Elf32_Ehdr *hdr = file;
-       Elf32_Shdr *sechdrs = file + hdr->e_shoff;
-       const char *secnames;
-       unsigned int i;
-
-       /* Too short? */
-       if (size < sizeof(*hdr))
-               return NULL;
-       if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0]))
-               return NULL;
-       if (size < sechdrs[hdr->e_shstrndx].sh_offset)
-               return NULL;
-               
-       secnames = file + sechdrs[hdr->e_shstrndx].sh_offset;
-       for (i = 1; i < hdr->e_shnum; i++)
-               if (streq(secnames + sechdrs[i].sh_name, name)) {
-                       *secsize = sechdrs[i].sh_size;
-                       return file + sechdrs[i].sh_offset;
-               }
-       return NULL;
-}
-
-static void *get_section64(void *file,
-                          unsigned long size,
-                          const char *name,
-                          unsigned long *secsize)
-{
-       Elf64_Ehdr *hdr = file;
-       Elf64_Shdr *sechdrs = file + hdr->e_shoff;
-       const char *secnames;
-       unsigned int i;
-
-       /* Too short? */
-       if (size < sizeof(*hdr))
-               return NULL;
-       if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0]))
-               return NULL;
-       if (size < sechdrs[hdr->e_shstrndx].sh_offset)
-               return NULL;
-               
-       secnames = file + sechdrs[hdr->e_shstrndx].sh_offset;
-       for (i = 1; i < hdr->e_shnum; i++)
-               if (streq(secnames + sechdrs[i].sh_name, name)) {
-                       *secsize = sechdrs[i].sh_size;
-                       return file + sechdrs[i].sh_offset;
-               }
-       return NULL;
-}
-
-static void *get_section(void *file,
-                        unsigned long size,
-                        const char *name,
-                        unsigned long *secsize)
-{
-       switch (elf_ident(file, size, NULL)) {
-       case ELFCLASS32:
-               return get_section32(file, size, name, secsize);
-       case ELFCLASS64:
-               return get_section64(file, size, name, secsize);
-       default:
-               return NULL;
-       }
-}
-
 static void rename_module(struct module *module,
                          void *mod,
                          unsigned long len,
@@ -921,14 +852,15 @@ void dump_modversions(const char *filename, errfn_t error)
        struct modver32_info *info32;
        struct modver64_info *info64;
        int n;
+       int conv;
 
        if (!file) {
                error("%s: %s\n", filename, strerror(errno));
                return;
        }
-       switch (elf_ident(file, size, NULL)) {
+       switch (elf_ident(file, size, &conv)) {
        case ELFCLASS32:
-               info32 = get_section32(file, size, "__versions", &secsize);
+               info32 = get_section32(file, size, "__versions", &secsize, 
conv);
                if (!info32)
                        return;  /* Does not seem to be a kernel module */
                if (secsize % sizeof(struct modver32_info))
@@ -939,7 +871,7 @@ void dump_modversions(const char *filename, errfn_t error)
                break;
 
        case ELFCLASS64:
-               info64 = get_section64(file, size, "__versions", &secsize);
+               info64 = get_section64(file, size, "__versions", &secsize, 
conv);
                if (!info64)
                        return;  /* Does not seem to be a kernel module */
                if (secsize % sizeof(struct modver64_info))
diff --git a/moduleops_core.c b/moduleops_core.c
index d11457e..0313e27 100644
--- a/moduleops_core.c
+++ b/moduleops_core.c
@@ -1,27 +1,10 @@
 /* Load the given section: NULL on error. */
 static void *PERBIT(load_section)(ElfPERBIT(Ehdr) *hdr,
                            const char *secname,
-                           unsigned long *size,
+                           unsigned long *secsize,
                            int conv)
 {
-       ElfPERBIT(Shdr) *sechdrs;
-       unsigned int i;
-       char *secnames;
-
-       /* Grab section headers and strings so we can tell who is who */
-       sechdrs = (void *)hdr + END(hdr->e_shoff, conv);
-       secnames = (void *)hdr
-               + END(sechdrs[END(hdr->e_shstrndx, conv)].sh_offset, conv);
-
-       /* Find the section they want */
-       for (i = 1; i < END(hdr->e_shnum, conv); i++) {
-               if (streq(secnames+END(sechdrs[i].sh_name, conv), secname)) {
-                       *size = END(sechdrs[i].sh_size, conv);
-                       return (void *)hdr + END(sechdrs[i].sh_offset, conv);
-               }
-       }
-       *size = 0;
-       return NULL;
+       return PERBIT(get_section)(hdr, 0, secname, secsize, conv);
 }
 
 static void PERBIT(load_symbols)(struct module *module)
diff --git a/util.c b/util.c
index c4515a4..0ee6064 100644
--- a/util.c
+++ b/util.c
@@ -162,3 +162,31 @@ int elf_ident(void *file, unsigned long fsize, int *conv)
                *conv = native_endianness() != ident[EI_DATA];
        return ident[EI_CLASS];
 }
+
+#define PERBIT(x) x##32
+#define ElfPERBIT(x) Elf32_##x
+#define ELFPERBIT(x) ELF32_##x
+#include "elf_core.c"
+
+#undef PERBIT
+#undef ElfPERBIT
+#undef ELFPERBIT
+#define PERBIT(x) x##64
+#define ElfPERBIT(x) Elf64_##x
+#define ELFPERBIT(x) ELF64_##x
+#include "elf_core.c"
+
+void *get_section(void *file, unsigned long filesize,
+                 const char *secname, unsigned long *secsize)
+{
+       int conv;
+
+       switch (elf_ident(file, filesize, &conv)) {
+       case ELFCLASS32:
+               return get_section32(file, filesize, secname, secsize, conv);
+       case ELFCLASS64:
+               return get_section64(file, filesize, secname, secsize, conv);
+       default:
+               return NULL;
+       }
+}
diff --git a/util.h b/util.h
index b545b3a..c73ad21 100644
--- a/util.h
+++ b/util.h
@@ -31,6 +31,12 @@ static inline void __swap_bytes(const void *src, void *dest, 
unsigned int size)
 int native_endianness(void);
 
 int elf_ident(void *file, unsigned long fsize, int *conv);
+void *get_section(void *file, unsigned long filesize,
+       const char *secname, unsigned long *secsize);
+void *get_section32(void *file, unsigned long filesize,
+       const char *secname, unsigned long *secsize, int conv);
+void *get_section64(void *file, unsigned long filesize,
+       const char *secname, unsigned long *secsize, int conv);
 
 #define streq(a,b) (strcmp((a),(b)) == 0)
 #define strstarts(a,start) (strncmp((a),(start), strlen(start)) == 0)
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-modules" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to