Skip to content

Commit

Permalink
libkmod: store common section off/size and use them
Browse files Browse the repository at this point in the history
Currently, we repeatedly loop over the elf headers looking for five well
known sections. Just do it once in kmod_elf_new() and reuse the data as
needed.

Note, that not all sections are guaranteed to be available, so calloc()
the struct kmod_elf, so we don't rely on garbage data later on.

Signed-off-by: Emil Velikov <[email protected]>
  • Loading branch information
evelikov committed Oct 24, 2024
1 parent 6e84030 commit 030cf3f
Showing 1 changed file with 85 additions and 29 deletions.
114 changes: 85 additions & 29 deletions libkmod/libkmod-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -339,6 +388,7 @@ struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
}
}

kmod_elf_save_sections(elf);
return elf;

invalid:
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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));
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down

0 comments on commit 030cf3f

Please sign in to comment.