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 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 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,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
$(call tc,f-embed_objinfo,tmp/$T.bin) $(call tc,f-embed_objinfo,tmp/$T.bin)
$(call tc,bin2h) tmp/$T.bin $@ $(call tc,bin2h) tmp/$T.bin $@
amd64-linux.elf-so_entry.h: $(srcdir)/src/$$T.S 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,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
$(call tc,f-embed_objinfo,tmp/$T.bin) $(call tc,f-embed_objinfo,tmp/$T.bin)
$(call tc,bin2h) 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 \ amd64-linux.elf-fold.h : $(srcdir)/src/$$T.lds \
tmp/$$T.o \ tmp/$$T.o \
tmp/amd64-expand.o \ tmp/amd64-expand.o \
tmp/amd64-linux.elf-upxfd_linux.o \
tmp/amd64-linux.elf-main2.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 # 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 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,f-embed_objinfo_without_xstrip_keep_dot_text,tmp/$T.bin)
$(call tc,bin2h) 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 amd64-linux.elf-so_fold.h : $(srcdir)/src/$$T.lds \
multiarch-ld-2.17 -r -T $(srcdir)/src/$T.lds -Map tmp/$T.map $(filter %.o,$^) -o tmp/$T.bin 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,f-embed_objinfo_without_xstrip,tmp/$T.bin)
$(call tc,bin2h) 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 tmp/amd64-expand.o: $(srcdir)/src/$$T.S
$(call tc,gcc) -c $< -o $@ $(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,gcc) -c $< -o $@
$(call tc,f-objstrip,$@) $(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 tmp/amd64-linux.elf-main.o : $(srcdir)/src/$$T.c
$(call tc,gcc) -c -Os $< -o $@ $(call tc,gcc) -c -Os $< -o $@
$(call tc,f-objstrip,$@) $(call tc,f-objstrip,$@)
@ -834,6 +846,11 @@ tmp/arm64-expand.o: $(srcdir)/src/$$T.S
$(call tc,gcc) -c $< -o $@ $(call tc,gcc) -c $< -o $@
arm64-linux-objdump-2.25 -Dr $(tc_objdump_disasm_options) tmp/$T.o | $(RTRIM) > tmp/$T.o.disasm 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 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,gcc) -c -Os $(srcdir)/src/arm64-linux.elf-main2.c -o $@
$(call tc,f-objstrip,$@) $(call tc,f-objstrip,$@)

View File

@ -229,3 +229,7 @@ eof_n2e:
movl %edi,(%rcx) // actual length used at dst XXX: 4GB movl %edi,(%rcx) // actual length used at dst XXX: 4GB
sub %rsi,%rax // src -= eof; // return 0: good; else: bad sub %rsi,%rax // src -= eof; // return 0: good; else: bad
ret 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 arg2l esi
#define arg3l edx #define arg3l edx
// Create anonymous temporary file on mfd; like upxfd_create // Create anonymous temporary file on mfd; like upxfd_create
push $'u'|('p'<<8)|('x'<<16)|(0<<24) // MATCH_22 push $'u'|('p'<<8)|('X'<<16)|(0<<24) // MATCH_22
push %rsp; pop %arg1 // "upx" push %rsp; pop %arg1 // "upX"
mov $MFD_EXEC,%arg2l push $MFD_EXEC; pop %arg2
0: // try memfd_create 0: // try memfd_create
movl $__NR_memfd_create,%eax; syscall movl $__NR_memfd_create,%eax; syscall
test %eax,%eax; jns ok_memfd // success 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_mprotect= 10
__NR_munmap= 11 __NR_munmap= 11
__NR_memfd_create= 0x13f // 319 __NR_memfd_create= 0x13f // 319
MFD_EXEC= 0x10
__NR_write= 1 __NR_write= 1
__NR_close= 3 __NR_close= 3
@ -204,9 +205,20 @@ eof_n2b:
pop %rbp // MATCH_45 pop %rbp // MATCH_45
push $0; pop %arg2 #define arg2l esi
call 0f; .asciz "upx"; 0: pop %arg1 // Create anonymous temporary file on mfd; like upxfd_create
push $__NR_memfd_create; call do_sys 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 %rax; pop %arg1 // mfd
push %rsp; pop %arg2 // buffer push %rsp; pop %arg2 // buffer

View File

@ -98,6 +98,7 @@ __NR_read= 0
__NR_write= 1 __NR_write= 1
//__NR_open= 2 //__NR_open= 2
__NR_openat= 257 __NR_openat= 257
FD_CWD= -100
__NR_close= 3 __NR_close= 3
__NR_mmap= 9 __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: syscall; cmp $-4096,%rax; jb 0f; int3; 0:
ret 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 Punmap: .globl Punmap // page-align the lo end
mov %arg1,%rax; and $0xfff,%eax mov %arg1,%rax; and $0xfff,%eax
sub %rax,%arg1 sub %rax,%arg1

View File

