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 check and
ELFDBG print the ones which are missing.

v2: quit looping when found, ELFDBG print missing sections

Signed-off-by: Emil Velikov <[email protected]>
  • Loading branch information
evelikov committed Nov 11, 2024
1 parent 417d273 commit 56cd05d
Showing 1 changed file with 106 additions and 28 deletions.
134 changes: 106 additions & 28 deletions libkmod/libkmod-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ 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,
};

static const char *const section_name_map[] = {
[KMOD_ELF_SECTION_KSYMTAB] = "__ksymtab_strings",
[KMOD_ELF_SECTION_MODINFO] = ".modinfo",
[KMOD_ELF_SECTION_STRTAB] = ".strtab",
[KMOD_ELF_SECTION_SYMTAB] = ".symtab",
[KMOD_ELF_SECTION_VERSIONS] = "__versions",
};

struct kmod_elf {
const uint8_t *memory;
uint64_t size;
Expand All @@ -45,6 +62,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 +269,56 @@ 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)
{
const uint16_t all_sec = (1 << KMOD_ELF_SECTION_MAX) - 1;
uint16_t found_sec = 0;

for (uint16_t i = 1; i < elf->header.section.count && found_sec != all_sec; 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;
found_sec |= 1 << KMOD_ELF_SECTION_KSYMTAB;
continue;
}
if (streq(".modinfo", n)) {
elf->sections[KMOD_ELF_SECTION_MODINFO].offset = off;
elf->sections[KMOD_ELF_SECTION_MODINFO].size = size;
found_sec |= 1 << KMOD_ELF_SECTION_MODINFO;
continue;
}
if (streq(".strtab", n)) {
elf->sections[KMOD_ELF_SECTION_STRTAB].offset = off;
elf->sections[KMOD_ELF_SECTION_STRTAB].size = size;
found_sec |= 1 << KMOD_ELF_SECTION_STRTAB;
continue;
}
if (streq(".symtab", n)) {
elf->sections[KMOD_ELF_SECTION_SYMTAB].offset = off;
elf->sections[KMOD_ELF_SECTION_SYMTAB].size = size;
found_sec |= 1 << KMOD_ELF_SECTION_SYMTAB;
continue;
}
if (streq("__versions", n)) {
elf->sections[KMOD_ELF_SECTION_VERSIONS].offset = off;
elf->sections[KMOD_ELF_SECTION_VERSIONS].size = size;
found_sec |= 1 << KMOD_ELF_SECTION_VERSIONS;
continue;
}
}

for (uint16_t i = 0; !((1 << i) & found_sec) && i < KMOD_ELF_SECTION_MAX; i++) {
ELFDBG(elf, "section %s not found\n", section_name_map[i]);
elf->sections[i].offset = 0;
elf->sections[i].size = 0;
}
}

struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
{
struct kmod_elf *elf;
Expand Down Expand Up @@ -335,6 +406,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 @@ -390,13 +462,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 @@ -486,15 +558,16 @@ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion
size_t off, crclen, namlen, verlen;

Check warning on line 558 in libkmod/libkmod-elf.c

View check run for this annotation

Codecov / codecov/patch

libkmod/libkmod-elf.c#L558

Added line #L558 was not covered by tests
uint64_t sec_off, size;
struct kmod_modversion *a;
int i, count, err;
int i, count;

Check warning on line 561 in libkmod/libkmod-elf.c

View check run for this annotation

Codecov / codecov/patch

libkmod/libkmod-elf.c#L561

Added line #L561 was not covered by tests

elf_get_modversion_lengths(elf, &verlen, &crclen, &namlen);

*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;

Check warning on line 568 in libkmod/libkmod-elf.c

View check run for this annotation

Codecov / codecov/patch

libkmod/libkmod-elf.c#L567-L568

Added lines #L567 - L568 were not covered by tests
if (sec_off == 0)
return -ENODATA;

if (size == 0)
return 0;
Expand Down Expand Up @@ -560,11 +633,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 @@ -645,14 +718,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 @@ -757,16 +831,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 @@ -913,13 +988,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 namlen, 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 @@ -936,14 +1012,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 56cd05d

Please sign in to comment.