From: norly Date: Sun, 26 May 2013 21:16:54 +0000 (+0100) Subject: Validate input at libelf level X-Git-Url: https://git.enpas.org/?p=centaur.git;a=commitdiff_plain;h=f5eac562c915811c27969949c178f8fe96a12e47 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. --- 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; }