diff options
-rw-r--r-- | include/libelfu/modeltypes.h | 5 | ||||
-rw-r--r-- | src/elfops/check.c | 16 | ||||
-rw-r--r-- | src/model/check.c | 2 | ||||
-rw-r--r-- | src/model/fromFile.c | 114 |
4 files changed, 121 insertions, 16 deletions
diff --git a/include/libelfu/modeltypes.h b/include/libelfu/modeltypes.h index c944234..c02eb34 100644 --- a/include/libelfu/modeltypes.h +++ b/include/libelfu/modeltypes.h @@ -12,6 +12,9 @@ typedef struct ElfuScn { Elf_Data data; + struct ElfuScn *link; + + CIRCLEQ_ENTRY(ElfuScn) elemPhdrToScn; CIRCLEQ_ENTRY(ElfuScn) elem; } ElfuScn; @@ -19,6 +22,8 @@ typedef struct ElfuScn { typedef struct ElfuPhdr { GElf_Phdr phdr; + CIRCLEQ_HEAD(PhdrToScnList, ElfuScn) phdrToScnList; + CIRCLEQ_ENTRY(ElfuPhdr) elem; } ElfuPhdr; diff --git a/src/elfops/check.c b/src/elfops/check.c index 8aaa7b5..daf6542 100644 --- a/src/elfops/check.c +++ b/src/elfops/check.c @@ -160,6 +160,22 @@ int elfu_eCheck(Elf *e) goto ERROR; } } + + /* Section addr/offset should match parent PHDR. + * Find parent PHDR: */ + for (j = 0; j < numPhdr; j++) { + if (PHDR_CONTAINS_SCN_IN_MEMORY(&phdrs[j], &shdrs[i])) { + if (!PHDR_CONTAINS_SCN_IN_FILE(&phdrs[j], &shdrs[i])) { + ELFU_WARN("elfu_eCheck: Memory/file offsets/sizes are not congruent for SHDR %d, PHDR %d.\n", i, j); + goto ERROR; + } + } + } + + /* sh_link members should not point to sections out of range. */ + if (shdrs[i].sh_link >= numShdr) { + ELFU_WARN("elfu_eCheck: Bogus sh_link in SHDR %d.\n", i); + } } } diff --git a/src/model/check.c b/src/model/check.c index 4fb042c..6dc0694 100644 --- a/src/model/check.c +++ b/src/model/check.c @@ -61,7 +61,7 @@ int elfu_mCheck(ElfuElf *me) sortedSecs[i] = ms; i++; } - assert(i = numSecs); + assert(i == numSecs); qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs); diff --git a/src/model/fromFile.c b/src/model/fromFile.c index bcdb91a..125ea77 100644 --- a/src/model/fromFile.c +++ b/src/model/fromFile.c @@ -7,6 +7,51 @@ #include <libelfu/libelfu.h> +static int cmpScnOffs(const void *ms1, const void *ms2) +{ + assert(ms1); + assert(ms2); + + ElfuScn *s1 = *(ElfuScn**)ms1; + ElfuScn *s2 = *(ElfuScn**)ms2; + + assert(s1); + assert(s2); + + + if (s1->shdr.sh_offset < s2->shdr.sh_offset) { + return -1; + } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) { + return 0; + } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ { + return 1; + } +} + + + +static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms) +{ + ElfuPhdr *mp; + + assert(me); + assert(ms); + + CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { + if (ms->shdr.sh_addr >= mp->phdr.p_vaddr + && OFFS_END(ms->shdr.sh_addr, ms->shdr.sh_size) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) { + return mp; + } else if (ms->shdr.sh_offset >= mp->phdr.p_offset + && OFFS_END(ms->shdr.sh_offset, SCNFILESIZE(&ms->shdr)) <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_filesz) + && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size) <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) { + return mp; + } + } + + return NULL; +} + + static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr) { ElfuPhdr *mp; @@ -21,6 +66,8 @@ static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr) mp->phdr = *phdr; + CIRCLEQ_INIT(&mp->phdrToScnList); + return mp; } @@ -77,6 +124,8 @@ static ElfuScn* modelFromSection(Elf_Scn *scn) } } + ms->link = NULL; + return ms; @@ -95,6 +144,7 @@ ElfuElf* elfu_mFromElf(Elf *e) ElfuElf *me; size_t shstrndx; size_t i, numPhdr, numShdr; + ElfuScn **secArray = NULL; assert(e); if (elfu_eCheck(e)) { @@ -143,39 +193,73 @@ ElfuElf* elfu_mFromElf(Elf *e) /* Load sections */ assert(!elf_getshdrnum(e, &numShdr)); - for (i = 1; i < numShdr; i++) { - Elf_Scn *scn; - ElfuScn *ms; + if (numShdr > 1) { + secArray = malloc((numShdr - 1) * sizeof(*secArray)); + if (!secArray) { + ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n"); + goto ERROR; + } - scn = elf_getscn(e, i); - assert(scn); + for (i = 1; i < numShdr; i++) { + Elf_Scn *scn; + ElfuScn *ms; - ms = modelFromSection(scn); - if (!ms) { - goto ERROR; + scn = elf_getscn(e, i); + assert(scn); + + ms = modelFromSection(scn); + if (!ms) { + goto ERROR; + } + + secArray[i-1] = ms; + + if (i == shstrndx) { + me->shstrtab = ms; + } } - CIRCLEQ_INSERT_TAIL(&me->scnList, ms, elem); - if (i == shstrndx) { - me->shstrtab = ms; + + /* Find sh_link dependencies */ + for (i = 0; i < numShdr - 1; i++) { + ElfuScn *ms = secArray[i]; + + if (ms->shdr.sh_link > 0) { + ms->link = secArray[ms->shdr.sh_link - 1]; + } } - } - /* Find sh_link dependencies */ + /* Sort sections by file offset */ + qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs); + + /* Find PHDR -> Section dependencies (needs sorted sections) */ + for (i = 0; i < numShdr - 1; i++) { + ElfuScn *ms = secArray[i]; - /* Sort sections by offset */ + ElfuPhdr *parent = parentPhdr(me, ms); + if (parent) { + CIRCLEQ_INSERT_TAIL(&parent->phdrToScnList, ms, elemPhdrToScn); + } + } - /* Find PHDR -> Section dependencies */ + /* Put sections into list of all sections */ + for (i = 0; i < numShdr - 1; i++) { + CIRCLEQ_INSERT_TAIL(&me->scnList, secArray[i], elem); + } + } return me; ERROR: + if (secArray) { + free(secArray); + } if (me) { // TODO: Free data structures } |