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 <andr345@xxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html