@ -40,8 +40,6 @@ extern size_t Pwrite(unsigned, void const *, size_t);
extern void f_int3(int arg); extern void f_int3(int arg);
#define DEBUG 1
#ifndef DEBUG //{ #ifndef DEBUG //{
#define DEBUG 0 #define DEBUG 0
#endif //} #endif //}
@ -384,10 +382,10 @@ make_hatch(
) >> ((pf & (PF_R|PF_W|PF_X))<<2) )) ) >> ((pf & (PF_R|PF_W|PF_X))<<2) ))
#undef PAGE_MASK #undef PAGE_MASK
static unsigned long static ElfW(Addr)
get_page_mask(void) // the mask which KEEPS the page, discards the offset 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); int fd = openat(0, addr_string("/proc/self/auxv"), O_RDONLY, 0);
if (0 <= fd) { if (0 <= fd) {
ElfW(auxv_t) data[40]; ElfW(auxv_t) data[40];
@ -454,16 +452,25 @@ fini_SELinux(
} }
unsigned 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") // 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" // that has never had PROT_WRITE. So use a Linux-only "memory file"
// to hold the contents. // to hold the contents.
char *val = upx_mmap_and_fd(ptr, size, nullptr); unsigned saved[65536/sizeof(unsigned)];
unsigned mfd = 0xfff & (unsigned)(long)val; 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; val -= mfd; --mfd;
if (len) if (val != page) {
Pwrite(mfd, ptr, len); // Save lo fragment of contents on first 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; return mfd;
} }
@ -491,7 +498,7 @@ upx_so_main( // returns &escape_hatch
ElfW(Ehdr) *elf_tmp // scratch for ElfW(Ehdr) and ElfW(Phdrs) 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; char *const va_load = (char *)&so_info->off_reloc - so_info->off_reloc;
So_info so_infc; // So_info Copy So_info so_infc; // So_info Copy
memcpy(&so_infc, so_info, sizeof(so_infc)); // before de-compression overwrites 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) for (; phdr < phdrN; ++phdr)
if (phdr->p_type == PT_LOAD && !(phdr->p_flags & PF_W)) { 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. // 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); x0.size = sizeof(struct b_info);
xread(&x0, (char *)&al_bi, x0.size); // aligned binfo xread(&x0, (char *)&al_bi, x0.size); // aligned binfo
x0.buf -= sizeof(al_bi); // back up (the xread() was a peek) 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) { if (!base) {
base = (ElfW(Addr))va_load - phdr->p_vaddr; base = (ElfW(Addr))va_load - phdr->p_vaddr;
DPRINTF("base=%%p\\n", base); DPRINTF("base=%%p\\n", base);
} }
DPRINTF("phdr@%%p p_offset=%%p p_vaddr=%%p p_filesz=%%p p_memsz=%%p\\n", x1.buf = (void *)(phdr->p_filesz + phdr->p_vaddr + base - x1.size);
phdr, phdr->p_offset, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz); if ((phdr->p_filesz + phdr->p_offset) <= xct_off) { // hi_offset <= xct_off
DPRINTF("x0=%%p x1=%%p\\n", &x0, &x1); if (!n_load) {
//my_bkpt((void const *)0x1230, phdr, &x0, &x1); ++n_load;
continue; // 1st PT_LOAD is non-compressed loader tables ONLY!
unsigned frag = ~page_mask & (unsigned)(long)x1.buf; }
unsigned mfd = 0; }
if (!n_load) { // 1st PT_LOAD is special. int mfd = 0;
// 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) { if (phdr->p_flags & PF_X) {
mfd = prep_SELinux(x1.size, x1.buf, frag); mfd = prep_SELinux(x1.size, x1.buf, page_mask);
} }
else { else {
underlay(x1.size, x1.buf, page_mask); // also makes PROT_WRITE underlay(x1.size, x1.buf, page_mask); // also makes PROT_WRITE
} }
Extent xt = x1;
unpackExtent(&x0, &x1); unpackExtent(&x0, &x1);
if (!hatch && phdr->p_flags & PF_X) { if (!hatch && phdr->p_flags & PF_X) {
hatch = make_hatch(phdr, x1.buf, ~page_mask); hatch = make_hatch(phdr, x1.buf, ~page_mask);
} fini_SELinux(xt.size, xt.buf, phdr, mfd, base); // FIXME: x1 was changed by unpackExtent!
my_bkpt((void const *)0x1235, &x1);
fini_SELinux(x1.size, x1.buf, phdr, mfd, base); // FIXME: x1 changed!
}
}
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);
} }
++n_load; ++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 POP4(x2,x3, fp,lr) // MATCH_94 x2= orig_dst; x3= plen_dst
ret ret
upx_mmap_and_fd: .globl upx_mmap_and_fd
// UMF_LINUX goes here
#define M_NRV2B_LE32 2 #define M_NRV2B_LE32 2
#define M_NRV2B_8 3 #define M_NRV2B_8 3
#define M_NRV2D_LE32 5 #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. This file is part of the UPX executable compressor.