From f5eac562c915811c27969949c178f8fe96a12e47 Mon Sep 17 00:00:00 2001 From: norly Date: Sun, 26 May 2013 22:16:54 +0100 Subject: [PATCH] Validate input at libelf level This way we can just assume that stuff works later on and keep the code clean and simple. It especially establishes that the file has a sane format and is thus understandable and editable. --- include/libelfu/elfops.h | 2 + include/libelfu/generic.h | 15 +++- src/elfops/check.c | 180 ++++++++++++++++++++++++++++++++++++++ src/model/fromFile.c | 19 ++-- 4 files changed, 209 insertions(+), 7 deletions(-) create mode 100644 src/elfops/check.c diff --git a/include/libelfu/elfops.h b/include/libelfu/elfops.h index 58da4cf..cf40090 100644 --- a/include/libelfu/elfops.h +++ b/include/libelfu/elfops.h @@ -7,6 +7,8 @@ #include +int elfu_eCheck(Elf *e); + char* elfu_eScnName(Elf *e, Elf_Scn *scn); Elf_Scn* elfu_eScnByName(Elf *e, char *name); diff --git a/include/libelfu/generic.h b/include/libelfu/generic.h index f5b0e0f..09d2ffc 100644 --- a/include/libelfu/generic.h +++ b/include/libelfu/generic.h @@ -3,9 +3,22 @@ #include +#define OFFS_END(off, sz) ((off) + (sz)) + +#define OVERLAPPING(off1, sz1, off2, sz2) \ + (!((off1) == (off2) && ((sz1 == 0) || (sz2 == 0))) \ + && (((off1) <= (off2) && (off2) < OFFS_END((off1), (sz1))) \ + || ((off2) <= (off1) && (off1) < OFFS_END((off2), (sz2)))) \ + ) + +#define FULLY_OVERLAPPING(off1, sz1, off2, sz2) \ + (((off1) <= (off2) && OFFS_END((off2), (sz2)) <= OFFS_END((off1), (sz1))) \ + || ((off2) <= (off1) && OFFS_END((off1), (sz1)) <= OFFS_END((off2), (sz2)))) + -size_t elfu_gScnSizeFile(const GElf_Shdr *shdr); int elfu_gPhdrContainsScn(GElf_Phdr *phdr, GElf_Shdr *shdr); +size_t elfu_gScnSizeFile(const GElf_Shdr *shdr); + #endif diff --git a/src/elfops/check.c b/src/elfops/check.c new file mode 100644 index 0000000..c7ebc7d --- /dev/null +++ b/src/elfops/check.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include + +int elfu_eCheck(Elf *e) +{ + int elfclass; + GElf_Ehdr ehdr; + GElf_Phdr *phdrs = NULL; + GElf_Shdr *shdrs = NULL; + size_t i, j, numPhdr, numShdr; + int retval = 0; + + assert(e); + + elfclass = gelf_getclass(e); + if (elfclass == ELFCLASSNONE) { + ELFU_WARNELF("getclass"); + goto ERROR; + } + + if (!gelf_getehdr(e, &ehdr)) { + ELFU_WARNELF("gelf_getehdr"); + goto ERROR; + } + + if (elf_getphdrnum(e, &numPhdr)) { + ELFU_WARNELF("elf_getphdrnum"); + goto ERROR; + } + + if (elf_getshdrnum(e, &numShdr)) { + ELFU_WARNELF("elf_getshdrnum"); + goto ERROR; + } + + + if (numPhdr > 0) { + phdrs = malloc(numPhdr * sizeof(GElf_Phdr)); + if (!phdrs) { + ELFU_WARN("elfu_eCheck: malloc() failed for phdrs.\n"); + goto ERROR; + } + + /* Attempt to load all PHDRs at once to catch any errors early */ + for (i = 0; i < numPhdr; i++) { + GElf_Phdr phdr; + if (gelf_getphdr(e, i, &phdr) != &phdr) { + ELFU_WARN("gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1)); + goto ERROR; + } + + phdrs[i] = phdr; + } + + /* Check that LOAD PHDR memory ranges do not overlap, and that others + * are either fully contained in a LOAD range, or not at all. */ + for (i = 0; i < numPhdr; i++) { + if (phdrs[i].p_type != PT_LOAD) { + continue; + } + + for (j = 0; j < numPhdr; j++) { + if (j == i || phdrs[j].p_type != PT_LOAD) { + continue; + } + + if (OVERLAPPING(phdrs[i].p_vaddr, phdrs[i].p_memsz, + phdrs[j].p_vaddr, phdrs[j].p_memsz)) { + if (phdrs[j].p_type == PT_LOAD) { + ELFU_WARN("elfu_eCheck: Found LOAD PHDRs that overlap in memory.\n"); + goto ERROR; + } else if (!FULLY_OVERLAPPING(phdrs[i].p_vaddr, phdrs[i].p_memsz, + phdrs[j].p_vaddr, phdrs[j].p_memsz)) { + ELFU_WARN("elfu_eCheck: PHDRs %d and %d partially overlap in memory.\n", i, j); + goto ERROR; + } + } + } + } + } + + + if (numShdr > 1) { + /* SHDRs should not overlap with PHDRs. */ + if (OVERLAPPING(ehdr.e_shoff, numShdr * ehdr.e_shentsize, + ehdr.e_phoff, numPhdr * ehdr.e_phentsize)) { + ELFU_WARN("elfu_eCheck: SHDRs overlap with PHDRs.\n"); + goto ERROR; + } + + shdrs = malloc(numShdr * sizeof(GElf_Shdr)); + if (!shdrs) { + ELFU_WARN("elfu_eCheck: malloc() failed for shdrs.\n"); + goto ERROR; + } + + /* Attempt to load all SHDRs at once to catch any errors early */ + for (i = 1; i < numShdr; i++) { + Elf_Scn *scn; + GElf_Shdr shdr; + + scn = elf_getscn(e, i); + if (!scn) { + ELFU_WARN("elf_getscn() failed for #%d: %s\n", i, elf_errmsg(-1)); + } + + if (gelf_getshdr(scn, &shdr) != &shdr) { + ELFU_WARNELF("gelf_getshdr"); + goto ERROR; + } + + shdrs[i] = shdr; + } + + + /* Check that Section memory ranges do not overlap. + * NB: Section 0 is reserved and thus ignored. */ + for (i = 1; i < numShdr; i++) { + /* Section should not overlap with EHDR. */ + if (shdrs[i].sh_offset == 0) { + ELFU_WARN("elfu_eCheck: Section %d overlaps with EHDR.\n", i); + goto ERROR; + } + + /* Section should not overlap with PHDRs. */ + if (OVERLAPPING(shdrs[i].sh_offset, elfu_gScnSizeFile(&shdrs[i]), + ehdr.e_phoff, numPhdr * ehdr.e_phentsize)) { + ELFU_WARN("elfu_eCheck: Section %d overlaps with PHDR.\n", i); + goto ERROR; + } + + /* Section should not overlap with SHDRs. */ + if (OVERLAPPING(shdrs[i].sh_offset, elfu_gScnSizeFile(&shdrs[i]), + ehdr.e_shoff, numShdr * ehdr.e_shentsize)) { + ELFU_WARN("elfu_eCheck: Section %d overlaps with SHDRs.\n", i); + goto ERROR; + } + + for (j = 1; j < numShdr; j++) { + if (j == i) { + continue; + } + + /* Sections must not overlap in memory. */ + if (shdrs[i].sh_addr != 0 + && shdrs[j].sh_addr != 0 + && OVERLAPPING(shdrs[i].sh_addr, shdrs[i].sh_size, + shdrs[j].sh_addr, shdrs[j].sh_size)) { + ELFU_WARN("elfu_eCheck: Sections %d and %d overlap in memory.\n", i, j); + goto ERROR; + } + + /* Sections must not overlap in file. */ + if (OVERLAPPING(shdrs[i].sh_offset, elfu_gScnSizeFile(&shdrs[i]), + shdrs[j].sh_offset, elfu_gScnSizeFile(&shdrs[j]))) { + ELFU_WARN("elfu_eCheck: Sections %d and %d overlap in file.\n", i, j); + goto ERROR; + } + } + } + } + + + DONE: + if (phdrs) { + free(phdrs); + } + if (shdrs) { + free(shdrs); + } + return retval; + + ERROR: + ELFU_WARN("elfu_eCheck: Errors found.\n"); + retval = -1; + goto DONE; +} diff --git a/src/model/fromFile.c b/src/model/fromFile.c index fee6ec0..57cb519 100644 --- a/src/model/fromFile.c +++ b/src/model/fromFile.c @@ -94,6 +94,12 @@ ElfuElf* elfu_mFromElf(Elf *e) size_t shstrndx; size_t i, n; + assert(e); + if (elfu_eCheck(e)) { + goto ERROR; + } + + /* Get the section string table index */ if (elf_getshdrstrndx(e, &shstrndx) != 0) { shstrndx = 0; } @@ -117,7 +123,7 @@ ElfuElf* elfu_mFromElf(Elf *e) if (!gelf_getehdr(e, &me->ehdr)) { ELFU_WARNELF("gelf_getehdr"); - goto out; + goto ERROR; } @@ -135,7 +141,7 @@ ElfuElf* elfu_mFromElf(Elf *e) me->shstrtab = ms; } } else { - goto out; + goto ERROR; } scn = elf_nextscn(e, scn); @@ -165,15 +171,16 @@ ElfuElf* elfu_mFromElf(Elf *e) if (mp) { CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem); } else { - goto out; + goto ERROR; } } + return me; - return me; + ERROR: + // TODO: Free data structures - out: - // FIXME + ELFU_WARN("elfu_mFromElf: Failed to load file.\n"); return NULL; } -- 2.30.2