diff options
author | norly <ny-git@enpas.org> | 2013-05-26 22:16:54 +0100 |
---|---|---|
committer | norly <ny-git@enpas.org> | 2013-05-27 03:10:31 +0100 |
commit | f5eac562c915811c27969949c178f8fe96a12e47 (patch) | |
tree | 7713d3c13719825ed96210f2acc4c34d796597b8 /src/elfops | |
parent | 3d899fbfd33a8b44dcbd7dfbc952464731a7e589 (diff) |
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.
Diffstat (limited to 'src/elfops')
-rw-r--r-- | src/elfops/check.c | 180 |
1 files changed, 180 insertions, 0 deletions
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 <assert.h> +#include <stdlib.h> +#include <libelf/libelf.h> +#include <libelf/gelf.h> +#include <libelfu/libelfu.h> + +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; +} |