From 0901ce1b6887f6a447dd72840381add4c19d49e2 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Wed, 26 Apr 2023 13:06:48 -0700 Subject: [PATCH] amd64-linux.elf shlib now fully-SELinux compliant modified: stub/src/amd64-linux.elf-so_entry.S modified: stub/src/amd64-linux.elf-so_fold.S --- src/stub/src/amd64-linux.elf-so_entry.S | 82 ++++++++++++++++--------- src/stub/src/amd64-linux.elf-so_fold.S | 25 ++++---- 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/stub/src/amd64-linux.elf-so_entry.S b/src/stub/src/amd64-linux.elf-so_entry.S index d11ddac6..d3f73f57 100644 --- a/src/stub/src/amd64-linux.elf-so_entry.S +++ b/src/stub/src/amd64-linux.elf-so_entry.S @@ -31,6 +31,7 @@ #include "arch/amd64/macros.S" #include "arch/amd64/regs.h" +NBPW= 8 sz_Ehdr= 64 sz_Phdr= 56 @@ -56,8 +57,10 @@ MAP_ANONYMOUS= 0x20 __NR_mmap= 9 // 64-bit mode only! /usr/include/asm/unistd_64.h __NR_mprotect= 10 __NR_munmap= 11 +__NR_memfd_create= 0x13f // 319 __NR_write= 1 +__NR_close= 3 __NR_exit= 60 PAGE_SHIFT= 12 @@ -85,8 +88,9 @@ _start: push %arg3 // MATCH_07 envp (glibc) push %arg2 // MATCH_01 argv push %arg1 // MATCH_00 argc - push %rbp // MATCH_02 saved register push %rbx // MATCH_03 saved register + push %rbp // MATCH_02 saved register + mov %rsp,%rbp call L70 // MATCH_08 push $&getbit /* Working registers */ #define off %eax /* XXX: 2GB */ @@ -111,24 +115,16 @@ refill: adcl bits,bits // LSB= 1 (CarryIn); CarryOut= next bit ret // infrequent (1/32) -L20: +L20: // %rdx == &getbit pop %rbx // MATCH_09 &fold_info + lea _start - 4*4 - getbit(%rdx),%rax // &so_info + push %rax // MATCH_14 &so_info + // cmpw $M_NRV2B_LE32|(0<<8),b_method(%rbx); je 0f; hlt; 0: // check method and filter bytes -// Get pages for unfolded code - sub %arg6,%arg6 // 0 - pop %rdx // MATCH_08 &getbit - sub %arg5,%arg5 // 0 - movl /*sz_unc*/(%rbx),%arg2l // dstlen - push $MAP_PRIVATE|MAP_ANONYMOUS; pop %sys4 - push %arg2 // MATCH_10 len for escape hatch - push %rdx // MATCH_15 save &getbit over syscall - push $PROT_READ|PROT_WRITE; pop %arg3 - subl %edi,%edi // (%arg1)dst = 0; // kernel chooses - push $__NR_mmap; pop %rax; syscall; cmp $-4096,%rax; jb 0f; int3; 0: - - pop %rdx // MATCH_15 &getbit - push %rax // MATCH_04 ptr unfolded_code +// De-compress folded code onto the stack + movl /*sz_unc*/(%rbx),%eax; push %rax // MATCH_40 len unfolded code + sub %rax,%rsp; and $-2*NBPW,%rsp // This is nrv2b_d32, inlined and optimized for small space (about 160 bytes). // The task is to de-compress the folded pieces for shared library init: @@ -140,7 +136,8 @@ L20: // and compressability of C-coded de-compressors for Lzma and Zstd // in contrast to the simple and small assembly-coded NRV. - push %rax; pop dst // &unfolded_code + push %rsp; pop dst // &unfolded_code + push %rbp // MATCH_45 movl sz_cpr(%rbx),len // lsrc lea sz_b_info(%rbx),src decompress: // inlined: (uchar const *src, uint len, uchar *dst /*, u32 &ldst, uint method */) @@ -150,8 +147,9 @@ decompress: // inlined: (uchar const *src, uint len, uchar *dst /*, u32 &ldst, // MATCH_05 &input_eof // MATCH_04 ptr unfolded_code // MATCH_10 len unfolded_code -// MATCH_03 saved %rbx +//%rbp: // MATCH_02 saved %rbp +// MATCH_03 saved %rbx // MATCH_00 argc // MATCH_01 argv // MATCH_07 envp @@ -201,33 +199,57 @@ gotlen_n2b: eof_n2b: pop %rcx // MATCH_05 &input_eof cmp %rcx,%rsi; je 0f; hlt; 0: // test for ending in correct place - lea _start - 4*4 - getbit(%rdx),%rdx // &so_info - pop %arg1 // MATCH_11 ptr unfolded code - pop %arg2 // MATCH_10 len unfolded code - push %rdx // MATCH_14 &so_info - push %arg2 // MATCH_12 len unfolded code - push %arg1 // MATCH_13 ptr unfolded code - push $PROT_EXEC|PROT_READ; pop %arg3 - push $__NR_mprotect; pop %rax; syscall; cmp $-4096,%rax; jb 0f; int3; 0: + pop %rbp // MATCH_45 + + push $0; pop %arg2 + call 0f; .asciz "upx"; 0: pop %arg1 + mov $__NR_memfd_create,%rax; call do_sys + + push %rax; pop %arg1 // mfd + push %rsp; pop %arg2 // buffer + push %rax // MATCH_47 save mfd + mov -2*NBPW(%rbp),%arg3 // length + push $__NR_write; pop %rax; call do_sys // scribbles %rcx !! + +// Map unfolded code the SELinux way + pop %arg5 // MATCH_47 mfd + lea -2*NBPW(%rbp),%rsp + pop %arg2; push %arg2 // MATCH_40 len unfolded code + sub %arg6l,%arg6l // 0 + push $MAP_PRIVATE; pop %sys4 + push $PROT_READ|PROT_EXEC; pop %arg3 + subl %edi,%edi // (%arg1)dst = 0; // kernel chooses addr + push $__NR_mmap; pop %rax; call do_sys + push %rax // MATCH_11 ptr unfolded code + + push %arg5; pop %arg1 // mfd + push $__NR_close; pop %rax; call do_sys // %rsp: -// MATCH_13 ptr unfolded_code; for escape hatch -// MATCH_12 len unfolded code; for escape hatch +// MATCH_11 ptr unfolded_code; for escape hatch +// MATCH_10 len unfolded code; for escape hatch // MATCH_14 &so_info -// MATCH_03 saved %rbx +// %rbp: // MATCH_02 saved %rbp +// MATCH_03 saved %rbx // MATCH_00 argc // MATCH_01 argv // MATCH_07 envp - pop %rax; push %rax // MATCH_13 ptr unfolded code + pop %rax; push %rax // MATCH_11 ptr unfolded code jmp *%rax // enter C code +do_sys: + syscall + cmp $-4096,%rax; jb 0f; int3; 0: + ret + // IDENTSTR goes here section ELFMAINZ L70: + pop %rdx // MATCH_08 &getbit call L20 // MATCH_09 push $&fold_info fold_info: // b_info (sz_unc, sz_cpr, method) of folded code (C-language, etc.) diff --git a/src/stub/src/amd64-linux.elf-so_fold.S b/src/stub/src/amd64-linux.elf-so_fold.S index 2462d3e4..1624978a 100644 --- a/src/stub/src/amd64-linux.elf-so_fold.S +++ b/src/stub/src/amd64-linux.elf-so_fold.S @@ -8,33 +8,34 @@ NBPW= 8 #endif //} // %rsp: -// MATCH_13 ptr unfolded_code; for escape hatch -// MATCH_12 len unfolded code; for escape hatch +// MATCH_11 ptr unfolded_code; for escape hatch +// MATCH_10 len unfolded code; for escape hatch // MATCH_14 &so_info: -// .long offset(.) // detect relocation -// .long offset(user DT_INIT) -// .long offset(escape_hatch) -// .long offset({l_info; p_info; b_info; compressed data}) -// MATCH_03 saved %rbx +// .word offset(.) // detect relocation +// .word offset(user DT_INIT) +// .word offset(escape_hatch) +// .word offset({l_info; p_info; b_info; compressed data}) +// %rbp: // MATCH_02 saved %rbp +// MATCH_03 saved %rbx // MATCH_00 argc // MATCH_01 argv // MATCH_07 envp section SO_HEAD fold: - pop %rbx // MATCH_13 ptr unfolded code - pop %rbp // MATCH_12 len unfolded code + pop %rbx // MATCH_11 ptr unfolded code + pop %rbp // MATCH_10 len unfolded code pop %arg1 // MATCH_14 &so_info - lea 2*NBPW(%rsp),%arg2 // skip MATCH_03, MATCH_02; MATCH_00 &{argc, argv, envp} + lea 2*NBPW(%rsp),%arg2 // &{argc, argv, envp} sub $MAX_ELF_HDR_64,%rsp; mov %rsp,%arg3 // space for Elf64_Ehdr and Elf64_Phdrs call upx_so_main // (&so_info, &{argc, argv, envp}, elf_tmp); returns &escape_hatch add $MAX_ELF_HDR_64,%rsp push %rbp; pop %arg2 // len unfolded code push %rbx; pop %arg1 // ptr unfolded code - pop %rbx // MATCH_03 restore pop %rbp // MATCH_02 restore + pop %rbx // MATCH_03 restore push %rax // MATCH_30 &escape_hatch push $__NR_munmap; pop %rax ret // MATCH_30 ==>escape_hatch: @@ -73,7 +74,7 @@ eof: // end of a compressed extent // Subroutines and syscalls needed by upx_so_main // my_bkpt: .globl my_bkpt - int3 + int3 // my_bkpt ret memset: .globl memset // void *memset(void *s, int c, size_t n);