Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 24 additions & 20 deletions libkmod/libkmod-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ struct kmod_elf {
struct {
struct {
uint64_t offset;
uint16_t count;
uint32_t count;
uint16_t entry_size;
} section;
struct {
uint16_t section; /* index of the strings section */
uint32_t section; /* index of the strings section */
uint64_t size;
uint64_t offset;
} strings;
Expand Down Expand Up @@ -203,28 +203,28 @@ static inline const void *elf_get_mem(const struct kmod_elf *elf, uint64_t offse
* (offset 0 cannot be a valid section offset because ELF header is located there).
*/
static inline uint64_t elf_get_section_header_offset(const struct kmod_elf *elf,
uint16_t idx)
uint32_t idx)
{
assert(idx != SHN_UNDEF);
assert(idx < elf->header.section.count);
if (idx == SHN_UNDEF || idx >= elf->header.section.count) {
ELFDBG(elf, "invalid section number: %" PRIu16 ", last=%" PRIu16 "\n",
ELFDBG(elf, "invalid section number: %" PRIu32 ", last=%" PRIu32 "\n",
idx, elf->header.section.count);
return 0;
}
return elf->header.section.offset +
(uint64_t)(idx * elf->header.section.entry_size);
(uint64_t)idx * elf->header.section.entry_size;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how easy is for the uint16_t * uint16_t overflow to trigger, but let's keep this change as separate commit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since idx is changed in this PR to a uint32_t and the C standard would therefore use unsigned int for the result, it would be possible.

}

static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx,
static inline int elf_get_section_info(const struct kmod_elf *elf, uint32_t idx,
uint64_t *offset, uint64_t *size,
const char **name)
{
uint64_t nameoff;
uint64_t off = elf_get_section_header_offset(elf, idx);

if (off == 0) {
ELFDBG(elf, "no section at %" PRIu16 "\n", idx);
ELFDBG(elf, "no section at %" PRIu32 "\n", idx);
goto fail;
}

Expand Down Expand Up @@ -258,7 +258,7 @@ static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx,
*name = elf_get_mem(elf, elf->header.strings.offset + nameoff);

ELFDBG(elf,
"section=%" PRIu16 " is: offset=%" PRIu64 " size=%" PRIu64 " name=%s\n",
"section=%" PRIu32 " is: offset=%" PRIu64 " size=%" PRIu64 " name=%s\n",
idx, *offset, *size, *name);

return 0;
Expand All @@ -275,7 +275,7 @@ static void kmod_elf_save_sections(struct kmod_elf *elf)
uint16_t found_sec = 0;
enum kmod_elf_section sec;

for (uint16_t i = 1; i < elf->header.section.count && found_sec != all_sec; i++) {
for (uint32_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);
Expand Down Expand Up @@ -364,8 +364,8 @@ struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
#undef READV

ELFDBG(elf,
"section: offset=%" PRIu64 " count=%" PRIu16 " entry_size=%" PRIu16
" strings index=%" PRIu16 "\n",
"section: offset=%" PRIu64 " count=%" PRIu32 " entry_size=%" PRIu16
" strings index=%" PRIu32 "\n",
elf->header.section.offset, elf->header.section.count,
elf->header.section.entry_size, elf->header.strings.section);

Expand All @@ -374,7 +374,11 @@ struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
elf->header.section.entry_size, shdr_size);
goto invalid;
}
shdrs_size = shdr_size * elf->header.section.count;
if (umulsz_overflow(shdr_size, elf->header.section.count, &shdrs_size)) {
ELFDBG(elf, "sections too large: %zu * %" PRIu32 "\n",
shdr_size, elf->header.section.count);
goto invalid;
}
if (!elf_range_valid(elf, elf->header.section.offset, shdrs_size))
goto invalid;

Expand Down Expand Up @@ -412,13 +416,13 @@ const void *kmod_elf_get_memory(const struct kmod_elf *elf)
}

/*
* Returns section index on success, negative value otherwise.
* Returns section index on success, zero otherwise.
* On success, sec_off and sec_size are range checked and valid.
*/
int kmod_elf_get_section(const struct kmod_elf *elf, const char *section,
uint64_t *sec_off, uint64_t *sec_size)
uint32_t kmod_elf_get_section(const struct kmod_elf *elf, const char *section,
uint64_t *sec_off, uint64_t *sec_size)
{
uint16_t i;
uint32_t i;

*sec_off = 0;
*sec_size = 0;
Expand All @@ -437,7 +441,7 @@ int kmod_elf_get_section(const struct kmod_elf *elf, const char *section,
return i;
}

return -ENODATA;
return 0;
}

/* array will be allocated with strings in a single malloc, just free *array */
Expand Down Expand Up @@ -596,11 +600,11 @@ static int elf_strip_versions_section(const struct kmod_elf *elf, uint8_t *chang
uint64_t off, size;
const void *buf;
/* the off and size values are not used, supply them as dummies */
int idx = kmod_elf_get_section(elf, "__versions", &off, &size);
uint32_t idx = kmod_elf_get_section(elf, "__versions", &off, &size);
uint64_t val;

if (idx < 0)
return idx == -ENODATA ? 0 : idx;
if (idx == 0)
return 0;

off = elf_get_section_header_offset(elf, idx);

Expand Down
2 changes: 1 addition & 1 deletion libkmod/libkmod-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ _must_check_ _nonnull_all_ const void *kmod_elf_strip(const struct kmod_elf *elf
* Debug mock lib need to find section ".gnu.linkonce.this_module" in order to
* get modname
*/
_must_check_ _nonnull_all_ int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, uint64_t *sec_off, uint64_t *sec_size);
_must_check_ _nonnull_all_ uint32_t kmod_elf_get_section(const struct kmod_elf *elf, const char *section, uint64_t *sec_off, uint64_t *sec_size);

/* libkmod-signature.c */
struct kmod_signature_info {
Expand Down
5 changes: 3 additions & 2 deletions testsuite/init_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ long init_module(void *mem, unsigned long len, const char *args)
struct kmod_elf *elf;
struct mod *mod;
const void *buf;
uint32_t idx;
uint64_t off;
uint64_t bufsize;
int err;
Expand All @@ -238,12 +239,12 @@ long init_module(void *mem, unsigned long len, const char *args)
if (elf == NULL)
return 0;

err = kmod_elf_get_section(elf, ".gnu.linkonce.this_module", &off, &bufsize);
idx = kmod_elf_get_section(elf, ".gnu.linkonce.this_module", &off, &bufsize);
buf = (const char *)kmod_elf_get_memory(elf) + off;
kmod_elf_unref(elf);

/* We couldn't parse the ELF file. Just exit as if it was successful */
if (err < 0)
if (idx == 0)
return 0;

/* We need to open both 32 and 64 bits module - hack! */
Expand Down