Corner cases for e_shnum vs e_shstrndx

modified:   p_lx_elf.cpp
This commit is contained in:
John Reiser
2018-12-16 15:36:51 -08:00
parent a784284b7f
commit 8e90c9af2b
+30 -14
View File
@@ -1645,9 +1645,10 @@ PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp)
} }
} }
unsigned const e_shstrndx = get_te16(&ehdri.e_shstrndx); unsigned const e_shstrndx = get_te16(&ehdri.e_shstrndx);
if (e_shnum <= e_shstrndx) { if (e_shnum <= e_shstrndx
&& !(0==e_shnum && 0==e_shstrndx) ) {
char msg[40]; snprintf(msg, sizeof(msg), char msg[40]; snprintf(msg, sizeof(msg),
"bad .e_shstrndx %d > .e_shnum %d", e_shstrndx, e_shnum); "bad .e_shstrndx %d >= .e_shnum %d", e_shstrndx, e_shnum);
throwCantPack(msg); throwCantPack(msg);
} }
} }
@@ -1956,12 +1957,11 @@ bool PackLinuxElf32::canPack()
phdri= (Elf32_Phdr *)((size_t)e_phoff + file_image); // do not free() !! phdri= (Elf32_Phdr *)((size_t)e_phoff + file_image); // do not free() !!
shdri= (Elf32_Shdr *)((size_t)e_shoff + file_image); // do not free() !! shdri= (Elf32_Shdr *)((size_t)e_shoff + file_image); // do not free() !!
if (!e_shnum) {
sec_strndx = NULL; sec_strndx = NULL;
shstrtab = NULL; shstrtab = NULL;
} if (e_shnum) {
else {
unsigned const e_shstrndx = get_te16(&ehdr->e_shstrndx); unsigned const e_shstrndx = get_te16(&ehdr->e_shstrndx);
if (e_shstrndx) {
if (e_shnum <= e_shstrndx) { if (e_shnum <= e_shstrndx) {
char msg[40]; snprintf(msg, sizeof(msg), char msg[40]; snprintf(msg, sizeof(msg),
"bad e_shstrndx %#x >= e_shnum %d", e_shstrndx, e_shnum); "bad e_shstrndx %#x >= e_shnum %d", e_shstrndx, e_shnum);
@@ -1975,6 +1975,7 @@ bool PackLinuxElf32::canPack()
throwCantPack(msg); throwCantPack(msg);
} }
shstrtab = (char const *)(sh_offset + file_image); shstrtab = (char const *)(sh_offset + file_image);
}
sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM); sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM);
if (sec_dynsym) { if (sec_dynsym) {
unsigned const sh_link = get_te32(&sec_dynsym->sh_link); unsigned const sh_link = get_te32(&sec_dynsym->sh_link);
@@ -1985,13 +1986,17 @@ bool PackLinuxElf32::canPack()
sec_dynstr = &shdri[sh_link]; sec_dynstr = &shdri[sh_link];
} }
if (sec_strndx) {
unsigned const sh_name = get_te32(&sec_strndx->sh_name); unsigned const sh_name = get_te32(&sec_strndx->sh_name);
if (Elf32_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type) if (Elf32_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type)
|| file_size <= (off_t)sh_name // FIXME: weak || file_size <= (off_t)sh_name // FIXME: weak
|| 0!=strcmp((char const *)".shstrtab", &shstrtab[sh_name]) ) { || (sh_name
&& 0!=strcmp((char const *)".shstrtab", &shstrtab[sh_name]))
) {
throwCantPack("bad e_shstrndx"); throwCantPack("bad e_shstrndx");
} }
} }
}
phdr= phdri; phdr= phdri;
for (int j= e_phnum; --j>=0; ++phdr) for (int j= e_phnum; --j>=0; ++phdr)
@@ -2239,12 +2244,11 @@ PackLinuxElf64::canPack()
phdri= (Elf64_Phdr *)((size_t)e_phoff + file_image); // do not free() !! phdri= (Elf64_Phdr *)((size_t)e_phoff + file_image); // do not free() !!
shdri= (Elf64_Shdr *)((size_t)e_shoff + file_image); // do not free() !! shdri= (Elf64_Shdr *)((size_t)e_shoff + file_image); // do not free() !!
if (!e_shnum) {
sec_strndx = NULL; sec_strndx = NULL;
shstrtab = NULL; shstrtab = NULL;
} if (e_shnum) {
else {
unsigned const e_shstrndx = get_te16(&ehdr->e_shstrndx); unsigned const e_shstrndx = get_te16(&ehdr->e_shstrndx);
if (e_shstrndx) {
if (e_shnum <= e_shstrndx) { if (e_shnum <= e_shstrndx) {
char msg[40]; snprintf(msg, sizeof(msg), char msg[40]; snprintf(msg, sizeof(msg),
"bad e_shstrndx %#x >= e_shnum %d", e_shstrndx, e_shnum); "bad e_shstrndx %#x >= e_shnum %d", e_shstrndx, e_shnum);
@@ -2258,6 +2262,7 @@ PackLinuxElf64::canPack()
throwCantPack(msg); throwCantPack(msg);
} }
shstrtab = (char const *)(sh_offset + file_image); shstrtab = (char const *)(sh_offset + file_image);
}
sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM); sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM);
if (sec_dynsym) { if (sec_dynsym) {
upx_uint64_t const sh_link = get_te64(&sec_dynsym->sh_link); upx_uint64_t const sh_link = get_te64(&sec_dynsym->sh_link);
@@ -2268,13 +2273,17 @@ PackLinuxElf64::canPack()
sec_dynstr = &shdri[sh_link]; sec_dynstr = &shdri[sh_link];
} }
if (sec_strndx) {
unsigned const sh_name = get_te32(&sec_strndx->sh_name); unsigned const sh_name = get_te32(&sec_strndx->sh_name);
if (Elf64_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type) if (Elf64_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type)
|| file_size <= (off_t)sh_name // FIXME: weak || file_size <= (off_t)sh_name // FIXME: weak
|| 0!=strcmp((char const *)".shstrtab", &shstrtab[sh_name]) ) { || (sh_name
&& 0!=strcmp((char const *)".shstrtab", &shstrtab[sh_name]))
) {
throwCantPack("bad e_shstrndx"); throwCantPack("bad e_shstrndx");
} }
} }
}
phdr= phdri; phdr= phdri;
for (int j= e_phnum; --j>=0; ++phdr) for (int j= e_phnum; --j>=0; ++phdr)
@@ -4251,6 +4260,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
"bad DYNAMIC", get_te64(&dynhdr->p_offset), get_te64(&dynhdr->p_filesz)); "bad DYNAMIC", get_te64(&dynhdr->p_offset), get_te64(&dynhdr->p_filesz));
dynstr = (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB); dynstr = (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB);
sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM); 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 off_dynsym = get_te64(&sec_dynsym->sh_offset);
upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size); upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size);
Elf64_Sym *const sym0 = (Elf64_Sym *)ibuf.subref( Elf64_Sym *const sym0 = (Elf64_Sym *)ibuf.subref(
@@ -4269,6 +4279,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
} }
} }
} }
}
if (fo) { if (fo) {
fo->write(ibuf + ph.u_len, xct_off - ph.u_len); fo->write(ibuf + ph.u_len, xct_off - ph.u_len);
} }
@@ -4668,9 +4679,10 @@ PackLinuxElf32::check_pt_dynamic(Elf32_Phdr const *const phdr)
unsigned t = get_te32(&phdr->p_offset), s = sizeof(Elf32_Dyn) + t; unsigned t = get_te32(&phdr->p_offset), s = sizeof(Elf32_Dyn) + t;
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);
if (s < t || file_size < (off_t)s if (s < t || file_size < (off_t)s
|| (3 & t) || (7 & (filesz | memsz)) // .balign 4; 8==sizeof(Elf32_Dyn) || (3 & t) || (7 & (filesz | memsz)) // .balign 4; 8==sizeof(Elf32_Dyn)
|| (-1+ page_size) & (t ^ vaddr) || (-1+ align) & (t ^ vaddr)
|| filesz < sizeof(Elf32_Dyn) || filesz < sizeof(Elf32_Dyn)
|| memsz < sizeof(Elf32_Dyn) || memsz < sizeof(Elf32_Dyn)
|| filesz < memsz) { || filesz < memsz) {
@@ -4748,9 +4760,10 @@ PackLinuxElf64::check_pt_dynamic(Elf64_Phdr const *const phdr)
upx_uint64_t t = get_te64(&phdr->p_offset), s = sizeof(Elf64_Dyn) + t; upx_uint64_t t = get_te64(&phdr->p_offset), s = sizeof(Elf64_Dyn) + t;
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);
if (s < t || (upx_uint64_t)file_size < s if (s < t || (upx_uint64_t)file_size < s
|| (7 & t) || (0xf & (filesz | memsz)) // .balign 8; 16==sizeof(Elf64_Dyn) || (7 & t) || (0xf & (filesz | memsz)) // .balign 8; 16==sizeof(Elf64_Dyn)
|| (-1+ page_size) & (t ^ vaddr) || (-1+ align) & (t ^ vaddr)
|| filesz < sizeof(Elf64_Dyn) || filesz < sizeof(Elf64_Dyn)
|| memsz < sizeof(Elf64_Dyn) || memsz < sizeof(Elf64_Dyn)
|| filesz < memsz) { || filesz < memsz) {
@@ -4860,9 +4873,10 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp)
} }
} }
unsigned const e_shstrndx = get_te16(&ehdri.e_shstrndx); unsigned const e_shstrndx = get_te16(&ehdri.e_shstrndx);
if (e_shnum <= e_shstrndx) { if (e_shnum <= e_shstrndx
&& !(0==e_shnum && 0==e_shstrndx) ) {
char msg[40]; snprintf(msg, sizeof(msg), char msg[40]; snprintf(msg, sizeof(msg),
"bad .e_shstrndx %d > .e_shnum %d", e_shstrndx, e_shnum); "bad .e_shstrndx %d >= .e_shnum %d", e_shstrndx, e_shnum);
throwCantPack(msg); throwCantPack(msg);
} }
} }
@@ -5123,6 +5137,7 @@ void PackLinuxElf32::unpack(OutputFile *fo)
"bad DYNAMIC", get_te32(&dynhdr->p_offset), get_te32(&dynhdr->p_filesz)); "bad DYNAMIC", get_te32(&dynhdr->p_offset), get_te32(&dynhdr->p_filesz));
dynstr = (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB); dynstr = (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB);
sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM); 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 off_dynsym = get_te32(&sec_dynsym->sh_offset);
unsigned const sz_dynsym = get_te32(&sec_dynsym->sh_size); unsigned const sz_dynsym = get_te32(&sec_dynsym->sh_size);
Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref( Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref(
@@ -5141,6 +5156,7 @@ void PackLinuxElf32::unpack(OutputFile *fo)
} }
} }
} }
}
if (fo) { if (fo) {
fo->write(ibuf + ph.u_len, xct_off - ph.u_len); fo->write(ibuf + ph.u_len, xct_off - ph.u_len);
} }