- Update section headers before the respective relocations to not

trigger a safety check in elftoolchain's implementation of libelf
 
 - Do not add garbage data to the .rela.orc_unwind_ip section
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmFr+qQACgkQEsHwGGHe
 VUqYCxAAqkHYOu4ok1t0ZUePJSDNFXbMNEq8gfb9gY4zQfsk80eE40EUeZhaqyvq
 a4JHKJSMus+towDB+Zpy1s3ZEfT8V2leZCjMsIS4yIy/dLHPC3TCL4kS1CVlpw0U
 funRhy4FkeiY2Un7ghvhvqSM9l9Dnw3TqxhGUZ0LcdlUaPIKIwzFhHvEVmZsXRFM
 cccz5F/r0yeg7r4TbGtTAmxpKSIsx4BaFqf/LICaLrWGo3pDVGlhn9sPflzv1vue
 rlR4Lb1NKKCaQTefFmLdEpV7FCiJ0QXeoZNGCJlk9NHZyGoNSRfkVSZRDGt/fb5A
 aKfaDvrimgALDB4naWSEplC3slVp9Z2+TpS2zHyqDchGnHIAyx9E6MSOt9F0fs//
 DSv83K2j18rRvmnOPsZoy2pySqtMULohIPECPHOtdZ1y+PwhD/FpSNtO51t/hig5
 2cPq8DnVycJiXM7VQpTcNXv+M2tZ2IZ/E3g8SHJCNSlGZ73YmZdiO2ZTmXGRPnmx
 Xq8gFl/nomMFQSdv6H+nlSy0EA5C3dWqa3pwtKBNrZ8mGAsrEZ2Ptl1TSKfjs28x
 tI7KTeZouxA2NlggBllgOFzm5HSSq+4S6l/gWjuR0yu7j2Kpha+UZUaXZHKHt+OU
 iFZ6BlITsFEE+cd2Nns2rTJjsjN08j/AfNJOGcjtiFVUjHeCc24=
 =tiWi
 -----END PGP SIGNATURE-----

Merge tag 'objtool_urgent_for_v5.15_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool fixes from Borislav Petkov:

 - Update section headers before the respective relocations to not
   trigger a safety check in elftoolchain's implementation of libelf

 - Do not add garbage data to the .rela.orc_unwind_ip section

* tag 'objtool_urgent_for_v5.15_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  objtool: Update section header before relocations
  objtool: Check for gelf_update_rel[a] failures
This commit is contained in:
Linus Torvalds 2021-10-17 17:41:39 -10:00
commit 6890acacde

View File

@ -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); list_add_tail(&reloc->list, &sec->reloc->reloc_list);
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
sec->reloc->sh.sh_size += sec->reloc->sh.sh_entsize;
sec->reloc->changed = true; sec->reloc->changed = true;
return 0; return 0;
@ -977,63 +978,63 @@ 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; struct reloc *reloc;
int idx = 0, size; int idx = 0;
void *buf; void *buf;
/* Allocate a buffer for relocations */ /* Allocate a buffer for relocations */
size = nr * sizeof(GElf_Rel); buf = malloc(sec->sh.sh_size);
buf = malloc(size);
if (!buf) { if (!buf) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
sec->data->d_buf = buf; 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->data->d_type = ELF_T_REL;
sec->sh.sh_size = size;
idx = 0; idx = 0;
list_for_each_entry(reloc, &sec->reloc_list, list) { list_for_each_entry(reloc, &sec->reloc_list, list) {
reloc->rel.r_offset = reloc->offset; reloc->rel.r_offset = reloc->offset;
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
gelf_update_rel(sec->data, idx, &reloc->rel); if (!gelf_update_rel(sec->data, idx, &reloc->rel)) {
WARN_ELF("gelf_update_rel");
return -1;
}
idx++; idx++;
} }
return 0; 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; struct reloc *reloc;
int idx = 0, size; int idx = 0;
void *buf; void *buf;
/* Allocate a buffer for relocations with addends */ /* Allocate a buffer for relocations with addends */
size = nr * sizeof(GElf_Rela); buf = malloc(sec->sh.sh_size);
buf = malloc(size);
if (!buf) { if (!buf) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
sec->data->d_buf = buf; 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->data->d_type = ELF_T_RELA;
sec->sh.sh_size = size;
idx = 0; idx = 0;
list_for_each_entry(reloc, &sec->reloc_list, list) { list_for_each_entry(reloc, &sec->reloc_list, list) {
reloc->rela.r_offset = reloc->offset; reloc->rela.r_offset = reloc->offset;
reloc->rela.r_addend = reloc->addend; reloc->rela.r_addend = reloc->addend;
reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
gelf_update_rela(sec->data, idx, &reloc->rela); if (!gelf_update_rela(sec->data, idx, &reloc->rela)) {
WARN_ELF("gelf_update_rela");
return -1;
}
idx++; idx++;
} }
@ -1042,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) 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) { switch (sec->sh.sh_type) {
case SHT_REL: return elf_rebuild_rel_reloc_section(sec, nr); case SHT_REL: return elf_rebuild_rel_reloc_section(sec);
case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr); case SHT_RELA: return elf_rebuild_rela_reloc_section(sec);
default: return -1; default: return -1;
} }
} }
@ -1111,12 +1105,6 @@ int elf_write(struct elf *elf)
/* Update changed relocation sections and section headers: */ /* Update changed relocation sections and section headers: */
list_for_each_entry(sec, &elf->sections, list) { list_for_each_entry(sec, &elf->sections, list) {
if (sec->changed) { 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); s = elf_getscn(elf->elf, sec->idx);
if (!s) { if (!s) {
WARN_ELF("elf_getscn"); WARN_ELF("elf_getscn");
@ -1127,6 +1115,12 @@ int elf_write(struct elf *elf)
return -1; return -1;
} }
if (sec->base &&
elf_rebuild_reloc_section(elf, sec)) {
WARN("elf_rebuild_reloc_section");
return -1;
}
sec->changed = false; sec->changed = false;
elf->changed = true; elf->changed = true;
} }