Check more in invert_pt_dynamic

https://github.com/upx/upx/issues/471
	modified:   p_lx_elf.cpp
This commit is contained in:
John Reiser
2021-03-16 18:46:11 -07:00
committed by Markus F.X.J. Oberhumer
parent ba5c77c9e5
commit 1218b6ff2a
+22 -26
View File
@@ -312,8 +312,9 @@ PackLinuxElf32::PackLinuxElf32help1(InputFile *f)
Elf32_Phdr const *phdr= phdri; Elf32_Phdr const *phdr= phdri;
for (int j = e_phnum; --j>=0; ++phdr) for (int j = e_phnum; --j>=0; ++phdr)
if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) {
dynseg= (Elf32_Dyn const *)(check_pt_dynamic(phdr) + file_image); unsigned offset = check_pt_dynamic(phdr);
invert_pt_dynamic(dynseg, get_te32(&phdr->p_filesz)); dynseg= (Elf32_Dyn const *)(offset + file_image);
invert_pt_dynamic(dynseg, get_te32(&phdr->p_filesz) - offset);
} }
else if (is_LOAD32(phdr)) { else if (is_LOAD32(phdr)) {
check_pt_load(phdr); check_pt_load(phdr);
@@ -812,8 +813,9 @@ PackLinuxElf64::PackLinuxElf64help1(InputFile *f)
Elf64_Phdr const *phdr= phdri; Elf64_Phdr const *phdr= phdri;
for (int j = e_phnum; --j>=0; ++phdr) for (int j = e_phnum; --j>=0; ++phdr)
if (Elf64_Phdr::PT_DYNAMIC==get_te64(&phdr->p_type)) { if (Elf64_Phdr::PT_DYNAMIC==get_te64(&phdr->p_type)) {
dynseg= (Elf64_Dyn const *)(check_pt_dynamic(phdr) + file_image); upx_uint64_t offset = check_pt_dynamic(phdr);
invert_pt_dynamic(dynseg, get_te64(&phdr->p_filesz)); dynseg= (Elf64_Dyn const *)(offset + file_image);
invert_pt_dynamic(dynseg, get_te64(&phdr->p_filesz) - offset);
} }
else if (PT_LOAD64==get_te32(&phdr->p_type)) { else if (PT_LOAD64==get_te32(&phdr->p_type)) {
check_pt_load(phdr); check_pt_load(phdr);
@@ -1604,19 +1606,14 @@ PackLinuxElf64arm::buildLoader(const Filter *ft)
} }
void void
PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, unsigned dt_filesz) PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, unsigned headway)
{ {
if (dt_table[Elf32_Dyn::DT_NULL]) { if (dt_table[Elf32_Dyn::DT_NULL]) {
return; // not 1st time; do not change upx_dt_init return; // not 1st time; do not change upx_dt_init
} }
if ((file_size - (e_phnum*sizeof(Elf32_Phdr) + sizeof(Elf32_Ehdr))) < dt_filesz) {
char msg[50]; snprintf(msg, sizeof(msg),
"bad PT_DYNAMIC.pt_filesz %#x", dt_filesz);
throwCantPack(msg);
}
Elf32_Dyn const *const dynp0 = dynp; Elf32_Dyn const *const dynp0 = dynp;
unsigned ndx = 1+ 0; unsigned ndx = 1+ 0;
unsigned const limit = dt_filesz / sizeof(*dynp); unsigned const limit = headway / sizeof(*dynp);
if (dynp) if (dynp)
for (; ; ++ndx, ++dynp) { for (; ; ++ndx, ++dynp) {
if (limit <= ndx) { if (limit <= ndx) {
@@ -2149,8 +2146,9 @@ bool PackLinuxElf32::canPack()
phdr= phdri; phdr= phdri;
for (int j= e_phnum; --j>=0; ++phdr) for (int j= e_phnum; --j>=0; ++phdr)
if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) {
dynseg= (Elf32_Dyn const *)(check_pt_dynamic(phdr) + file_image); unsigned offset = check_pt_dynamic(phdr);
invert_pt_dynamic(dynseg, get_te32(&phdr->p_filesz)); dynseg= (Elf32_Dyn const *)(offset + file_image);
invert_pt_dynamic(dynseg, file_size - offset);
} }
else if (is_LOAD32(phdr)) { else if (is_LOAD32(phdr)) {
if (!pload_x0 if (!pload_x0
@@ -2535,8 +2533,9 @@ PackLinuxElf64::canPack()
phdr= phdri; phdr= phdri;
for (int j= e_phnum; --j>=0; ++phdr) for (int j= e_phnum; --j>=0; ++phdr)
if (Elf64_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { if (Elf64_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) {
dynseg= (Elf64_Dyn const *)(check_pt_dynamic(phdr) + file_image); upx_uint64_t offset = check_pt_dynamic(phdr);
invert_pt_dynamic(dynseg, get_te64(&phdr->p_filesz)); dynseg= (Elf64_Dyn const *)(offset + file_image);
invert_pt_dynamic(dynseg, file_size - offset);
} }
else if (PT_LOAD64==get_te32(&phdr->p_type)) { else if (PT_LOAD64==get_te32(&phdr->p_type)) {
if (!pload_x0 if (!pload_x0
@@ -4708,7 +4707,7 @@ void PackLinuxElf64::un_DT_INIT(
fi->seek(dyn_off, SEEK_SET); fi->seek(dyn_off, SEEK_SET);
fi->readx(ibuf, dyn_len); fi->readx(ibuf, dyn_len);
Elf64_Dyn *dyn = (Elf64_Dyn *)(void *)ibuf; Elf64_Dyn *dyn = (Elf64_Dyn *)(void *)ibuf;
dynseg = dyn; invert_pt_dynamic(dynseg, get_te64(&dynhdr->p_filesz)); dynseg = dyn; invert_pt_dynamic(dynseg, file_size - dyn_off);
for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) {
upx_uint64_t const tag = get_te64(&dyn->d_tag); upx_uint64_t const tag = get_te64(&dyn->d_tag);
upx_uint64_t val = get_te64(&dyn->d_val); upx_uint64_t val = get_te64(&dyn->d_val);
@@ -5189,7 +5188,8 @@ PackLinuxElf32::check_pt_dynamic(Elf32_Phdr const *const phdr)
unsigned vaddr = get_te32(&phdr->p_vaddr); unsigned vaddr = get_te32(&phdr->p_vaddr);
unsigned filesz = get_te32(&phdr->p_filesz), memsz = get_te32(&phdr->p_memsz); unsigned filesz = get_te32(&phdr->p_filesz), memsz = get_te32(&phdr->p_memsz);
unsigned align = get_te32(&phdr->p_align); unsigned align = get_te32(&phdr->p_align);
if (s < t || (u32_t)file_size < s || t < sizeof(Elf32_Ehdr) if (s < t || (u32_t)file_size < (filesz + t)
|| t < (e_phnum*sizeof(Elf32_Phdr) + sizeof(Elf32_Ehdr))
|| (3 & t) || (7 & (filesz | memsz)) // .balign 4; 8==sizeof(Elf32_Dyn) || (3 & t) || (7 & (filesz | memsz)) // .balign 4; 8==sizeof(Elf32_Dyn)
|| (-1+ align) & (t ^ vaddr) || (-1+ align) & (t ^ vaddr)
|| (unsigned long)file_size <= memsz || (unsigned long)file_size <= memsz
@@ -5291,7 +5291,8 @@ PackLinuxElf64::check_pt_dynamic(Elf64_Phdr const *const phdr)
upx_uint64_t vaddr = get_te64(&phdr->p_vaddr); upx_uint64_t vaddr = get_te64(&phdr->p_vaddr);
upx_uint64_t filesz = get_te64(&phdr->p_filesz), memsz = get_te64(&phdr->p_memsz); upx_uint64_t filesz = get_te64(&phdr->p_filesz), memsz = get_te64(&phdr->p_memsz);
upx_uint64_t align = get_te64(&phdr->p_align); upx_uint64_t align = get_te64(&phdr->p_align);
if (s < t || (upx_uint64_t)file_size < s || t < sizeof(Elf64_Ehdr) if (s < t || (upx_uint64_t)file_size < (filesz + t)
|| t < (e_phnum*sizeof(Elf64_Phdr) + sizeof(Elf64_Ehdr))
|| (7 & t) || (0xf & (filesz | memsz)) // .balign 8; 16==sizeof(Elf64_Dyn) || (7 & t) || (0xf & (filesz | memsz)) // .balign 8; 16==sizeof(Elf64_Dyn)
|| (-1+ align) & (t ^ vaddr) || (-1+ align) & (t ^ vaddr)
|| (unsigned long)file_size <= memsz || (unsigned long)file_size <= memsz
@@ -5307,19 +5308,14 @@ PackLinuxElf64::check_pt_dynamic(Elf64_Phdr const *const phdr)
} }
void void
PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t dt_filesz) PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway)
{ {
if (dt_table[Elf64_Dyn::DT_NULL]) { if (dt_table[Elf64_Dyn::DT_NULL]) {
return; // not 1st time; do not change upx_dt_init return; // not 1st time; do not change upx_dt_init
} }
if (((u64_t)file_size - (e_phnum*sizeof(Elf64_Phdr) + sizeof(Elf64_Ehdr))) < dt_filesz) {
char msg[50]; snprintf(msg, sizeof(msg),
"bad PT_DYNAMIC.pt_filesz %#lx", (long unsigned)dt_filesz);
throwCantPack(msg);
}
Elf64_Dyn const *const dynp0 = dynp; Elf64_Dyn const *const dynp0 = dynp;
unsigned ndx = 1+ 0; unsigned ndx = 1+ 0;
unsigned const limit = dt_filesz / sizeof(*dynp); unsigned const limit = headway / sizeof(*dynp);
if (dynp) if (dynp)
for (; ; ++ndx, ++dynp) { for (; ; ++ndx, ++dynp) {
if (limit <= ndx) { if (limit <= ndx) {
@@ -5975,7 +5971,7 @@ void PackLinuxElf32::unpack(OutputFile *fo)
} }
Elf32_Dyn *dyn = (Elf32_Dyn *)((unsigned char *)ibuf + Elf32_Dyn *dyn = (Elf32_Dyn *)((unsigned char *)ibuf +
(dyn_off - load_off)); (dyn_off - load_off));
dynseg = dyn; invert_pt_dynamic(dynseg, get_te32(&udynhdr->p_filesz)); dynseg = dyn; invert_pt_dynamic(dynseg, file_size - dyn_off);
for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) {
unsigned const tag = get_te32(&dyn->d_tag); unsigned const tag = get_te32(&dyn->d_tag);
unsigned val = get_te32(&dyn->d_val); unsigned val = get_te32(&dyn->d_val);