Stub for 64-bit shlib

modified:   stub/Makefile
	modified:   stub/src/amd64-expand.S
	modified:   stub/src/amd64-linux.elf-entry.S
	modified:   stub/src/amd64-linux.elf-so_entry.S
	modified:   stub/src/amd64-linux.elf-so_fold.S
	modified:   stub/src/amd64-linux.elf-so_main.c
	modified:   stub/src/arm64-expand.S
	modified:   stub/src/upxfd_linux.c
This commit is contained in:
John Reiser 2024-11-28 19:10:27 -08:00
parent d04209d30f
commit bd251c0dbd
8 changed files with 99 additions and 66 deletions

View File

@ -421,11 +421,13 @@ tc.amd64-linux.elf.gcc += -fno-exceptions -fno-asynchronous-unwind-tables
tc.amd64-linux.elf.gcc += -Wall -W -Wcast-align -Wcast-qual -Wstrict-prototypes -Wwrite-strings -Werror
amd64-linux.elf-entry.h: $(srcdir)/src/$$T.S
@echo; echo TARGET=$@ PATH=$(PATH); echo
$(call tc,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
$(call tc,f-embed_objinfo,tmp/$T.bin)
$(call tc,bin2h) tmp/$T.bin $@
amd64-linux.elf-so_entry.h: $(srcdir)/src/$$T.S
@echo; echo TARGET=$@ PATH=$(PATH); echo
$(call tc,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
$(call tc,f-embed_objinfo,tmp/$T.bin)
$(call tc,bin2h) tmp/$T.bin $@
@ -433,17 +435,32 @@ amd64-linux.elf-so_entry.h: $(srcdir)/src/$$T.S
amd64-linux.elf-fold.h : $(srcdir)/src/$$T.lds \
tmp/$$T.o \
tmp/amd64-expand.o \
tmp/amd64-linux.elf-upxfd_linux.o \
tmp/amd64-linux.elf-main2.o
@echo; echo TARGET=$@ PATH=$(PATH); echo
# FIXME: multiarch-ld-2.18 creates a huge file here, so use 2.17
multiarch-ld-2.17 -r -T $(srcdir)/src/$T.lds -Map tmp/$T.map $(filter %.o,$^) -o tmp/$T.bin
$(call tc,f-embed_objinfo_without_xstrip_keep_dot_text,tmp/$T.bin)
$(call tc,bin2h) tmp/$T.bin $@
amd64-linux.elf-so_fold.h : tmp/$$T.o tmp/amd64-linux.elf-so_main.o $(srcdir)/src/$$T.lds tmp/amd64-expand.o
multiarch-ld-2.17 -r -T $(srcdir)/src/$T.lds -Map tmp/$T.map $(filter %.o,$^) -o tmp/$T.bin
amd64-linux.elf-so_fold.h : $(srcdir)/src/$$T.lds \
tmp/$$T.o \
tmp/amd64-expand.o \
tmp/amd64-linux.elf-upxfd_linux.o \
tmp/amd64-linux.elf-so_main.o
@echo; echo TARGET=$@ PATH=$(PATH); echo
# FIXME: multiarch-ld-2.18 creates a huge file here, so use 2.17
$(call tc,ld) -r -T $(srcdir)/src/$T.lds -Map tmp/$T.map $(filter %.o,$^) -o tmp/$T.bin
# multiarch-ld-2.17 -r -T $(srcdir)/src/$T.lds -Map tmp/$T.map $(filter %.o,$^) -o tmp/$T.bin
ls -l tmp/$T.bin
$(call tc,f-embed_objinfo_without_xstrip,tmp/$T.bin)
$(call tc,bin2h) tmp/$T.bin $@
tmp/amd64-linux.elf-so_fold.o : $(srcdir)/src/$$T.S
$(call tc,gcc) -c $< -o tmp/$T.o
$(call tc,objcopy) -R .text $@
$(call tc,f-objstrip,$@)
tmp/amd64-expand.o: $(srcdir)/src/$$T.S
$(call tc,gcc) -c $< -o $@
@ -451,11 +468,6 @@ tmp/amd64-linux.elf-fold.o : $(srcdir)/src/$$T.S
$(call tc,gcc) -c $< -o $@
$(call tc,f-objstrip,$@)
tmp/amd64-linux.elf-so_fold.o : $(srcdir)/src/$$T.S
$(call tc,gcc) -c $< -o $@
$(call tc,objcopy) -R .text $@
$(call tc,f-objstrip,$@)
tmp/amd64-linux.elf-main.o : $(srcdir)/src/$$T.c
$(call tc,gcc) -c -Os $< -o $@
$(call tc,f-objstrip,$@)
@ -834,6 +846,11 @@ tmp/arm64-expand.o: $(srcdir)/src/$$T.S
$(call tc,gcc) -c $< -o $@
arm64-linux-objdump-2.25 -Dr $(tc_objdump_disasm_options) tmp/$T.o | $(RTRIM) > tmp/$T.o.disasm
tmp/amd64-linux.elf-upxfd_linux.o : $(srcdir)/src/upxfd_linux.c
$(call tc,gcc) -c -O $< -o $@
$(call tc,objcopy) --rename-section .text=UMF_LINUX -R .comment -R .data -R .bss -R .note.GNU-stack $@
$(call tc,objdump) -Dr $(tc_objdump_disasm_options) $@ | $(RTRIM) > $@.disasm
tmp/arm64-linux.elf-main2.o : $(srcdir)/src/$$T.c $(srcdir)/src/amd64-linux.elf-main2.c
$(call tc,gcc) -c -Os $(srcdir)/src/arm64-linux.elf-main2.c -o $@
$(call tc,f-objstrip,$@)

View File

@ -229,3 +229,7 @@ eof_n2e:
movl %edi,(%rcx) // actual length used at dst XXX: 4GB
sub %rsi,%rax // src -= eof; // return 0: good; else: bad
ret
.balign 4
upx_mmap_and_fd: .globl upx_mmap_and_fd
// UMF_LINUX goes here

View File

@ -129,9 +129,9 @@ D_PMASK= 0*NBPW
#define arg2l esi
#define arg3l edx
// Create anonymous temporary file on mfd; like upxfd_create
push $'u'|('p'<<8)|('x'<<16)|(0<<24) // MATCH_22
push %rsp; pop %arg1 // "upx"
mov $MFD_EXEC,%arg2l
push $'u'|('p'<<8)|('X'<<16)|(0<<24) // MATCH_22
push %rsp; pop %arg1 // "upX"
push $MFD_EXEC; pop %arg2
0: // try memfd_create
movl $__NR_memfd_create,%eax; syscall
test %eax,%eax; jns ok_memfd // success

View File

@ -58,6 +58,7 @@ __NR_mmap= 9 // 64-bit mode only! /usr/include/asm/unistd_64.h
__NR_mprotect= 10
__NR_munmap= 11
__NR_memfd_create= 0x13f // 319
MFD_EXEC= 0x10
__NR_write= 1
__NR_close= 3
@ -204,9 +205,20 @@ eof_n2b:
pop %rbp // MATCH_45
push $0; pop %arg2
call 0f; .asciz "upx"; 0: pop %arg1
push $__NR_memfd_create; call do_sys
#define arg2l esi
// Create anonymous temporary file on mfd; like upxfd_create
push $'u'|('p'<<8)|('X'<<16)|(0<<24) // MATCH_22
push %rsp; pop %arg1 // "upX"
push $MFD_EXEC; pop %arg2
0: // try memfd_create
movl $__NR_memfd_create,%eax; syscall
test %eax,%eax; jns ok_memfd // success
test %arg2l,%arg2l; jz no_memfd // memfd_create failed twice
xor %arg2l,%arg2l; jmp 0b // try again without MFD_EXEC
no_memfd: // so try /dev/shm
hlt // FIXME /dev/shm
ok_memfd:
pop %rcx // MATCH_22 discard "upx"
push %rax; pop %arg1 // mfd
push %rsp; pop %arg2 // buffer

View File

@ -98,6 +98,7 @@ __NR_read= 0
__NR_write= 1
//__NR_open= 2
__NR_openat= 257
FD_CWD= -100
__NR_close= 3
__NR_mmap= 9
@ -149,6 +150,13 @@ sysgo: # NOTE: kernel demands 4th arg in %sys4, NOT %arg4
syscall; cmp $-4096,%rax; jb 0f; int3; 0:
ret
open: .globl open
mov %arg3,%arg4
mov %arg2,%arg3
mov %arg1,%arg2
mov $FD_CWD,%arg1
jmp openat
Punmap: .globl Punmap // page-align the lo end
mov %arg1,%rax; and $0xfff,%eax
sub %rax,%arg1

View File

@ -40,8 +40,6 @@ extern size_t Pwrite(unsigned, void const *, size_t);
extern void f_int3(int arg);
#define DEBUG 1
#ifndef DEBUG //{
#define DEBUG 0
#endif //}
@ -384,10 +382,10 @@ make_hatch(
) >> ((pf & (PF_R|PF_W|PF_X))<<2) ))
#undef PAGE_MASK
static unsigned long
static ElfW(Addr)
get_page_mask(void) // the mask which KEEPS the page, discards the offset
{
unsigned long rv = ~0xffful; // default to (PAGE_SIZE == 4KiB)
ElfW(Addr) rv = ~0xffful; // default to (PAGE_SIZE == 4KiB)
int fd = openat(0, addr_string("/proc/self/auxv"), O_RDONLY, 0);
if (0 <= fd) {
ElfW(auxv_t) data[40];
@ -454,16 +452,25 @@ fini_SELinux(
}
unsigned
prep_SELinux(unsigned size, char *ptr, unsigned len) // returns mfd
prep_SELinux(unsigned size, char *ptr, ElfW(Addr) page_mask) // returns mfd
{
// Cannot set PROT_EXEC except via mmap() into a region (Linux "vma")
// that has never had PROT_WRITE. So use a Linux-only "memory file"
// to hold the contents.
char *val = upx_mmap_and_fd(ptr, size, nullptr);
unsigned mfd = 0xfff & (unsigned)(long)val;
unsigned saved[65536/sizeof(unsigned)];
char *page = (char *)(page_mask & (ElfW(Addr))ptr);
unsigned frag = (unsigned)(ptr - page);
if (frag) {
memcpy(saved, page, frag);
}
char *val = upx_mmap_and_fd(page, frag + size, nullptr);
unsigned mfd = 0xfff & (unsigned)(ElfW(Addr))val;
val -= mfd; --mfd;
if (len)
Pwrite(mfd, ptr, len); // Save lo fragment of contents on first page.
if (val != page) {
my_bkpt((void const *)0x1262, val, page, ptr, frag);
}
if (frag)
write(mfd, saved, frag); // Save lo fragment of contents on page.
return mfd;
}
@ -491,7 +498,7 @@ upx_so_main( // returns &escape_hatch
ElfW(Ehdr) *elf_tmp // scratch for ElfW(Ehdr) and ElfW(Phdrs)
)
{
unsigned long const page_mask = get_page_mask();
ElfW(Addr) const page_mask = get_page_mask();
char *const va_load = (char *)&so_info->off_reloc - so_info->off_reloc;
So_info so_infc; // So_info Copy
memcpy(&so_infc, so_info, sizeof(so_infc)); // before de-compression overwrites
@ -548,59 +555,41 @@ upx_so_main( // returns &escape_hatch
for (; phdr < phdrN; ++phdr)
if (phdr->p_type == PT_LOAD && !(phdr->p_flags & PF_W)) {
unsigned hi_offset = phdr->p_filesz + phdr->p_offset;
struct b_info al_bi; // for aligned data from binfo
// Need un-aligned read of b_info to determine compression sizes.
struct b_info al_bi; // for aligned data from binfo
x0.size = sizeof(struct b_info);
xread(&x0, (char *)&al_bi, x0.size); // aligned binfo
x0.buf -= sizeof(al_bi); // back up (the xread() was a peek)
x1.size = hi_offset - xct_off;
x1.buf = (void *)(hi_offset + base - al_bi.sz_unc);
x0.size = al_bi.sz_cpr;
x0.size = al_bi.sz_cpr;
x1.size = al_bi.sz_unc;
DPRINTF("\\nphdr@%%p p_offset=%%p p_vaddr=%%p p_filesz=%%p p_memsz=%%p\\n",
phdr, phdr->p_offset, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz);
DPRINTF("x0=%%p x1=%%p\\n", &x0, &x1);
if (!base) {
base = (ElfW(Addr))va_load - phdr->p_vaddr;
DPRINTF("base=%%p\\n", base);
}
DPRINTF("phdr@%%p p_offset=%%p p_vaddr=%%p p_filesz=%%p p_memsz=%%p\\n",
phdr, phdr->p_offset, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz);
DPRINTF("x0=%%p x1=%%p\\n", &x0, &x1);
//my_bkpt((void const *)0x1230, phdr, &x0, &x1);
unsigned frag = ~page_mask & (unsigned)(long)x1.buf;
unsigned mfd = 0;
if (!n_load) { // 1st PT_LOAD is special.
// Already ELF headers are in place, perhaps already followed
// by non-compressed loader tables below xct_off.
if (xct_off < hi_offset) { // 1st PT_LOAD also has compressed code, too
if (phdr->p_flags & PF_X) {
mfd = prep_SELinux(x1.size, x1.buf, frag);
}
else {
underlay(x1.size, x1.buf, page_mask); // also makes PROT_WRITE
}
unpackExtent(&x0, &x1);
if (!hatch && phdr->p_flags & PF_X) {
hatch = make_hatch(phdr, x1.buf, ~page_mask);
}
my_bkpt((void const *)0x1235, &x1);
fini_SELinux(x1.size, x1.buf, phdr, mfd, base); // FIXME: x1 changed!
x1.buf = (void *)(phdr->p_filesz + phdr->p_vaddr + base - x1.size);
if ((phdr->p_filesz + phdr->p_offset) <= xct_off) { // hi_offset <= xct_off
if (!n_load) {
++n_load;
continue; // 1st PT_LOAD is non-compressed loader tables ONLY!
}
}
else { // 2nd and later PT_LOADs
x1.buf = (void *)(phdr->p_vaddr + base);
x1.size = phdr->p_filesz;
if (phdr->p_flags & PF_X) {
mfd = prep_SELinux(x1.size, x1.buf, frag);
}
else {
underlay(x1.size, x1.buf, page_mask); // also makes PROT_WRITE
}
unpackExtent(&x0, &x1);
if (!hatch && phdr->p_flags &PF_X) {
hatch = make_hatch(phdr, x1.buf, ~page_mask);
}
fini_SELinux(al_bi.sz_unc, (void *)(phdr->p_vaddr + base), phdr, mfd, base);
int mfd = 0;
if (phdr->p_flags & PF_X) {
mfd = prep_SELinux(x1.size, x1.buf, page_mask);
}
else {
underlay(x1.size, x1.buf, page_mask); // also makes PROT_WRITE
}
Extent xt = x1;
unpackExtent(&x0, &x1);
if (!hatch && phdr->p_flags & PF_X) {
hatch = make_hatch(phdr, x1.buf, ~page_mask);
fini_SELinux(xt.size, xt.buf, phdr, mfd, base); // FIXME: x1 was changed by unpackExtent!
}
++n_load;
}

View File

@ -140,6 +140,9 @@ eof_lzma: .globl eof_lzma
POP4(x2,x3, fp,lr) // MATCH_94 x2= orig_dst; x3= plen_dst
ret
upx_mmap_and_fd: .globl upx_mmap_and_fd
// UMF_LINUX goes here
#define M_NRV2B_LE32 2
#define M_NRV2B_8 3
#define M_NRV2D_LE32 5

View File

@ -1,4 +1,4 @@
/* upxfd_create.c -- workaround for 32-bit Android
/* upxfd_create.c -- simplify upx_mmap_and_fd_linux for non-Android
This file is part of the UPX executable compressor.