From: Ulrich Drepper Date: Sun, 4 Dec 2005 15:51:06 +0000 (+0000) Subject: elflint now checks whether program header entries which must be X-Git-Tag: elfutils-0.120~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=607e05466d3fef5e3ad90aa200d3bba1950cf982;p=thirdparty%2Felfutils.git elflint now checks whether program header entries which must be allocated point to loaded segments. Don't bail out on relocations not expected for file type if they are not loaded. --- diff --git a/NEWS b/NEWS index 11c9b9e85..6ad05f91f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Version 0.118: + +elflint: more tests. + Version 0.117: libdwfl: New function dwfl_module_return_value_location. diff --git a/src/ChangeLog b/src/ChangeLog index 2f7ba0f7e..4c668c231 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,13 @@ +2005-11-28 Ulrich Drepper + + * elflint.c (check_one_reloc): Take additional parameters. Use + them to determine whether relocation is valid in this type of + file. DSOs and executables can contain relocation sections in + unloaded sections which just show the relocations the linker + applied. Adjust all callers. + (check_program_header): Check that PT_PHDR is loaded and that offset + matches the one in the ELF header. + 2005-10-26 Roland McGrath * nm.c (get_var_range): dwarf_getloclist -> dwarf_getlocation. diff --git a/src/elflint.c b/src/elflint.c index cf0f3ca44..227a463cd 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -1129,8 +1129,9 @@ enum load_state static void -check_one_reloc (Ebl *ebl, int idx, size_t cnt, const GElf_Shdr *symshdr, - Elf_Data *symdata, GElf_Addr r_offset, GElf_Xword r_info, +check_one_reloc (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *relshdr, int idx, + size_t cnt, const GElf_Shdr *symshdr, Elf_Data *symdata, + GElf_Addr r_offset, GElf_Xword r_info, const GElf_Shdr *destshdr, bool reldyn, struct loaded_segment *loaded, enum load_state *statep) { @@ -1139,7 +1140,12 @@ check_one_reloc (Ebl *ebl, int idx, size_t cnt, const GElf_Shdr *symshdr, if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (r_info))) ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"), idx, section_name (ebl, idx), cnt); - else if (!ebl_reloc_valid_use (ebl, GELF_R_TYPE (r_info))) + else if (((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + /* The executable/DSO can contain relocation sections with + all the relocations the linker has applied. Those sections + are marked non-loaded, though. */ + || (relshdr->sh_flags & SHF_ALLOC) != 0) + && !ebl_reloc_valid_use (ebl, GELF_R_TYPE (r_info))) ERROR (gettext ("\ section [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"), idx, section_name (ebl, idx), cnt); @@ -1270,8 +1276,9 @@ section [%2d] '%s': cannot get relocation %zu: %s\n"), continue; } - check_one_reloc (ebl, idx, cnt, symshdr, symdata, rela->r_offset, - rela->r_info, destshdr, reldyn, loaded, &state); + check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata, + rela->r_offset, rela->r_info, destshdr, reldyn, loaded, + &state); } while (loaded != NULL) @@ -1319,8 +1326,9 @@ section [%2d] '%s': cannot get relocation %zu: %s\n"), continue; } - check_one_reloc (ebl, idx, cnt, symshdr, symdata, rel->r_offset, - rel->r_info, destshdr, reldyn, loaded, &state); + check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata, + rel->r_offset, rel->r_info, destshdr, reldyn, loaded, + &state); } while (loaded != NULL) @@ -1337,7 +1345,7 @@ static int ndynamic; static void -check_dynamic (Ebl *ebl, GElf_Shdr *shdr, int idx) +check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) { Elf_Data *data; GElf_Shdr strshdr_mem; @@ -1484,6 +1492,56 @@ section [%2d] '%s': entry %zu: DT_PLTREL value must be DT_REL or DT_RELA\n"), pltreladdr = dyn->d_un.d_ptr; if (dyn->d_tag == DT_PLTRELSZ) pltrelsz = dyn->d_un.d_val; + + /* Check that addresses for entries are in loaded segments. */ + switch (dyn->d_tag) + { + size_t n; + default: + if (dyn->d_tag < DT_ADDRRNGLO || dyn->d_tag > DT_ADDRRNGHI) + /* Value is no pointer. */ + break; + /* FALLTHROUGH */ + + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_SONAME: + case DT_RPATH: + case DT_SYMBOLIC: + case DT_REL: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_RUNPATH: + case DT_VERSYM: + case DT_VERDEF: + case DT_VERNEED: + case DT_AUXILIARY: + case DT_FILTER: + for (n = 0; n < ehdr->e_phnum; ++n) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (ebl->elf, n, &phdr_mem); + if (phdr != NULL && phdr->p_type == PT_LOAD + && phdr->p_vaddr <= dyn->d_un.d_ptr + && phdr->p_vaddr + phdr->p_memsz > dyn->d_un.d_ptr) + break; + } + if (unlikely (n >= ehdr->e_phnum)) + { + char buf[50]; + ERROR (gettext ("\ +section [%2d] '%s': entry %zu: %s value must point into loaded segment\n"), + idx, section_name (ebl, idx), cnt, + ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, + sizeof (buf))); + } + } } for (cnt = 1; cnt < DT_NUM; ++cnt) @@ -2832,7 +2890,7 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"), break; case SHT_DYNAMIC: - check_dynamic (ebl, shdr, cnt); + check_dynamic (ebl, ehdr, shdr, cnt); break; case SHT_SYMTAB_SHNDX: @@ -3177,8 +3235,36 @@ loadable segment GNU_RELRO applies to is executable\n")); if (inner >= ehdr->e_phnum) ERROR (gettext ("\ -GNU_RELRO segment not contained in a loaded segment\n")); +%s segment not contained in a loaded segment\n"), "GNU_RELRO"); + } + } + else if (phdr->p_type == PT_PHDR) + { + /* Check that the region is in a writable segment. */ + int inner; + for (inner = 0; inner < ehdr->e_phnum; ++inner) + { + GElf_Phdr phdr2_mem; + GElf_Phdr *phdr2; + + phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem); + if (phdr2 != NULL + && phdr2->p_type == PT_LOAD + && phdr->p_vaddr >= phdr2->p_vaddr + && (phdr->p_vaddr + phdr->p_memsz + <= phdr2->p_vaddr + phdr2->p_memsz)) + break; } + + if (inner >= ehdr->e_phnum) + ERROR (gettext ("\ +%s segment not contained in a loaded segment\n"), "PHDR"); + + /* Check that offset in segment corresponds to offset in ELF + header. */ + if (phdr->p_offset != ehdr->e_phoff) + ERROR (gettext ("\ +program header offset in ELF header and PHDR entry do not match")); } if (phdr->p_filesz > phdr->p_memsz)