summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2017-02-11 02:20:33 -0500
committerMike Frysinger <vapier@gentoo.org>2017-02-11 02:20:33 -0500
commit858939ea6ad63f1acb4ec74bba705c197a67d559 (patch)
tree4f54fc837aaa36bdd2408c7bb89709cb74306823
parentscanelf: check range of hash bucket (diff)
downloadpax-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.c2
-rw-r--r--paxelf.h12
-rw-r--r--scanelf.c30
3 files changed, 19 insertions, 25 deletions
diff --git a/dumpelf.c b/dumpelf.c
index 60c78a3..6ba37fc 100644
--- a/dumpelf.c
+++ b/dumpelf.c
@@ -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; \
diff --git a/paxelf.h b/paxelf.h
index 90b283c..9d609b8 100644
--- a/paxelf.h
+++ b/paxelf.h
@@ -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);
diff --git a/scanelf.c b/scanelf.c
index 70856f3..ddd7722 100644
--- a/scanelf.c
+++ b/scanelf.c
@@ -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) {