diff options
author | Mike Frysinger <vapier@gentoo.org> | 2017-02-11 02:20:33 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2017-02-11 02:20:33 -0500 |
commit | 858939ea6ad63f1acb4ec74bba705c197a67d559 (patch) | |
tree | 4f54fc837aaa36bdd2408c7bb89709cb74306823 | |
parent | scanelf: check range of hash bucket (diff) | |
download | pax-utils-858939ea6ad63f1acb4ec74bba705c197a67d559.tar.gz pax-utils-858939ea6ad63f1acb4ec74bba705c197a67d559.tar.bz2 pax-utils-858939ea6ad63f1acb4ec74bba705c197a67d559.zip |
add helper for checking memory/elf ranges
Less likely to screw up the logic this way.
-rw-r--r-- | dumpelf.c | 2 | ||||
-rw-r--r-- | paxelf.h | 12 | ||||
-rw-r--r-- | scanelf.c | 30 |
3 files changed, 19 insertions, 25 deletions
@@ -385,7 +385,7 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, size_t shdr_cnt, const /* Special case so we can do valid check next. */ \ if (be_verbose) \ printf("\t/* NOBITS sections do not occupy the file. */\n"); \ - } else if (!(offset < (uint64_t)elf->len && size < (uint64_t)elf->len && offset <= elf->len - size)) { \ + } else if (!VALID_RANGE(elf, offset, size)) { \ printf(" /* corrupt section header ! */ "); \ } else if (size && be_verbose) { \ void *vdata = elf->vdata + offset; \ @@ -39,17 +39,15 @@ typedef struct { #define SYM32(ptr) ((Elf32_Sym *)(ptr)) #define SYM64(ptr) ((Elf64_Sym *)(ptr)) +#define VALID_RANGE(elf, offset, size) \ + ((uint64_t)(size) <= (uint64_t)elf->len && \ + (uint64_t)(offset) <= (uint64_t)elf->len - (uint64_t)(size)) #define VALID_SHDR(elf, shdr) \ (shdr && \ EGET(shdr->sh_type) != SHT_NOBITS && \ - EGET(shdr->sh_offset) < (uint64_t)elf->len && \ - EGET(shdr->sh_size) < (uint64_t)elf->len && \ - EGET(shdr->sh_offset) <= elf->len - EGET(shdr->sh_size)) + VALID_RANGE(elf, EGET(shdr->sh_offset), EGET(shdr->sh_size))) #define VALID_PHDR(elf, phdr) \ - (phdr && \ - EGET(phdr->p_filesz) < (uint64_t)elf->len && \ - EGET(phdr->p_offset) < (uint64_t)elf->len && \ - EGET(phdr->p_filesz) <= elf->len - EGET(phdr->p_offset)) + (phdr && VALID_RANGE(elf, EGET(phdr->p_offset), EGET(phdr->p_filesz))) /* prototypes */ extern char *pax_short_hf_flags(unsigned long flags); @@ -181,7 +181,7 @@ static void *scanelf_file_get_pt_dynamic(elfobj *elf) if (EGET(phdr->p_filesz) == 0) \ break; \ offset = EGET(phdr->p_offset); \ - if (offset >= elf->len - sizeof(Elf##B##_Dyn)) \ + if (!VALID_RANGE(elf, offset, sizeof(Elf##B##_Dyn))) \ break; \ return phdr; SCANELF_ELF_SIZED(CHECK_PT_DYNAMIC); @@ -299,11 +299,9 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str) if (EGET(phdr[i].p_type) != PT_LOAD) \ continue; \ \ - if (offset >= (uint64_t)elf->len) \ + if (!VALID_RANGE(elf, offset, filesz)) \ goto corrupt_hash; \ - if (filesz >= (uint64_t)elf->len) \ - goto corrupt_hash; \ - if (hash_offset + (sizeof(Elf32_Word) * 4) > (uint64_t)elf->len) \ + if (!VALID_RANGE(elf, hash_offset, sizeof(Elf32_Word) * 4)) \ goto corrupt_hash; \ \ if (vhash >= vaddr && vhash < vaddr + filesz) { \ @@ -317,15 +315,9 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str) Elf32_Word sym_idx; \ Elf32_Word chained; \ \ - if (hash_offset >= (uint64_t)elf->len) \ - goto corrupt_hash; \ - if (nbuckets >= UINT32_MAX / 4) \ - goto corrupt_hash; \ - if (nchains >= UINT32_MAX / 4) \ - goto corrupt_hash; \ - if (nbuckets * 4 > elf->len - offset) \ + if (!VALID_RANGE(elf, offset, nbuckets * 4)) \ goto corrupt_hash; \ - if (nchains * 4 > elf->len - offset) \ + if (!VALID_RANGE(elf, offset, nchains * 4)) \ goto corrupt_hash; \ \ for (b = 0; b < nbuckets; ++b) { \ @@ -345,13 +337,17 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str) } \ \ if (vsym >= vaddr && vsym < vaddr + filesz) { \ + Elf##B##_Shdr *shdr = &sym_shdr; \ ESET(sym_shdr.sh_offset, offset + (vsym - vaddr)); \ - *sym = &sym_shdr; \ + if (VALID_SHDR(elf, shdr)) \ + *sym = shdr; \ } \ \ if (vstr >= vaddr && vstr < vaddr + filesz) { \ + Elf##B##_Shdr *shdr = &str_shdr; \ ESET(str_shdr.sh_offset, offset + (vstr - vaddr)); \ - *str = &str_shdr; \ + if (VALID_SHDR(elf, shdr)) \ + *str = shdr; \ } \ } if (elf->phdr) @@ -487,7 +483,7 @@ static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, for (i = 0; i < shnum; ++i) { \ if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ - if (offset >= elf->len - sizeof(NOTE_GNU_STACK)) \ + if (!VALID_RANGE(elf, offset, sizeof(NOTE_GNU_STACK))) \ continue; \ if (!strcmp(elf->data + offset, NOTE_GNU_STACK)) { \ if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \ @@ -1505,7 +1501,7 @@ static int scanelf_elfobj(elfobj *elf) case 'a': out = get_elfemtype(elf); break; case 'I': out = get_elfosabi(elf); break; case 'Y': out = get_elf_eabi(elf); break; - case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;; + case 'Z': snprintf(ubuf, sizeof(ubuf), "%"PRIu64, (uint64_t)elf->len); out = ubuf; break;; default: warnf("'%c' has no scan code?", out_format[i]); } if (out) { |