Esempio n. 1
0
int elfu_mCheck(ElfuElf *me)
{
  size_t numSecs;
  ElfuScn **sortedSecs;
  size_t i;

  sortedSecs = elfu_mScnSortedByOffset(me, &numSecs);
  if (!sortedSecs) {
    return -1;
  }


  /* Check for overlapping sections */
  for (i = 0; i < numSecs - 1; i++) {
    if (sortedSecs[i]->shdr.sh_offset + SCNFILESIZE(&sortedSecs[i]->shdr)
        > sortedSecs[i+1]->shdr.sh_offset) {
      ELFU_WARN("elfu_check: Found overlapping sections: %s and %s.\n",
                elfu_mScnName(me, sortedSecs[i]),
                elfu_mScnName(me, sortedSecs[i+1]));
    }
  }


  /* Check for sections overlapping with EHDR */
  for (i = 0; i < numSecs; i++) {
    if (sortedSecs[i]->shdr.sh_offset < me->ehdr.e_ehsize) {
      ELFU_WARN("elfu_check: Found section overlapping with EHDR: %s.\n",
                elfu_mScnName(me, sortedSecs[i]));
    }
  }


  /* Check for sections overlapping with PHDRs */
  for (i = 0; i < numSecs; i++) {
    if (OVERLAPPING(sortedSecs[i]->shdr.sh_offset,
                    SCNFILESIZE(&sortedSecs[i]->shdr),
                    me->ehdr.e_phoff,
                    me->ehdr.e_phentsize * me->ehdr.e_phnum)) {
      ELFU_WARN("elfu_check: Found section overlapping with PHDRs: %s.\n",
                elfu_mScnName(me, sortedSecs[i]));
    }
  }


  free(sortedSecs);

  return 0;
}
Esempio n. 2
0
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 (ehdr.e_machine != EM_386 && ehdr.e_machine != EM_X86_64) {
    ELFU_WARN("Sorry, only x86-32 and x86-64 ELF files are supported at the moment.\n");
    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, SCNFILESIZE(&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, SCNFILESIZE(&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, SCNFILESIZE(&shdrs[i]),
                        shdrs[j].sh_offset, SCNFILESIZE(&shdrs[j]))) {
          ELFU_WARN("elfu_eCheck: Sections %d and %d overlap in file.\n", i, j);
          goto ERROR;
        }

        /* We may not have more than one symbol table */
        if (shdrs[i].sh_type == SHT_SYMTAB && shdrs[j].sh_type == SHT_SYMTAB) {
          ELFU_WARN("elfu_eCheck: Found more than one SYMTAB section.\n");
          goto ERROR;
        }

        /* We may not have more than one dynamic symbol table */
        if (shdrs[i].sh_type == SHT_DYNSYM && shdrs[j].sh_type == SHT_DYNSYM) {
          ELFU_WARN("elfu_eCheck: Found more than one DYNSYM section.\n");
          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])) {
          GElf_Off shoff = phdrs[j].p_offset + (shdrs[i].sh_addr - phdrs[j].p_vaddr);

          if ((shdrs[i].sh_offset != shoff && shdrs[i].sh_type != SHT_NOBITS)
              || !PHDR_CONTAINS_SCN_IN_FILE(&phdrs[j], &shdrs[i])) {
            ELFU_WARN("elfu_eCheck: SHDR %d and PHDR %d report conflicting file/memory regions.\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);
      }
    }
  }


  DONE:
  if (phdrs) {
    free(phdrs);
  }
  if (shdrs) {
    free(shdrs);
  }
  return retval;

  ERROR:
  ELFU_WARN("elfu_eCheck: Errors found.\n");
  retval = -1;
  goto DONE;
}