Skip to content

Commit

Permalink
objtool: Update section header before relocations
Browse files Browse the repository at this point in the history
The libelf implementation from elftoolchain has a safety check in
gelf_update_rel[a] to check that the data corresponds to a section
that has type SHT_REL[A] [0]. If the relocation is updated before
the section header is updated with the proper type, this check
fails.

To fix this, update the section header first, before the relocations.
Previously, the section size was calculated in elf_rebuild_reloc_section
by counting the number of entries in the reloc_list. However, we
now need the size during elf_write so instead keep a running total
and add to it for every new relocation.

[0] https://sourceforge.net/p/elftoolchain/mailman/elftoolchain-developers/thread/CAGw6cBtkZro-8wZMD2ULkwJ39J+tHtTtAWXufMjnd3cQ7XG54g@mail.gmail.com/

Signed-off-by: Michael Forney <mforney@mforney.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/r/20210509000103.11008-2-mforney@mforney.org
  • Loading branch information
Michael Forney authored and Josh Poimboeuf committed Oct 7, 2021
1 parent b46179d commit 86e1e05
Showing 1 changed file with 17 additions and 29 deletions.
46 changes: 17 additions & 29 deletions tools/objtool/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
list_add_tail(&reloc->list, &sec->reloc->reloc_list);
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));

sec->reloc->sh.sh_size += sec->reloc->sh.sh_entsize;
sec->reloc->changed = true;

return 0;
Expand Down Expand Up @@ -977,26 +978,23 @@ static struct section *elf_create_reloc_section(struct elf *elf,
}
}

static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
static int elf_rebuild_rel_reloc_section(struct section *sec)
{
struct reloc *reloc;
int idx = 0, size;
int idx = 0;
void *buf;

/* Allocate a buffer for relocations */
size = nr * sizeof(GElf_Rel);
buf = malloc(size);
buf = malloc(sec->sh.sh_size);
if (!buf) {
perror("malloc");
return -1;
}

sec->data->d_buf = buf;
sec->data->d_size = size;
sec->data->d_size = sec->sh.sh_size;
sec->data->d_type = ELF_T_REL;

sec->sh.sh_size = size;

idx = 0;
list_for_each_entry(reloc, &sec->reloc_list, list) {
reloc->rel.r_offset = reloc->offset;
Expand All @@ -1011,26 +1009,23 @@ static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
return 0;
}

static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
static int elf_rebuild_rela_reloc_section(struct section *sec)
{
struct reloc *reloc;
int idx = 0, size;
int idx = 0;
void *buf;

/* Allocate a buffer for relocations with addends */
size = nr * sizeof(GElf_Rela);
buf = malloc(size);
buf = malloc(sec->sh.sh_size);
if (!buf) {
perror("malloc");
return -1;
}

sec->data->d_buf = buf;
sec->data->d_size = size;
sec->data->d_size = sec->sh.sh_size;
sec->data->d_type = ELF_T_RELA;

sec->sh.sh_size = size;

idx = 0;
list_for_each_entry(reloc, &sec->reloc_list, list) {
reloc->rela.r_offset = reloc->offset;
Expand All @@ -1048,16 +1043,9 @@ static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)

static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
{
struct reloc *reloc;
int nr;

nr = 0;
list_for_each_entry(reloc, &sec->reloc_list, list)
nr++;

switch (sec->sh.sh_type) {
case SHT_REL: return elf_rebuild_rel_reloc_section(sec, nr);
case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr);
case SHT_REL: return elf_rebuild_rel_reloc_section(sec);
case SHT_RELA: return elf_rebuild_rela_reloc_section(sec);
default: return -1;
}
}
Expand Down Expand Up @@ -1117,12 +1105,6 @@ int elf_write(struct elf *elf)
/* Update changed relocation sections and section headers: */
list_for_each_entry(sec, &elf->sections, list) {
if (sec->changed) {
if (sec->base &&
elf_rebuild_reloc_section(elf, sec)) {
WARN("elf_rebuild_reloc_section");
return -1;
}

s = elf_getscn(elf->elf, sec->idx);
if (!s) {
WARN_ELF("elf_getscn");
Expand All @@ -1133,6 +1115,12 @@ int elf_write(struct elf *elf)
return -1;
}

if (sec->base &&
elf_rebuild_reloc_section(elf, sec)) {
WARN("elf_rebuild_reloc_section");
return -1;
}

sec->changed = false;
elf->changed = true;
}
Expand Down

0 comments on commit 86e1e05

Please sign in to comment.