Sync copyright year 2023

modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
	modified:   p_unix.cpp
	modified:   p_unix.h
This commit is contained in:
John Reiser 2023-01-02 08:28:41 -08:00 committed by Markus F.X.J. Oberhumer
parent 3ff5dbd179
commit 64aa7540e2
4 changed files with 161 additions and 86 deletions

View File

@ -4861,13 +4861,13 @@ PackLinuxElf64::unRela64(
upx_uint64_t r_info = get_te64(&rela->r_info);
unsigned r_type = ELF64_R_TYPE(r_info);
if (is_asl && Elf64_Ehdr::EM_AARCH64 == e_machine) {
#if 0 //{
if (R_AARCH64_RELATIVE == r_type) {
#if 0 //{ FIXME
if (old_dtinit == r_addend) {
set_te64(&ptload1[r_offset - plt_va], r_addend);
}
}
#endif //}
}
if (R_AARCH64_JUMP_SLOT == r_type) {
++n_jmp_slot;
// .rela.plt contains offset of the "first time" target
@ -4893,6 +4893,47 @@ PackLinuxElf64::unRela64(
}
}
void
PackLinuxElf64::un_asl_dynsym( // ibuf has the input
unsigned orig_file_size,
OutputFile *fo // else just leave in ibuf
)
{
// un-Relocate dynsym (DT_SYMTAB) which is below xct_off
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 (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(
"bad dynsym", off_dynsym, sz_dynsym);
Elf64_Sym *sym = sym0;
for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) {
upx_uint64_t symval = get_te64(&sym->st_value);
unsigned symsec = get_te16(&sym->st_shndx);
if (Elf64_Sym::SHN_UNDEF != symsec
&& Elf64_Sym::SHN_ABS != symsec
&& xct_off <= symval) {
set_te64(&sym->st_value, symval - asl_delta);
}
if (Elf64_Sym::SHN_ABS == symsec && xct_off <= symval) {
adjABS(sym, 0ul - (unsigned long)asl_delta);
}
}
if (fo) {
unsigned pos = fo->tell();
fo->seek(off_dynsym, SEEK_SET);
fo->rewrite(sym0, sz_dynsym);
fo->seek(pos, SEEK_SET);
}
}
}
// File layout of compressed .so (new-style: 3 or 4 PT_LOAD) shared library:
// 1. new Elf headers: Ehdr, PT_LOAD (r-x), PT_LOAD (rw-, if any), non-PT_LOAD Phdrs
// 2. Space for (original - 2) PT_LOAD Phdr
@ -4931,7 +4972,6 @@ void PackLinuxElf64::un_shlib_1(
unsigned const limit_dynhdr = get_te64(&dynhdr->p_offset) + get_te64(&dynhdr->p_filesz);
fi->readx(ibuf, limit_dynhdr);
//overlay_offset -= sizeof(linfo);
loader_offset = 0;
e_shoff = get_te64(&ehdri.e_shoff);
if (e_shoff && e_shnum
&& (e_shoff + sizeof(Elf64_Shdr) * e_shnum) <= limit_dynhdr) { // --android-shlib
@ -4941,40 +4981,6 @@ void PackLinuxElf64::un_shlib_1(
"bad Shdr table", e_shoff, sizeof(Elf64_Shdr)*e_shnum);
yct_off = get_te64(&shdri->sh_offset); // for the output file (de-compresssed)
xct_off = asl_delta + yct_off; // for the input file (compressed)
// un-Relocate dynsym (DT_SYMTAB) which is below xct_off
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 (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(
"bad dynsym", off_dynsym, sz_dynsym);
Elf64_Sym *sym = sym0;
for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) {
upx_uint64_t symval = get_te64(&sym->st_value);
unsigned symsec = get_te16(&sym->st_shndx);
if (Elf64_Sym::SHN_UNDEF != symsec
&& Elf64_Sym::SHN_ABS != symsec
&& xct_off <= symval) {
set_te64(&sym->st_value, symval - asl_delta);
}
if (Elf64_Sym::SHN_ABS == symsec && xct_off <= symval) {
adjABS(sym, 0ul - (unsigned long)asl_delta);
}
}
#if 0 //{ Stupid MSVC 14.2, 14.3
if (0 && fo) {
fo->seek(off_dynsym, SEEK_SET);
fo->rewrite(sym0, sz_dynsym);
}
#endif //}
}
}
// Decompress first Extent. Old style covers [0, xct_off)
@ -4989,7 +4995,6 @@ void PackLinuxElf64::un_shlib_1(
struct {
struct l_info l;
struct p_info p;
struct b_info b;
} hdr;
fi->readx(&hdr, sizeof(hdr));
if (hdr.l.l_magic != UPX_MAGIC_LE32
@ -4997,17 +5002,39 @@ void PackLinuxElf64::un_shlib_1(
|| hdr.p.p_filesize != ph.u_file_size) {
throwCantUnpack("corrupt l_info/p_info");
}
ph.c_len = get_te32(&hdr.b.sz_cpr);
ph.u_len = get_te32(&hdr.b.sz_unc);
#define MAX_ELF_HDR 1024
if (MAX_ELF_HDR < ph.u_len) {
// FIXME: old-style (upx < 4.0) compresses up to xct_off
throwCantUnpack("ElfXX_Ehdr corrupted");
// The default layout for a shared library created by binutils-2.29
// (Fedora 28; 2018) has two PT_LOAD: permissions r-x and rw-.
// xct_off (the lowest address of executable instructions;
// the highest address of read-only data used by rtld (ld-linux))
// will be somewhere in the first PT_LOAD.
//
// The default layout for a shared library created by binutils-2.31
// (Fedora 29; 2018) has four PT_LOAD: permissions r--, r-x, r--, rw-.
// xct_off will be the base of the second [r-x] PT_LOAD.
//
// Bytes below xct_off cannot be compressed because they are used
// by rtld *before* the UPX run-time de-compression stub gets control
// via DT_INIT. Bytes in a Writeable PT_LOAD cannot be compressed
// because they may be relocated by rtld, again before stub execution.
//
// We need to know which layout of PT_LOAD. It seems risky to steal
// bits in the input ElfXX_Ehdr or ElfXX_Phdr, so we decompress
// the first compressed block. For an old-style shared library
// the first compressed block covers [0, xct_off) which is redundant
// with the interval [sz_elf_hdrs, xct_off) because those bytes
// must be present for use by rtl (So that is a large inefficiency.)
// Fortunately p_info.p_blocksize fits in ibuf, and unpackExtent
// will just decompress it all. For new style, the first compressed
// block covers [0, sz_elf_hdrs).
// Peek: unpack into ibuf, but do not write
unsigned const sz_block1 = unpackExtent(sz_elf_hdrs, nullptr,
c_adler, u_adler, false, szb_info, -1);
if (sz_block1 < sz_elf_hdrs) {
throwCantUnpack("corrupt b_info");
}
fi->readx(ibuf, ph.c_len);
fi->seek(-(off_t)(sizeof(b_info) + ph.c_len), SEEK_CUR);
decompress(ibuf, o_elfhdrs, false);
memcpy(o_elfhdrs, ibuf, sz_elf_hdrs); // save de-compressed Elf headers
Elf64_Ehdr const *const ehdro = (Elf64_Ehdr const *)(void const *)o_elfhdrs;
if (ehdro->e_type !=ehdri.e_type
|| ehdro->e_machine!=ehdri.e_machine
@ -5020,19 +5047,13 @@ void PackLinuxElf64::un_shlib_1(
|| memcmp(ehdro->e_ident, ehdri.e_ident, Elf64_Ehdr::EI_OSABI)) {
throwCantUnpack("ElfXX_Ehdr corrupted");
}
unpackExtent(ph.u_len, fo,
c_adler, u_adler, false, szb_info);
if (fo) {
// Re-generate unmodified rtld data below xct_off
// FIXME: depends on (yct_off < limit_dynhdr)
unsigned d = yct_off - ph.u_len;
fo->write(&ibuf[ph.u_len], d);
total_out += d;
fo->write(ibuf, sz_block1);
total_out = sz_block1;
}
Elf64_Phdr const *o_phdr = (Elf64_Phdr const *)(1+ (Elf64_Ehdr const *)(void const *)o_elfhdrs);
Elf64_Phdr const *o_phdr = (Elf64_Phdr const *)(1+ ehdro);
// Handle compressed PT_LOADs (must not have PF_W)
unsigned not_first_LOAD = 0;
for (unsigned j = 0; j < e_phnum; ++j, ++o_phdr) {
unsigned type = get_te32(&o_phdr->p_type);
unsigned flags = get_te32(&o_phdr->p_flags);
@ -5041,27 +5062,56 @@ void PackLinuxElf64::un_shlib_1(
}
unsigned p_offset = get_te64(&o_phdr->p_offset);
unsigned p_filesz = get_te64(&o_phdr->p_filesz);
if ((p_filesz + p_offset) <= yct_off) {
continue; // already entirely re-generated
}
if (p_offset < yct_off) {
p_offset = yct_off; // not at beginning of PT_LOAD
unsigned wanted = p_filesz;
if (!not_first_LOAD++) { // first PT_LOAD
wanted -= sz_block1;
if (sz_block1 > sz_elf_hdrs) { // old style
if (is_asl) {
un_asl_dynsym(orig_file_size, fo);
}
p_offset += sz_block1;
}
if (sz_block1 == sz_elf_hdrs) { // new style
unsigned const len = yct_off - sz_elf_hdrs;
unsigned const ipos = fi->tell();
fi->seek(sz_elf_hdrs, SEEK_SET);
fi->readx(&ibuf[sz_elf_hdrs], len);
if (is_asl) {
un_asl_dynsym(orig_file_size, nullptr);
}
if (fo) {
fo->write(&ibuf[sz_elf_hdrs], len);
}
total_out += len;
// github-issue629: (overlay_offset = 0xa500), so initially (xct_off = 0xa494).
// But "yct_off = get_te64(&shdri->sh_offset)" so if _Shdrs are aligned (??)
// then (0x10500 == (xct_off = asl_delta + yct_off)), and we read+write
// more than we need.
// So assume the excess just lives there, or is overwritten later by seek+write.
if (wanted < len) { // FIXME: why does this happen?
wanted = 0;
}
else {
wanted -= len;
}
fi->seek(ipos, SEEK_SET);
if (total_out == p_filesz) {
continue; // already entirely re-generated
}
p_offset = total_out;
}
}
if (fo) {
fo->seek(p_offset, SEEK_SET);
}
// Peek at b_info to find sizes
fi->readx(&hdr.b, sizeof(hdr.b));
fi->seek(-(off_t)sizeof(struct b_info), SEEK_CUR);
ph.c_len = get_te32(&hdr.b.sz_cpr);
ph.u_len = get_te32(&hdr.b.sz_unc);
unpackExtent(ph.u_len, fo, c_adler, u_adler, false, szb_info);
unpackExtent(wanted, fo, c_adler, u_adler, false, szb_info);
}
funpad4(fi);
loader_offset = fi->tell();
// Handle PT_LOAD with PF_W: writeable, so not compressed. "Slide"
o_phdr = (Elf64_Phdr const *)(1+ (Elf64_Ehdr const *)(void const *)o_elfhdrs);
o_phdr = (Elf64_Phdr const *)(1+ ehdro);
Elf64_Phdr const *i_phdr = phdri;
for (unsigned j = 0; j < e_phnum; ++j, ++o_phdr, ++i_phdr) {
unsigned type = get_te32(&o_phdr->p_type);

View File

@ -278,6 +278,7 @@ protected:
virtual off_t pack3(OutputFile *, Filter &) override; // append loader
virtual void pack4(OutputFile *, Filter &) override; // append pack header
virtual void unpack(OutputFile *fo) override;
virtual void un_asl_dynsym(unsigned orig_file_size, OutputFile *);
virtual void un_shlib_1(
OutputFile *const fo,
MemBuffer &o_elfhdrs,

View File

@ -451,12 +451,18 @@ void PackUnix::packExtent(
}
}
void PackUnix::unpackExtent(unsigned wanted, OutputFile *fo,
// Consumes b_info header block and sz_cpr data block from input file 'fi'.
// De-compresses; appends to output file 'fo' unless rewrite or peeking.
// For "peeking" without writing: set (fo = nullptr), (is_rewrite = -1)
// Return actual length when peeking; else 0.
unsigned PackUnix::unpackExtent(unsigned wanted, OutputFile *fo,
unsigned &c_adler, unsigned &u_adler,
bool first_PF_X, unsigned szb_info, bool is_rewrite
bool first_PF_X, unsigned szb_info,
int is_rewrite // 0(false): write; 1(true): rewrite; -1: no write
)
{
b_info hdr; memset(&hdr, 0, sizeof(hdr));
unsigned inlen = 0; // output index (if-and-only-if peeking)
while (wanted) {
fi->readx(&hdr, szb_info);
int const sz_unc = ph.u_len = get_te32(&hdr.sz_unc);
@ -472,21 +478,22 @@ void PackUnix::unpackExtent(unsigned wanted, OutputFile *fo,
if (sz_cpr > sz_unc || sz_unc > (int)blocksize)
throwCantUnpack("corrupt b_info");
int j = blocksize + OVERHEAD - sz_cpr;
// place the input for overlapping de-compression
// FIXME: inlen cheats OVERHEAD; assumes small wanted peek length
int j = inlen + blocksize + OVERHEAD - sz_cpr;
fi->readx(ibuf+j, sz_cpr);
total_in += sz_cpr;
total_in += sz_cpr;
// update checksum of compressed data
c_adler = upx_adler32(ibuf + j, sz_cpr, c_adler);
// decompress
if (sz_cpr < sz_unc)
{
decompress(ibuf+j, ibuf, false);
if (sz_cpr < sz_unc) { // block was compressed
decompress(ibuf+j, ibuf+inlen, false);
if (12==szb_info) { // modern per-block filter
if (hdr.b_ftid) {
Filter ft(ph.level); // FIXME: ph.level for b_info?
ft.init(hdr.b_ftid, 0);
ft.cto = hdr.b_cto8;
ft.unfilter(ibuf, sz_unc);
ft.unfilter(ibuf+inlen, sz_unc);
}
}
else { // ancient per-file filter
@ -497,27 +504,38 @@ void PackUnix::unpackExtent(unsigned wanted, OutputFile *fo,
Filter ft(ph.level);
ft.init(ph.filter, 0);
ft.cto = (unsigned char) ph.filter_cto;
ft.unfilter(ibuf, sz_unc);
ft.unfilter(ibuf+inlen, sz_unc);
}
}
j = 0;
}
else if (sz_cpr == sz_unc) { // slide literal (non-compressible) block
memmove(&ibuf[inlen], &ibuf[j], sz_unc);
}
// update checksum of uncompressed data
u_adler = upx_adler32(ibuf + j, sz_unc, u_adler);
u_adler = upx_adler32(ibuf + inlen, sz_unc, u_adler);
// write block
if (fo) {
if (is_rewrite) {
fo->rewrite(ibuf + j, sz_unc);
fo->rewrite(ibuf, sz_unc);
}
else {
fo->write(ibuf + j, sz_unc);
fo->write(ibuf, sz_unc);
total_out += sz_unc;
}
}
if (wanted < (unsigned)sz_unc)
else if (is_rewrite < 0) { // append to &ibuf[inlen]
inlen += sz_unc; // accounting; data is already there
if (wanted <= (unsigned)sz_unc) // done
break;
}
else if (wanted < (unsigned)sz_unc) // mismatched end-of-block
throwCantUnpack("corrupt b_info");
else { // "upx -t": (!fo && !(is_rewrite < 0))
// No output.
}
wanted -= sz_unc;
}
return inlen;
}
/*************************************************************************

View File

@ -4,6 +4,7 @@
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2023 Laszlo Molnar
Copyright (C) 2000-2023 John F. Reiser
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
@ -23,6 +24,9 @@
Markus F.X.J. Oberhumer Laszlo Molnar
<markus@oberhumer.com> <ezerotven+github@gmail.com>
John F. Reiser
<jreiser@users.sourceforge.net>
*/
@ -76,9 +80,11 @@ protected:
Filter *, OutputFile *,
unsigned hdr_len = 0, unsigned b_extra = 0 ,
bool inhibit_compression_check = false);
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
virtual unsigned unpackExtent(unsigned wanted, OutputFile *fo,
unsigned &c_adler, unsigned &u_adler,
bool first_PF_X, unsigned szb_info, bool is_rewrite = false);
bool first_PF_X, unsigned szb_info,
int is_rewrite = false // 0(false): write; 1(true): rewrite; -1: no write
);
unsigned total_in, total_out; // unpack
int exetype;