Skip to content

Commit 86e1e05

Browse files
michaelforneyjpoimboe
authored andcommitted
objtool: Update section header before relocations
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 <[email protected]> Reviewed-by: Miroslav Benes <[email protected]> Signed-off-by: Josh Poimboeuf <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b46179d commit 86e1e05

File tree

1 file changed

+17
-29
lines changed

1 file changed

+17
-29
lines changed

tools/objtool/elf.c

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
508508
list_add_tail(&reloc->list, &sec->reloc->reloc_list);
509509
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
510510

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

513514
return 0;
@@ -977,26 +978,23 @@ static struct section *elf_create_reloc_section(struct elf *elf,
977978
}
978979
}
979980

980-
static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
981+
static int elf_rebuild_rel_reloc_section(struct section *sec)
981982
{
982983
struct reloc *reloc;
983-
int idx = 0, size;
984+
int idx = 0;
984985
void *buf;
985986

986987
/* Allocate a buffer for relocations */
987-
size = nr * sizeof(GElf_Rel);
988-
buf = malloc(size);
988+
buf = malloc(sec->sh.sh_size);
989989
if (!buf) {
990990
perror("malloc");
991991
return -1;
992992
}
993993

994994
sec->data->d_buf = buf;
995-
sec->data->d_size = size;
995+
sec->data->d_size = sec->sh.sh_size;
996996
sec->data->d_type = ELF_T_REL;
997997

998-
sec->sh.sh_size = size;
999-
1000998
idx = 0;
1001999
list_for_each_entry(reloc, &sec->reloc_list, list) {
10021000
reloc->rel.r_offset = reloc->offset;
@@ -1011,26 +1009,23 @@ static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
10111009
return 0;
10121010
}
10131011

1014-
static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
1012+
static int elf_rebuild_rela_reloc_section(struct section *sec)
10151013
{
10161014
struct reloc *reloc;
1017-
int idx = 0, size;
1015+
int idx = 0;
10181016
void *buf;
10191017

10201018
/* Allocate a buffer for relocations with addends */
1021-
size = nr * sizeof(GElf_Rela);
1022-
buf = malloc(size);
1019+
buf = malloc(sec->sh.sh_size);
10231020
if (!buf) {
10241021
perror("malloc");
10251022
return -1;
10261023
}
10271024

10281025
sec->data->d_buf = buf;
1029-
sec->data->d_size = size;
1026+
sec->data->d_size = sec->sh.sh_size;
10301027
sec->data->d_type = ELF_T_RELA;
10311028

1032-
sec->sh.sh_size = size;
1033-
10341029
idx = 0;
10351030
list_for_each_entry(reloc, &sec->reloc_list, list) {
10361031
reloc->rela.r_offset = reloc->offset;
@@ -1048,16 +1043,9 @@ static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
10481043

10491044
static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
10501045
{
1051-
struct reloc *reloc;
1052-
int nr;
1053-
1054-
nr = 0;
1055-
list_for_each_entry(reloc, &sec->reloc_list, list)
1056-
nr++;
1057-
10581046
switch (sec->sh.sh_type) {
1059-
case SHT_REL: return elf_rebuild_rel_reloc_section(sec, nr);
1060-
case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr);
1047+
case SHT_REL: return elf_rebuild_rel_reloc_section(sec);
1048+
case SHT_RELA: return elf_rebuild_rela_reloc_section(sec);
10611049
default: return -1;
10621050
}
10631051
}
@@ -1117,12 +1105,6 @@ int elf_write(struct elf *elf)
11171105
/* Update changed relocation sections and section headers: */
11181106
list_for_each_entry(sec, &elf->sections, list) {
11191107
if (sec->changed) {
1120-
if (sec->base &&
1121-
elf_rebuild_reloc_section(elf, sec)) {
1122-
WARN("elf_rebuild_reloc_section");
1123-
return -1;
1124-
}
1125-
11261108
s = elf_getscn(elf->elf, sec->idx);
11271109
if (!s) {
11281110
WARN_ELF("elf_getscn");
@@ -1133,6 +1115,12 @@ int elf_write(struct elf *elf)
11331115
return -1;
11341116
}
11351117

1118+
if (sec->base &&
1119+
elf_rebuild_reloc_section(elf, sec)) {
1120+
WARN("elf_rebuild_reloc_section");
1121+
return -1;
1122+
}
1123+
11361124
sec->changed = false;
11371125
elf->changed = true;
11381126
}

0 commit comments

Comments
 (0)