summaryrefslogtreecommitdiff
path: root/src/elfops/check.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/elfops/check.c')
-rw-r--r--src/elfops/check.c180
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;
+}