diff --git a/libkmod/libkmod-elf.c b/libkmod/libkmod-elf.c index 77b8cb85..e9c6556d 100644 --- a/libkmod/libkmod-elf.c +++ b/libkmod/libkmod-elf.c @@ -27,6 +27,15 @@ struct kmod_modversion64 { char name[64 - sizeof(uint64_t)]; }; +enum kmod_elf_section { + KMOD_ELF_SECTION_KSYMTAB, + KMOD_ELF_SECTION_MODINFO, + KMOD_ELF_SECTION_STRTAB, + KMOD_ELF_SECTION_SYMTAB, + KMOD_ELF_SECTION_VERSIONS, + KMOD_ELF_SECTION_MAX, +}; + struct kmod_elf { const uint8_t *memory; uint64_t size; @@ -45,6 +54,10 @@ struct kmod_elf { } strings; uint16_t machine; } header; + struct { + uint64_t offset; + uint64_t size; + } sections[KMOD_ELF_SECTION_MAX]; }; //#undef ENABLE_ELFDBG @@ -248,6 +261,42 @@ static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx, return -EINVAL; } +static void kmod_elf_save_sections(struct kmod_elf *elf) +{ + for (uint16_t i = 1; i < elf->header.section.count; i++) { + uint64_t off, size; + const char *n; + int err = elf_get_section_info(elf, i, &off, &size, &n); + if (err < 0) + continue; + if (streq("__ksymtab_strings", n)) { + elf->sections[KMOD_ELF_SECTION_KSYMTAB].offset = off; + elf->sections[KMOD_ELF_SECTION_KSYMTAB].size = size; + continue; + } + if (streq(".modinfo", n)) { + elf->sections[KMOD_ELF_SECTION_MODINFO].offset = off; + elf->sections[KMOD_ELF_SECTION_MODINFO].size = size; + continue; + } + if (streq(".strtab", n)) { + elf->sections[KMOD_ELF_SECTION_STRTAB].offset = off; + elf->sections[KMOD_ELF_SECTION_STRTAB].size = size; + continue; + } + if (streq(".symtab", n)) { + elf->sections[KMOD_ELF_SECTION_SYMTAB].offset = off; + elf->sections[KMOD_ELF_SECTION_SYMTAB].size = size; + continue; + } + if (streq("__versions", n)) { + elf->sections[KMOD_ELF_SECTION_VERSIONS].offset = off; + elf->sections[KMOD_ELF_SECTION_VERSIONS].size = size; + continue; + } + } +} + struct kmod_elf *kmod_elf_new(const void *memory, off_t size) { struct kmod_elf *elf; @@ -266,7 +315,7 @@ struct kmod_elf *kmod_elf_new(const void *memory, off_t size) return NULL; } - elf = malloc(sizeof(struct kmod_elf)); + elf = calloc(1, sizeof(struct kmod_elf)); if (elf == NULL) { return NULL; } @@ -339,6 +388,7 @@ struct kmod_elf *kmod_elf_new(const void *memory, off_t size) } } + kmod_elf_save_sections(elf); return elf; invalid: @@ -394,13 +444,13 @@ int kmod_elf_get_modinfo_strings(const struct kmod_elf *elf, char ***array) uint64_t off, size; const char *strings; char *s, **a; - int err; *array = NULL; - err = kmod_elf_get_section(elf, ".modinfo", &off, &size); - if (err < 0) - return err; + off = elf->sections[KMOD_ELF_SECTION_MODINFO].offset; + size = elf->sections[KMOD_ELF_SECTION_MODINFO].size; + if (off == 0) + return -ENODATA; strings = elf_get_mem(elf, off); @@ -470,7 +520,7 @@ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion size_t off, offcrc; uint64_t sec_off, size; struct kmod_modversion *a; - int i, count, err; + int i, count; #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64)) assert_cc(sizeof(struct kmod_modversion64) == sizeof(struct kmod_modversion32)); @@ -482,9 +532,10 @@ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion *array = NULL; - err = kmod_elf_get_section(elf, "__versions", &sec_off, &size); - if (err < 0) - return err; + sec_off = elf->sections[KMOD_ELF_SECTION_VERSIONS].offset; + size = elf->sections[KMOD_ELF_SECTION_VERSIONS].size; + if (sec_off == 0) + return -ENODATA; if (size == 0) return 0; @@ -543,11 +594,11 @@ static int elf_strip_vermagic(const struct kmod_elf *elf, uint8_t *changed) { uint64_t i, sec_off, size; const char *strings; - int err; - err = kmod_elf_get_section(elf, ".modinfo", &sec_off, &size); - if (err < 0) - return err == -ENODATA ? 0 : err; + sec_off = elf->sections[KMOD_ELF_SECTION_MODINFO].offset; + size = elf->sections[KMOD_ELF_SECTION_MODINFO].size; + if (sec_off == 0) + return 0; strings = elf_get_mem(elf, sec_off); /* skip zero padding */ @@ -628,14 +679,15 @@ static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, uint64_t i, last, off, size; const char *strings; struct kmod_modversion *a; - int count, err; + int count; size_t total_size; *array = NULL; - err = kmod_elf_get_section(elf, "__ksymtab_strings", &off, &size); - if (err < 0) - return err; + off = elf->sections[KMOD_ELF_SECTION_KSYMTAB].offset; + size = elf->sections[KMOD_ELF_SECTION_KSYMTAB].size; + if (off == 0) + return -ENODATA; strings = elf_get_mem(elf, off); /* skip zero padding */ @@ -735,16 +787,17 @@ int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **ar uint64_t strtablen, symtablen, str_sec_off, sym_sec_off, str_off, sym_off; struct kmod_modversion *a; size_t i, count, symcount, symlen; - int err; - err = kmod_elf_get_section(elf, ".strtab", &str_sec_off, &strtablen); - if (err < 0) { + str_sec_off = elf->sections[KMOD_ELF_SECTION_STRTAB].offset; + strtablen = elf->sections[KMOD_ELF_SECTION_STRTAB].size; + if (str_sec_off == 0) { ELFDBG(elf, "no .strtab found.\n"); goto fallback; } - err = kmod_elf_get_section(elf, ".symtab", &sym_sec_off, &symtablen); - if (err < 0) { + sym_sec_off = elf->sections[KMOD_ELF_SECTION_SYMTAB].offset; + symtablen = elf->sections[KMOD_ELF_SECTION_SYMTAB].size; + if (sym_sec_off == 0) { ELFDBG(elf, "no .symtab found.\n"); goto fallback; } @@ -897,13 +950,14 @@ int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, uint64_t str_sec_off, sym_sec_off; struct kmod_modversion *a; size_t verlen, symlen, crclen; - int i, count, symcount, vercount, err; + int i, count, symcount, vercount; bool handle_register_symbols; uint8_t *visited_versions; uint64_t *symcrcs; - err = kmod_elf_get_section(elf, "__versions", &ver_off, &versionslen); - if (err < 0) { + ver_off = elf->sections[KMOD_ELF_SECTION_VERSIONS].offset; + versionslen = elf->sections[KMOD_ELF_SECTION_VERSIONS].size; + if (ver_off == 0) { versionslen = 0; verlen = 0; crclen = 0; @@ -927,14 +981,16 @@ int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, } } - err = kmod_elf_get_section(elf, ".strtab", &str_sec_off, &strtablen); - if (err < 0) { + str_sec_off = elf->sections[KMOD_ELF_SECTION_STRTAB].offset; + strtablen = elf->sections[KMOD_ELF_SECTION_STRTAB].size; + if (str_sec_off == 0) { ELFDBG(elf, "no .strtab found.\n"); return -EINVAL; } - err = kmod_elf_get_section(elf, ".symtab", &sym_sec_off, &symtablen); - if (err < 0) { + sym_sec_off = elf->sections[KMOD_ELF_SECTION_SYMTAB].offset; + symtablen = elf->sections[KMOD_ELF_SECTION_SYMTAB].size; + if (sym_sec_off == 0) { ELFDBG(elf, "no .symtab found.\n"); return -EINVAL; }