From 77c914bce58aab9459029bed699f2bfb7ff2f90f Mon Sep 17 00:00:00 2001 From: John Reiser Date: Sat, 25 Jul 2020 09:28:02 -0700 Subject: [PATCH] Check de-compressed SHT_SYMTAB https://github.com/upx/upx/issues/396 modified: p_lx_elf.cpp --- src/p_lx_elf.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index d7ec2cf9..265f23d8 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -3134,8 +3134,8 @@ static char const abs_symbol_names[][14] = { int PackLinuxElf32::adjABS(Elf32_Sym *sym, unsigned delta) { + unsigned st_name = get_te32(&sym->st_name); for (int j = 0; abs_symbol_names[j][0]; ++j) { - unsigned st_name = get_te32(&sym->st_name); if (!strcmp(abs_symbol_names[j], get_str_name(st_name, (unsigned)-1))) { sym->st_value += delta; return 1; @@ -3147,8 +3147,8 @@ PackLinuxElf32::adjABS(Elf32_Sym *sym, unsigned delta) int PackLinuxElf64::adjABS(Elf64_Sym *sym, unsigned delta) { + unsigned st_name = get_te32(&sym->st_name); for (int j = 0; abs_symbol_names[j][0]; ++j) { - unsigned st_name = get_te32(&sym->st_name); if (!strcmp(abs_symbol_names[j], get_str_name(st_name, (unsigned)-1))) { sym->st_value += delta; return 1; @@ -4614,16 +4614,21 @@ void PackLinuxElf64::unpack(OutputFile *fo) xct_off = e_shoff; } // un-Relocate dynsym (DT_SYMTAB) which is below xct_off - dynseg = (Elf64_Dyn const *)ibuf.subref( - "bad DYNAMIC", get_te64(&dynhdr->p_offset), get_te64(&dynhdr->p_filesz)); + upx_uint64_t dyn_offset = get_te64(&dynhdr->p_offset); + upx_uint64_t dyn_filesz = get_te64(&dynhdr->p_filesz); + if (orig_file_size < dyn_offset + || (orig_file_size - dyn_offset) < dyn_filesz) { + throwCantUnpack("bad PT_DYNAMIC"); + } + dynseg = (Elf64_Dyn const *)ibuf.subref("bad DYNAMIC", dyn_offset, dyn_filesz); dynstr = (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB); sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM); if (sec_dynsym) { upx_uint64_t const off_dynsym = get_te64(&sec_dynsym->sh_offset); upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size); - if ((upx_uint64_t)file_size < sz_dynsym - || (upx_uint64_t)file_size < off_dynsym - || ((upx_uint64_t)file_size - off_dynsym) < sz_dynsym) { + if (orig_file_size < sz_dynsym + || orig_file_size < off_dynsym + || (orig_file_size - off_dynsym) < sz_dynsym) { throwCantUnpack("bad SHT_DYNSYM"); } Elf64_Sym *const sym0 = (Elf64_Sym *)ibuf.subref( @@ -5695,13 +5700,23 @@ void PackLinuxElf32::unpack(OutputFile *fo) xct_off = e_shoff; } // un-Relocate dynsym (DT_SYMTAB) which is below xct_off - dynseg = (Elf32_Dyn const *)ibuf.subref( - "bad DYNAMIC", get_te32(&dynhdr->p_offset), get_te32(&dynhdr->p_filesz)); + unsigned dyn_offset = get_te32(&dynhdr->p_offset); + unsigned dyn_filesz = get_te32(&dynhdr->p_filesz); + if (orig_file_size < dyn_offset + || (orig_file_size - dyn_offset) < dyn_filesz) { + throwCantUnpack("bad PT_DYNAMIC"); + } + dynseg = (Elf32_Dyn const *)ibuf.subref("bad DYNAMIC", dyn_offset, dyn_filesz); dynstr = (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB); sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM); if (sec_dynsym) { unsigned const off_dynsym = get_te32(&sec_dynsym->sh_offset); unsigned const sz_dynsym = get_te32(&sec_dynsym->sh_size); + if (orig_file_size < sz_dynsym + || orig_file_size < off_dynsym + || (orig_file_size - off_dynsym) < sz_dynsym) { + throwCantUnpack("bad SHT_DYNSYM"); + } Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref( "bad dynsym", off_dynsym, sz_dynsym); Elf32_Sym *sym = sym0;