1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

better checking of DT_STRSZ for ELF

https://github.com/upx/upx/issues/779
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66064
	modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
This commit is contained in:
John Reiser 2024-01-27 11:11:07 -08:00
parent ff5a4eeb96
commit 69c51eee4d
2 changed files with 27 additions and 15 deletions

View File

@ -259,7 +259,7 @@ PackLinuxElf::PackLinuxElf(InputFile *f)
o_elf_shnum(0)
{
memset(dt_table, 0, sizeof(dt_table));
symnum_end = 0;
symnum_max = 0;
user_init_rp = nullptr;
}
@ -2102,15 +2102,21 @@ PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, u32_t headway)
else if (dt_table[Elf32_Dyn::DT_INIT_ARRAY]) upx_dt_init = Elf32_Dyn::DT_INIT_ARRAY;
unsigned const z_str = dt_table[Elf32_Dyn::DT_STRSZ];
strtab_end = !z_str ? 0 : get_te32(&dynp0[-1+ z_str].d_val);
if (!z_str || (u32_t)file_size <= strtab_end) { // FIXME: weak
strtab_max = !z_str ? 0 : get_te32(&dynp0[-1+ z_str].d_val);
unsigned const z_tab = dt_table[Elf32_Dyn::DT_STRTAB];
unsigned const strtab_beg = !z_tab ? 0 : get_te32(&dynp0[-1+ z_tab].d_val);
if (!z_str || !z_tab
|| (this->file_size - strtab_beg) < strtab_max // strtab overlaps EOF
// last string in table must have terminating NUL
|| '\0' != ((char *)file_image.getVoidPtr())[-1+ strtab_max + strtab_beg]
) {
char msg[50]; snprintf(msg, sizeof(msg),
"bad DT_STRSZ %#x", strtab_end);
"bad DT_STRSZ %#x", strtab_max);
throwCantPack(msg);
}
// Find end of DT_SYMTAB
symnum_end = elf_find_table_size(
symnum_max = elf_find_table_size(
Elf32_Dyn::DT_SYMTAB, Elf32_Shdr::SHT_DYNSYM) / sizeof(Elf32_Sym);
unsigned const x_sym = dt_table[Elf32_Dyn::DT_SYMTAB];
@ -2346,7 +2352,7 @@ Elf64_Shdr *PackLinuxElf64::elf_find_section_type(
char const *PackLinuxElf64::get_str_name(unsigned st_name, unsigned symnum) const
{
if (strtab_end <= st_name) {
if (strtab_max <= st_name) {
char msg[70]; snprintf(msg, sizeof(msg),
"bad .st_name %#x in DT_SYMTAB[%d]", st_name, symnum);
throwCantPack(msg);
@ -2356,7 +2362,7 @@ char const *PackLinuxElf64::get_str_name(unsigned st_name, unsigned symnum) cons
char const *PackLinuxElf64::get_dynsym_name(unsigned symnum, unsigned relnum) const
{
if (symnum_end <= symnum) {
if (symnum_max <= symnum) {
char msg[70]; snprintf(msg, sizeof(msg),
"bad symnum %#x in Elf64_Rel[%d]", symnum, relnum);
throwCantPack(msg);
@ -2383,7 +2389,7 @@ bool PackLinuxElf64::calls_crt1(Elf64_Rela const *rela, int sz)
char const *PackLinuxElf32::get_str_name(unsigned st_name, unsigned symnum) const
{
if (strtab_end <= st_name) {
if (strtab_max <= st_name) {
char msg[70]; snprintf(msg, sizeof(msg),
"bad .st_name %#x in DT_SYMTAB[%d]\n", st_name, symnum);
throwCantPack(msg);
@ -2393,7 +2399,7 @@ char const *PackLinuxElf32::get_str_name(unsigned st_name, unsigned symnum) cons
char const *PackLinuxElf32::get_dynsym_name(unsigned symnum, unsigned relnum) const
{
if (symnum_end <= symnum) {
if (symnum_max <= symnum) {
char msg[70]; snprintf(msg, sizeof(msg),
"bad symnum %#x in Elf32_Rel[%d]\n", symnum, relnum);
throwCantPack(msg);
@ -8002,15 +8008,21 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway)
else if (dt_table[Elf64_Dyn::DT_INIT_ARRAY]) upx_dt_init = Elf64_Dyn::DT_INIT_ARRAY;
unsigned const z_str = dt_table[Elf64_Dyn::DT_STRSZ];
strtab_end = !z_str ? 0 : get_te64(&dynp0[-1+ z_str].d_val);
if (!z_str || (u64_t)file_size <= strtab_end) { // FIXME: weak
strtab_max = !z_str ? 0 : get_te64(&dynp0[-1+ z_str].d_val);
unsigned const z_tab = dt_table[Elf64_Dyn::DT_STRTAB];
unsigned const strtab_beg = !z_tab ? 0 : get_te64(&dynp0[-1+ z_tab].d_val);
if (!z_str || !z_tab
|| (this->file_size - strtab_beg) < strtab_max // strtab overlaps EOF
// last string in table must have terminating NUL
|| '\0' != ((char *)file_image.getVoidPtr())[-1+ strtab_max + strtab_beg]
) {
char msg[50]; snprintf(msg, sizeof(msg),
"bad DT_STRSZ %#x", strtab_end);
"bad DT_STRSZ %#x", strtab_max);
throwCantPack(msg);
}
// Find end of DT_SYMTAB
symnum_end = elf_find_table_size(
symnum_max = elf_find_table_size(
Elf64_Dyn::DT_SYMTAB, Elf64_Shdr::SHT_DYNSYM) / sizeof(Elf64_Sym);
unsigned const x_sym = dt_table[Elf64_Dyn::DT_SYMTAB];

View File

@ -84,8 +84,8 @@ protected:
MemBuffer mb_shdr; // Shdr might not be near Phdr
MemBuffer mb_dt_offsets; // file offset of various DT_ tables
unsigned *dt_offsets; // index by dt_table[]
unsigned symnum_end;
unsigned strtab_end;
unsigned symnum_max;
unsigned strtab_max;
char const *dynstr; // from DT_STRTAB
unsigned sz_phdrs; // sizeof Phdr[]