ELF: amd64-linux main programs use 2-step de-compressor

The first $ARCH to move to 2-step de-compressor for ELF main programs.
De-compressor uses memfd_create to comply with strictest SELinux
settings (no PROT_WRITE on any PROT_EXEC page).
First step de-compressor always uses NRV2B to de-compress the second step,
and the second step can use a different de-compressor for each PT_LOAD.
	modified:   p_lx_elf.cpp
	modified:   stub/Makefile
	modified:   stub/src/amd64-linux.elf-fold.lds
	modified:   stub/src/amd64-linux.elf-entry.S
	modified:   stub/src/amd64-linux.elf-fold.S
	new file:   stub/src/amd64-linux.elf-main2.c

	modified:   stub/amd64-linux.elf-entry.h
	modified:   stub/amd64-linux.elf-fold.h
	modified:   stub/tmp/amd64-linux.elf-entry.bin.dump
	modified:   stub/tmp/amd64-linux.elf-fold.map
This commit is contained in:
John Reiser
2024-06-21 10:43:47 -07:00
parent 44e4bd0b54
commit c36977f0b1
10 changed files with 2547 additions and 1153 deletions
+156 -17
View File
@@ -1466,7 +1466,7 @@ PackLinuxElf32::buildLinuxLoader(
// EXP_TAIL FIXME: unfilter
// SO_TAIL
// SO_MAIN C-language supervision based on PT_LOADs
char sec[120];
char sec[120]; memset(sec, 0, sizeof(sec)); // debug convenience
int len = 0;
unsigned m_decompr = (methods_used ? methods_used : (1u << ph_forced_method(ph.method)));
len += snprintf(sec, sizeof(sec), "%s", "SO_HEAD,ptr_NEXT,EXP_HEAD");
@@ -1494,8 +1494,44 @@ PackLinuxElf32::buildLinuxLoader(
method = M_NRV2B_LE32; // requires unaligned fetch
if (this->e_machine==Elf32_Ehdr::EM_ARM)
method = M_NRV2B_8; //only ARM v6 and above has unaligned fetch
} // end shlib
else if (0
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_386
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_MIPS
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_PPC
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_ARM
) { // main program with ELF2 de-compressor
initLoader(fold, szfold);
char sec[120];
int len = 0;
unsigned m_decompr = (methods_used ? methods_used : (1u << ph_forced_method(ph.method)));
len += snprintf(sec, sizeof(sec), "%s", ".text,EXP_HEAD");
if (((1u<<M_NRV2B_LE32)|(1u<<M_NRV2B_8)|(1u<<M_NRV2B_LE16)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2B");
}
if (((1u<<M_NRV2D_LE32)|(1u<<M_NRV2D_8)|(1u<<M_NRV2D_LE16)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2D");
}
if (((1u<<M_NRV2E_LE32)|(1u<<M_NRV2E_8)|(1u<<M_NRV2E_LE16)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2E");
}
if (((1u<<M_LZMA)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30");
}
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "SYSCALLS,EXP_TAIL");
(void)len;
addLoader(sec, nullptr);
relocateLoader();
{
int sz_unc_int;
uncLoader = linker->getLoader(&sz_unc_int);
sz_unc = sz_unc_int;
}
method = M_NRV2B_LE32; // requires unaligned fetch
if (this->e_machine==Elf32_Ehdr::EM_ARM)
method = M_NRV2B_8; //only ARM v6 and above has unaligned fetch
}
else {
else { // main program with ELF1 de-compressor
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
unsigned fold_hdrlen = upx::umax(0x80u, usizeof(hf->ehdr) +
get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum) +
@@ -1529,16 +1565,28 @@ PackLinuxElf32::buildLinuxLoader(
initLoader(proto, szproto, -1, sz_cpr);
NO_printf("FOLDEXEC unc=%#x cpr=%#x\n", sz_unc, sz_cpr);
linker->addSection("FOLDEXEC", mb_cprLoader, sizeof(b_info) + sz_cpr, 0);
if (xct_off
&& ( this->e_machine==Elf32_Ehdr::EM_ARM
if (xct_off // shlib
&& (0
|| this->e_machine==Elf32_Ehdr::EM_ARM
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_MIPS
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_PPC
|| this->e_machine==Elf32_Ehdr::EM_386)
) {
) { // shlib with ELF2 de-compressor
addLoader("ELFMAINX,ELFMAINZ,FOLDEXEC,IDENTSTR");
}
else {
else if (0
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_ARM
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_MIPS
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_PPC
//ELF2 NYI || this->e_machine==Elf32_Ehdr::EM_386
) { // main program with ELF2 de-compressor
addLoader("ELFMAINX,ELFMAINZ,FOLDEXEC,IDENTSTR");
defineSymbols(ft);
}
else { // ELF1 de-compressor
addStubEntrySections(ft, (methods_used ? methods_used
: (1u << ph_forced_method(ph.method))) );
if (!xct_off) {
if (!xct_off) { // main program
defineSymbols(ft);
}
}
@@ -1601,7 +1649,40 @@ PackLinuxElf64::buildLinuxLoader(
}
method = M_NRV2B_LE32; // requires unaligned fetch
}
else {
else if (0
|| this->e_machine==Elf64_Ehdr::EM_X86_64
//ELF2 NYI || this->e_machine==Elf64_Ehdr::EM_PPC64
//ELF2 NYI || this->e_machine==Elf64_Ehdr::EM_AARCH64
) { // main program with ELF2 de-compressor
initLoader(fold, szfold);
char sec[120]; memset(sec, 0, sizeof(sec)); // debug convenience
int len = 0;
unsigned m_decompr = (methods_used ? methods_used : (1u << ph_forced_method(ph.method)));
len += snprintf(sec, sizeof(sec), "%s", ".text,EXP_HEAD");
if (((1u<<M_NRV2B_LE32)|(1u<<M_NRV2B_8)|(1u<<M_NRV2B_LE16)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2B");
}
if (((1u<<M_NRV2D_LE32)|(1u<<M_NRV2D_8)|(1u<<M_NRV2D_LE16)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2D");
}
if (((1u<<M_NRV2E_LE32)|(1u<<M_NRV2E_8)|(1u<<M_NRV2E_LE16)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2E");
}
if (((1u<<M_LZMA)) & m_decompr) {
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30");
}
len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "SYSCALLS,EXP_TAIL");
(void)len;
addLoader(sec, nullptr);
relocateLoader();
{
int sz_unc_int;
uncLoader = linker->getLoader(&sz_unc_int);
sz_unc = sz_unc_int;
}
method = M_NRV2B_LE32; // requires unaligned fetch
}
else { // not shlib: main program with ELF1 de-compressor
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
unsigned fold_hdrlen = upx::umax(0x80u, usizeof(hf->ehdr) +
get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum) +
@@ -1630,18 +1711,34 @@ PackLinuxElf64::buildLinuxLoader(
set_te32(&h.sz_cpr, h.sz_cpr);
set_te32(&h.sz_unc, h.sz_unc);
memcpy(cprLoader, &h, sizeof(h)); // cprLoader will become FOLDEXEC
}
} // end (0 < szfold)
initLoader(proto, szproto, -1, sz_cpr);
NO_printf("FOLDEXEC unc=%#x cpr=%#x\n", sz_unc, sz_cpr);
linker->addSection("FOLDEXEC", mb_cprLoader, sizeof(b_info) + sz_cpr, 0);
if (xct_off
&& ( this->e_machine==Elf64_Ehdr::EM_X86_64
&& (0
|| this->e_machine==Elf64_Ehdr::EM_X86_64
//ELF2 NYI || this->e_machine==Elf64_Ehdr::EM_PPC64
|| this->e_machine==Elf64_Ehdr::EM_AARCH64)
) {
addLoader("ELFMAINX,ELFMAINZ,FOLDEXEC,IDENTSTR");
} // shlib
else if (0
|| this->e_machine==Elf64_Ehdr::EM_X86_64
//ELF2 NYI || this->e_machine==Elf64_Ehdr::EM_PPC64
//ELF2 NYI || this->e_machine==Elf64_Ehdr::EM_AARCH64
) { // main program with ELF2 de-compressor
addLoader("ELFMAINX,ELFMAINZ,FOLDEXEC,IDENTSTR");
if (this->e_machine==Elf64_Ehdr::EM_PPC64
&& elfout.ehdr.e_ident[Elf64_Ehdr::EI_DATA]==Elf64_Ehdr::ELFDATA2MSB) {
addLoader("ELFMAINZe");
}
if (!xct_off) {
defineSymbols(ft);
}
}
else {
else { // main program with ELF1 de-compressor
addStubEntrySections(ft, (methods_used ? methods_used
: (1u << ph_forced_method(ph.method))) );
if (!xct_off) {
@@ -3460,10 +3557,24 @@ PackLinuxElf32::generateElfHdr(
cprElfHdr2 *const h2 = (cprElfHdr2 *)(void *)&elfout;
cprElfHdr3 *const h3 = (cprElfHdr3 *)(void *)&elfout;
h3->ehdr = ((cprElfHdr3 const *)proto)->ehdr;
h3->phdr[C_BASE] = ((cprElfHdr3 const *)proto)->phdr[1]; // .data; .p_align
h3->phdr[C_TEXT] = ((cprElfHdr3 const *)proto)->phdr[0]; // .text
if (Elf32_Ehdr::ET_REL == get_te16(&h3->ehdr.e_type)) {
set_te32(&h3->ehdr.e_phoff, sizeof(Elf32_Ehdr));
set_te16(&h3->ehdr.e_ehsize,sizeof(Elf32_Ehdr));
set_te16(&h3->ehdr.e_phentsize, sizeof(Elf32_Phdr));
set_te16(&h3->ehdr.e_phnum, 2);
memset(&h3->phdr[C_BASE], 0, sizeof(h3->phdr[C_BASE]));
memset(&h3->phdr[C_TEXT], 0, sizeof(h3->phdr[C_TEXT]));
memset(&h3->phdr[2 ], 0, sizeof(h3->phdr[2 ]));
set_te32(&h3->phdr[C_BASE].p_flags, 0);
set_te32(&h3->phdr[C_TEXT].p_flags, Elf32_Phdr::PF_X| Elf32_Phdr::PF_R);
}
else {
h3->phdr[C_BASE] = ((cprElfHdr3 const *)proto)->phdr[1]; // .data; .p_align
h3->phdr[C_TEXT] = ((cprElfHdr3 const *)proto)->phdr[0]; // .text
}
h3->ehdr.e_type = ehdri.e_type; // ET_EXEC vs ET_DYN (gcc -pie -fPIC)
memset(&h3->linfo, 0, sizeof(h3->linfo));
h3->ehdr.e_ident[Elf32_Ehdr::EI_OSABI] = ei_osabi;
if (Elf32_Ehdr::EM_MIPS==e_machine) { // MIPS R3000 FIXME
h3->ehdr.e_ident[Elf32_Ehdr::EI_OSABI] = Elf32_Ehdr::ELFOSABI_NONE;
@@ -3749,8 +3860,22 @@ PackLinuxElf64::generateElfHdr(
cprElfHdr2 *const h2 = (cprElfHdr2 *)(void *)&elfout;
cprElfHdr3 *const h3 = (cprElfHdr3 *)(void *)&elfout;
h3->ehdr = ((cprElfHdr3 const *)proto)->ehdr;
h3->phdr[C_BASE] = ((cprElfHdr3 const *)proto)->phdr[1]; // .data; .p_align
h3->phdr[C_TEXT] = ((cprElfHdr3 const *)proto)->phdr[0]; // .text
if (Elf64_Ehdr::ET_REL == get_te16(&h3->ehdr.e_type)) {
set_te64(&h3->ehdr.e_phoff, sizeof(Elf64_Ehdr));
set_te16(&h3->ehdr.e_ehsize,sizeof(Elf64_Ehdr));
set_te16(&h3->ehdr.e_phentsize, sizeof(Elf64_Phdr));
set_te16(&h3->ehdr.e_phnum, 2);
memset(&h3->phdr[C_BASE], 0, sizeof(h3->phdr[C_BASE]));
memset(&h3->phdr[C_TEXT], 0, sizeof(h3->phdr[C_TEXT]));
memset(&h3->phdr[2 ], 0, sizeof(h3->phdr[2 ]));
set_te32(&h3->phdr[C_BASE].p_flags, 0);
set_te32(&h3->phdr[C_TEXT].p_flags, Elf64_Phdr::PF_X| Elf64_Phdr::PF_R);
}
else {
h3->phdr[C_BASE] = ((cprElfHdr3 const *)proto)->phdr[1]; // .data; .p_align
h3->phdr[C_TEXT] = ((cprElfHdr3 const *)proto)->phdr[0]; // .text
}
memset(&h3->linfo, 0, sizeof(h3->linfo));
h3->ehdr.e_type = ehdri.e_type; // ET_EXEC vs ET_DYN (gcc -pie -fPIC)
h3->ehdr.e_ident[Elf64_Ehdr::EI_OSABI] = ei_osabi;
@@ -3774,13 +3899,27 @@ PackLinuxElf64::generateElfHdr(
h2->ehdr.e_shstrndx = o_elf_shnum - 1;
}
else {
// https://bugzilla.redhat.com/show_bug.cgi?id=2131609
// 0==.e_shnum is a special case for libbfd
// that requires 0==.e_shentsize in order to force "no Shdrs"
h2->ehdr.e_shentsize = 0;
h2->ehdr.e_shnum = 0;
h2->ehdr.e_shstrndx = 0;
}
unsigned phnum_o = 2 + n_phdrx; // C_BASE, C_TEXT
unsigned const phnum_i = get_te16(&h2->ehdr.e_phnum);
unsigned phnum_o = 2 + n_phdrx; // C_BASE, C_TEXT
set_te16(&h2->ehdr.e_phnum, phnum_o);
o_binfo = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phnum_o + sizeof(l_info) + sizeof(p_info);
set_te64(&h2->phdr[C_TEXT].p_filesz, sizeof(*h2)); // + identsize;
h2->phdr[C_TEXT].p_memsz = h2->phdr[C_TEXT].p_filesz;
set_te32(&h2->phdr[C_TEXT].p_type, PT_LOAD64); // be sure
for (unsigned j=0; j < phnum_i; ++j) {
if (is_LOAD64(&h3->phdr[j])) {
set_te64( &h3->phdr[j].p_align, page_size);
}
}
// Info for OS kernel to set the brk()
if (brka) {