diff --git a/src/elf_util.c b/src/elf_util.c index 57a89fe..204c2bc 100644 --- a/src/elf_util.c +++ b/src/elf_util.c @@ -80,12 +80,18 @@ static int64_t sleb128_decode(struct sleb128_decoder *decoder) { const size_t size = sizeof(int64_t) * CHAR_BIT; do { - if (decoder->current >= decoder->end) - LOGF("Failed to decode SLEB128: buffer overrun"); + if (decoder->current >= decoder->end) { + LOGF("Failed to decode SLEB128: buffer overrun"); + return 0; + } byte = *decoder->current++; value |= ((int64_t)(byte & 0x7F)) << shift; shift += 7; + if (shift > size) { + LOGF("SLEB128 shift overflow"); + return 0; + } } while (byte & 0x80); if (shift < size && (byte & 0x40)) { @@ -327,8 +333,9 @@ static bool elfutil_unpack_android_relocs(const struct elf_image *elf, struct an struct sleb128_decoder decoder; sleb128_decoder_init(&decoder, (const uint8_t *)elf->rel_android_, elf->rel_android_size_); - uint64_t num_relocs = sleb128_decode(&decoder); - if (num_relocs <= 0) return false; + int64_t num_relocs_signed = sleb128_decode(&decoder); + if (num_relocs_signed <= 0) return false; + uint64_t num_relocs = (uint64_t)num_relocs_signed; size_t out_index = 0; void *entries = calloc(num_relocs, elf->rel_android_is_rela_ ? sizeof(ElfW(Rela)) : sizeof(ElfW(Rel))); @@ -397,6 +404,14 @@ static bool elfutil_unpack_android_relocs(const struct elf_image *elf, struct an if (elf->rel_android_is_rela_ && group_flags_reloc == RELOCATION_GROUP_HAS_ADDEND_FLAG) r_addend += sleb128_decode(&decoder); + if (out_index >= num_relocs) { + LOGE("out_index exceeded num_relocs"); + + free(entries); + + return false; + } + if (elf->rel_android_is_rela_) { ElfW(Rela) *rela = (ElfW(Rela) *)entries; rela[out_index].r_offset = current_offset; diff --git a/src/plti.c b/src/plti.c index 47676ef..ab69b6b 100644 --- a/src/plti.c +++ b/src/plti.c @@ -259,7 +259,9 @@ static bool plti_internal_set_got_entry(struct elf_info *info, uintptr_t got_add if (!stash) { /* INFO: Don't call LOGE -- or else it will try to access GOT while it's being modified */ void *hint = find_high_backup_hint(vma_len); - void *backup_addr = mmap(hint, vma_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + void *backup_addr = MAP_FAILED; + if (hint) + backup_addr = mmap(hint, vma_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (backup_addr == MAP_FAILED) { backup_addr = mmap(NULL, vma_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (backup_addr == MAP_FAILED) {