1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

WIP: SELinux is expensive: +2KB in stub

Needs make_hatch()
	modified:   stub/src/amd64-linux.elf-so_main.c
	modified:   stub/src/amd64-linux.elf-so_fold.S

	modified:   stub/amd64-linux.elf-so_fold.h
	modified:   stub/arm64-linux.elf-so_fold.h
	modified:   stub/src/arm.v4a-linux.elf-so_fold.S
	modified:   stub/tmp/amd64-linux.elf-so_fold.bin.dump
This commit is contained in:
John Reiser 2023-04-24 19:40:57 -07:00
parent 04ffb641a6
commit 98b835e0a7
6 changed files with 2176 additions and 1827 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include "arch/amd64/regs.h"
#include "arch/amd64/macros.S"
#include "MAX_ELF_HDR.S"
NBPW= 8
#ifndef DEBUG //{
@ -26,7 +27,9 @@ fold:
pop %rbp // MATCH_12 len unfolded code
pop %arg1 // MATCH_14 &so_info
lea 2*NBPW(%rsp),%arg2 // skip MATCH_03, MATCH_02; MATCH_00 &{argc, argv, envp}
call upx_so_main // (&so_info, &{argc, argv, envp}); returns &escape_hatch
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
@ -100,6 +103,8 @@ __NR_mmap= 9
__NR_mprotect= 10
__NR_munmap= 11
__NR_mremap= 216
__NR_memfd_create= 0x13f // 319
__NR_ftruncate= 0x4d // 77
__NR_brk= 12
@ -144,6 +149,10 @@ sysgo: # NOTE: kernel demands 4th arg in %sys4, NOT %arg4
exit: .globl exit
push $ __NR_exit; 5: jmp 5f
ftruncate: .globl ftruncate
push $__NR_ftruncate; 5: jmp 5f
memfd_create: .globl memfd_create
push $__NR_memfd_create; 5: jmp 5f
close: .globl close
push $ __NR_close; 5: jmp 5f
openat: .globl openat
@ -153,7 +162,7 @@ write: .globl write
read: .globl read
push $ __NR_read; 5: jmp 5f
munmap: .globl munmap
push $ __NR_munmap; 5: jmp sysgo
push $__NR_munmap; 5: jmp sysgo
// Sometimes Linux enforces page-aligned address for mprotect
Pprotect: .globl Pprotect

View File

@ -221,19 +221,18 @@ ERR_LAB
static void *
make_hatch_x86_64(
Elf64_Phdr const *const phdr,
Elf64_Addr reloc,
Elf64_Addr addr,
unsigned const frag_mask
)
{
unsigned xprot = 0;
unsigned *hatch = 0;
DPRINTF("make_hatch %%p %%x %%x\\n",phdr,reloc,frag_mask);
DPRINTF("make_hatch %%p %%p %%x\\n", phdr, addr, frag_mask);
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
if (
// Try page fragmentation just beyond .text .
( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr + reloc)),
( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
&& (1*6)<=(frag_mask & -(int)(size_t)hatch) ) ) // space left on page
( (hatch = (void *)addr,
(1*6)<=(frag_mask & -(int)(size_t)hatch) ) ) // space left on page
// Allocate and use a new page.
|| ( xprot = 1, hatch = mmap(0, PAGE_SIZE, PROT_WRITE|PROT_READ,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) )
@ -241,6 +240,7 @@ make_hatch_x86_64(
{
hatch[0] = 0x5e5f050f; // syscall; pop %arg1{%rdi}; pop %arg2{%rsi}
((short *)hatch)[2] = 0xc35a; // pop %arg3{%rdx}; ret
DPRINTF("xprot= %%x\\n", xprot);
if (xprot) {
Pprotect(hatch, 6, PROT_EXEC|PROT_READ);
}
@ -403,7 +403,7 @@ extern void *memset(void *dst, unsigned val, size_t n);
#ifndef __arm__ //{
// Segregate large local array, to avoid code bloat due to large displacements.
static void
underlay(unsigned size, char *ptr, unsigned len) // len < PAGE_SIZE
underlay(unsigned size, char *ptr, unsigned len) // len <= PAGE_SIZE
{
DPRINTF("underlay size=%%u ptr=%%p len=%%u\\n", size, ptr, len);
unsigned saved[4096/sizeof(unsigned)];
@ -417,6 +417,17 @@ extern void
underlay(unsigned size, char *ptr, unsigned len);
#endif //}
extern int memfd_create(const char *name, unsigned int flags);
extern int ftruncate(int fd, off_t length);
// Exchange the bits with values 4 (PF_R, PROT_EXEC) and 1 (PF_X, PROT_READ)
// Use table lookup into a PIC-string that pre-computes the result.
unsigned PF_to_PROT(Elf64_Phdr const *phdr)
{
return 7& addr_string("@\x04\x02\x06\x01\x05\x03\x07")
[phdr->p_flags & (PF_R|PF_W|PF_X)];
}
typedef struct {
long argc;
char **argv;
@ -437,25 +448,22 @@ typedef struct {
void *
upx_so_main( // returns &escape_hatch
So_info *so_info,
So_args *so_args
So_args *so_args,
Elf64_Ehdr *elf_tmp // scratch for Elf64_Ehdr and Elf64_Phdrs
)
{
unsigned long const PAGE_MASK = get_PAGE_MASK();
char *const va_load = (char *)&so_info->off_reloc - so_info->off_reloc;
Elf64_Phdr const *phdr = (Elf64_Phdr *)(1+ (Elf64_Ehdr *)(void *)va_load);
while (phdr->p_type != PT_LOAD) ++phdr; // skip PT_PHDR if any
Elf64_Addr const base = (Elf64_Addr)va_load - phdr->p_vaddr;
So_info so_infc; // So_info Copy
memcpy(&so_infc, so_info, sizeof(so_infc)); // before de-compression overwrites
unsigned const xct_off = so_infc.off_xct_off;
(void)xct_off; // use even if not DEBUG
unsigned const xct_off = so_infc.off_xct_off; (void)xct_off;
char *const cpr_ptr = so_info->off_info + va_load;
unsigned const cpr_len = (char *)so_info - cpr_ptr;
typedef void (*Dt_init)(int argc, char *argv[], char *envp[]);
Dt_init const dt_init = (Dt_init)(void *)(so_info->off_user_DT_INIT + va_load);
DPRINTF("upx_so_main va_load=%%p base=%%p so_infc=%%p cpr_ptr=%%p cpr_len=%%x xct_off=%%x\\n",
va_load, base, &so_infc, cpr_ptr, cpr_len, xct_off);
DPRINTF("upx_so_main va_load=%%p so_infc=%%p cpr_ptr=%%p cpr_len=%%x xct_off=%%x\\n",
va_load, &so_infc, cpr_ptr, cpr_len, xct_off);
// DO NOT USE *so_info AFTER THIS!! It gets overwritten.
// Copy compressed data before de-compression overwrites it.
@ -485,19 +493,35 @@ upx_so_main( // returns &escape_hatch
// Get the uncompressed Elf64_Ehdr and Elf64_Phdr
// The first b_info is aligned, so direct access to fields is OK.
Extent x1 = {binfo->sz_unc, va_load}; // destination
Pprotect(va_load, binfo->sz_unc, PROT_WRITE|PROT_READ);
Extent x1 = {binfo->sz_unc, (char *)elf_tmp}; // destination
Extent x0 = {binfo->sz_cpr + sizeof(*binfo), (char *)binfo}; // source
unpackExtent(&x0, &x1); // de-compress _Ehdr and _Phdrs; x0.buf is updated
Elf64_Phdr const *phdr = (Elf64_Phdr *)(1+ elf_tmp);
Elf64_Phdr const *const phdrN = &phdr[elf_tmp->e_phnum];
while (phdr->p_type != PT_LOAD) ++phdr; // skip PT_PHDR if any
Elf64_Addr const base = (Elf64_Addr)va_load - phdr->p_vaddr;
DPRINTF("base=%%p\\n", base);
if (phdr->p_flags & PF_X) {
int mfd = memfd_create(addr_string("upx"), 0);
unsigned mfd_len = 0ul - PAGE_MASK;
write(mfd, elf_tmp, binfo->sz_unc); // de-compressed Elf_Ehdr and Elf_Phdrs
write(mfd, binfo->sz_unc + va_load, mfd_len - binfo->sz_unc); // rest of 1st page
munmap(va_load, mfd_len); // make SELinux forget any previous protection
Elf64_Addr va_mfd = (Elf64_Addr)mmap(va_load, mfd_len, PF_to_PROT(phdr),
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, mfd, 0); (void)va_mfd;
close(mfd);
}
// Process each read-only PT_LOAD.
// A read+write PT_LOAD might be relocated by rtld before de-compression,
// so it cannot be compressed.
struct b_info al_bi; // for aligned data from binfo
void *hatch = nullptr;
unsigned n_phdr = ((Elf64_Ehdr *)(void *)va_load)->e_phnum;
for (; n_phdr > 0; --n_phdr, ++phdr)
for (; phdr < phdrN; ++phdr)
if ( phdr->p_type == PT_LOAD && !(phdr->p_flags & PF_W)) {
DPRINTF("phdr@%%p p_offset=%%p p_vaddr=%%p p_filesz=%%p p_memsz=%%p binfo=%%p\\n",
phdr, phdr->p_offset, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz, x0.buf);
@ -523,38 +547,65 @@ upx_so_main( // returns &escape_hatch
pfx = (phdr->p_vaddr + pfx) & ~PAGE_MASK; // lo fragment on page
x1.buf -= pfx;
x1.size += pfx;
DPRINTF("mmap(%%p %%p) xct_off=%%x pfx=%%x\\n", x1.buf, x1.size, xct_off, pfx);
underlay(x1.size, x1.buf, pfx);
DPRINTF("phdr(%%p %%p) xct_off=%%x pfx=%%x\\n", x1.buf, x1.size, xct_off, pfx);
int mfd = 0;
char *mfd_addr = 0;
if (phdr->p_flags & PF_X) { // SELinux
// Cannot set PROT_EXEC except via mmap() into a region that has
// never had PROT_WRITE. So use a Linux-only "memory file"
// to hold the contents.
mfd = memfd_create(addr_string("upx"), 0); // the directory entry
ftruncate(mfd, x1.size); // Allocate the pages in the file.
write(mfd, x1.buf, pfx); // Save lo fragment of contents of first page.
mfd_addr = mmap(0, x1.size, PROT_READ|PROT_WRITE, MAP_SHARED, mfd, 0);
DPRINTF("mfd_addr= %%p\\n", mfd_addr);
munmap(x1.buf, x1.size); // Discard original page frames in RAM.
x1.buf = mfd_addr; // will add pfx soon
}
else {
underlay(x1.size, x1.buf, pfx); // also makes PROT_WRITE
}
x1.buf += pfx;
x1.size = al_bi.sz_unc;
x0.size = al_bi.sz_cpr + sizeof(struct b_info);
DPRINTF("befor unpack x0=(%%p %%p x1=(%%p %%p)\\n", x0.size, x0.buf, x1.size, x1.buf);
unpackExtent(&x0, &x1); // updates x0 and x1
DPRINTF("after unpack x0=(%%p %%p x1=(%%p %%p)\\n", x0.size, x0.buf, x1.size, x1.buf);
if (!hatch && phdr->p_flags & PF_X) {
//#define PAGE_MASK ~0xFFFull
#if defined(__x86_64) //{
hatch = make_hatch_x86_64(phdr, base, ~PAGE_MASK);
hatch = make_hatch_x86_64(phdr, (long)x1.buf + (phdr->p_memsz - phdr->p_filesz), ~PAGE_MASK);
#elif defined(__powerpc64__) //}{
hatch = make_hatch_ppc64(phdr, base, ~PAGE_MASK);
#elif defined(__aarch64__) //}{
hatch = make_hatch_arm64(phdr, base, ~PAGE_MASK);
#endif //}
}
// Exchange the bits with values 4 (PF_R, PROT_EXEC) and 1 (PF_X, PROT_READ)
// Use table lookup into a PIC-string that pre-computes the result.
unsigned prot = 7& addr_string("@\x04\x02\x06\x01\x05\x03\x07")
[phdr->p_flags & (PF_R|PF_W|PF_X)];
DPRINTF("Pprotect %%p (%%p %%p %%x)\\n",
phdr, (char *)(phdr->p_vaddr + base), phdr->p_memsz, prot);
Pprotect( (char *)(phdr->p_vaddr + base), phdr->p_memsz, prot);
if (phdr->p_flags & PF_X) { // SELinux
// Map the contents of mfd into the specified address and protections.
DPRINTF("mfd mmap addr=%%p len=%%p\\n", (phdr->p_vaddr + base + pfx), al_bi.sz_unc);
my_bkpt((void *)0xab, mfd_addr, phdr);
mmap((char *)(phdr->p_vaddr + base + pfx), al_bi.sz_unc, PF_to_PROT(phdr),
MAP_FIXED|MAP_SHARED, mfd, 0);
munmap(mfd_addr, pfx + al_bi.sz_unc); // Discard RW mapping
close(mfd);
}
else { // easy
Pprotect( (char *)(phdr->p_vaddr + base), phdr->p_memsz, PF_to_PROT(phdr));
}
}
munmap(sideaddr, cpr_len);
DPRINTF("calling user DT_INIT %%p\\n", dt_init);
my_bkpt((void *)0xac, dt_init, hatch);
dt_init(so_args->argc, so_args->argv, so_args->envp);
DPRINTF("returning hatch=%%p\\n", hatch);
my_bkpt((void *)0x12, hatch);
return hatch;
}

View File

@ -312,7 +312,7 @@ ptr .req r5
ulen .req r6
pflg .req r7
underlay: .globl underlay // (unsigned size, char *ptr, unsigned ulen, unsigned p_flags) // ulen < PAGE_SIZE
underlay: .globl underlay // (unsigned size, char *ptr, unsigned ulen, unsigned p_flags) // ulen <= PAGE_SIZE
stmdb sp!,{r0,r1,r2,r3,r4,r5,r6,r7, lr}
ldmia sp!, {r4,r5,r6,r7} // r4= r0; r5= r1; r6= r2; r7= r3;
mov r0,sp

View File

@ -2,19 +2,19 @@ file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn Flags
0 SO_MAIN 05f0 0 0 040 2**4 CONTENTS
1 EXP_HEAD 0e0 0 0 0630 2**0 CONTENTS
2 NRV2E 0e5 0 0 0710 2**0 CONTENTS
3 NRV2D 0d7 0 0 07f5 2**0 CONTENTS
4 NRV2B 0c1 0 0 08cc 2**0 CONTENTS
5 SO_HEAD 01b 0 0 098d 2**0 CONTENTS
6 ptr_NEXT 0 0 0 09a8 2**0 CONTENTS
7 SO_TAIL 081 0 0 09a8 2**0 CONTENTS
8 LZMA_ELF00 064 0 0 0a29 2**0 CONTENTS
9 LZMA_DEC10 09f7 0 0 0a8d 2**0 CONTENTS
10 LZMA_DEC20 09f7 0 0 01484 2**0 CONTENTS
11 LZMA_DEC30 018 0 0 01e7b 2**0 CONTENTS
12 EXP_TAIL 0c 0 0 01e93 2**0 CONTENTS
0 SO_MAIN 079d 0 0 040 2**4 CONTENTS
1 EXP_HEAD 0e0 0 0 07dd 2**0 CONTENTS
2 NRV2E 0e5 0 0 08bd 2**0 CONTENTS
3 NRV2D 0d7 0 0 09a2 2**0 CONTENTS
4 NRV2B 0c1 0 0 0a79 2**0 CONTENTS
5 SO_HEAD 02c 0 0 0b3a 2**0 CONTENTS
6 ptr_NEXT 0 0 0 0b66 2**0 CONTENTS
7 SO_TAIL 08c 0 0 0b66 2**0 CONTENTS
8 LZMA_ELF00 064 0 0 0bf2 2**0 CONTENTS
9 LZMA_DEC10 09f7 0 0 0c56 2**0 CONTENTS
10 LZMA_DEC20 09f7 0 0 0164d 2**0 CONTENTS
11 LZMA_DEC30 018 0 0 02044 2**0 CONTENTS
12 EXP_TAIL 0c 0 0 0205c 2**0 CONTENTS
SYMBOL TABLE:
0000000000000000 l d EXP_HEAD 0 EXP_HEAD
0000000000000000 l d LZMA_DEC30 0 LZMA_DEC30
@ -30,21 +30,24 @@ SYMBOL TABLE:
0000000000000000 l d LZMA_DEC10 0 LZMA_DEC10
0000000000000000 l d LZMA_DEC20 0 LZMA_DEC20
0000000000000000 g EXP_HEAD 0 f_expand
000000000000006a g SO_TAIL 0 munmap
0000000000000075 g SO_TAIL 0 munmap
000000000000001c g SO_TAIL 0 memcpy
0000000000000031 g SO_TAIL 0 O_BINFO
0000000000000057 g SO_TAIL 0 ftruncate
0000000000000031 g SO_TAIL 0 mmap
0000000000000000 g F SO_TAIL 0 eof
0000000000000062 g SO_TAIL 0 write
0000000000000066 g SO_TAIL 0 read
000000000000006d g SO_TAIL 0 write
0000000000000355 g F SO_MAIN 01d PF_to_PROT
000000000000005b g SO_TAIL 0 memfd_create
0000000000000071 g SO_TAIL 0 read
0000000000000013 g SO_TAIL 0 memset
0000000000000011 g SO_TAIL 0 my_bkpt
000000000000006e g SO_TAIL 0 Pprotect
0000000000000079 g SO_TAIL 0 Pprotect
0000000000000053 g SO_TAIL 0 exit
000000000000005b g SO_TAIL 0 openat
000000000000006e g SO_TAIL 0 mprotect
0000000000000057 g SO_TAIL 0 close
0000000000000368 g F SO_MAIN 0288 upx_so_main
0000000000000066 g SO_TAIL 0 openat
0000000000000079 g SO_TAIL 0 mprotect
0000000000000062 g SO_TAIL 0 close
0000000000000372 g F SO_MAIN 042b upx_so_main
RELOCATION RECORDS FOR [SO_MAIN]:
OFFSET TYPE VALUE
@ -52,19 +55,38 @@ OFFSET TYPE VALUE
0000000000000017 R_X86_64_PLT32 exit+0xfffffffffffffffc
000000000000002e R_X86_64_PLT32 exit+0xfffffffffffffffc
000000000000010e R_X86_64_PLT32 f_expand+0xfffffffffffffffc
00000000000001e0 R_X86_64_PLT32 mmap+0xfffffffffffffffc
000000000000020a R_X86_64_PLT32 Pprotect+0xfffffffffffffffc
0000000000000268 R_X86_64_PLT32 openat+0xfffffffffffffffc
0000000000000283 R_X86_64_PLT32 read+0xfffffffffffffffc
0000000000000291 R_X86_64_PLT32 close+0xfffffffffffffffc
000000000000030d R_X86_64_PLT32 memcpy+0xfffffffffffffffc
000000000000032e R_X86_64_PLT32 mmap+0xfffffffffffffffc
000000000000033c R_X86_64_PLT32 memcpy+0xfffffffffffffffc
0000000000000401 R_X86_64_PLT32 mmap+0xfffffffffffffffc
0000000000000412 R_X86_64_PLT32 memcpy+0xfffffffffffffffc
000000000000043f R_X86_64_PLT32 Pprotect+0xfffffffffffffffc
00000000000005ad R_X86_64_PLT32 Pprotect+0xfffffffffffffffc
00000000000005c5 R_X86_64_PLT32 munmap+0xfffffffffffffffc
00000000000001cd R_X86_64_PLT32 mmap+0xfffffffffffffffc
00000000000001f7 R_X86_64_PLT32 Pprotect+0xfffffffffffffffc
0000000000000255 R_X86_64_PLT32 openat+0xfffffffffffffffc
0000000000000270 R_X86_64_PLT32 read+0xfffffffffffffffc
000000000000027e R_X86_64_PLT32 close+0xfffffffffffffffc
00000000000002fa R_X86_64_PLT32 memcpy+0xfffffffffffffffc
000000000000031b R_X86_64_PLT32 mmap+0xfffffffffffffffc
0000000000000329 R_X86_64_PLT32 memcpy+0xfffffffffffffffc
00000000000003ef R_X86_64_PLT32 mmap+0xfffffffffffffffc
0000000000000402 R_X86_64_PLT32 memcpy+0xfffffffffffffffc
00000000000004a4 R_X86_64_PLT32 memfd_create+0xfffffffffffffffc
00000000000004bd R_X86_64_PLT32 write+0xfffffffffffffffc
00000000000004d1 R_X86_64_PLT32 write+0xfffffffffffffffc
00000000000004e0 R_X86_64_PLT32 munmap+0xfffffffffffffffc
00000000000004e8 R_X86_64_PLT32 PF_to_PROT+0xfffffffffffffffc
0000000000000503 R_X86_64_PLT32 mmap+0xfffffffffffffffc
000000000000050a R_X86_64_PLT32 close+0xfffffffffffffffc
00000000000005e9 R_X86_64_PLT32 memfd_create+0xfffffffffffffffc
00000000000005f8 R_X86_64_PLT32 ftruncate+0xfffffffffffffffc
0000000000000608 R_X86_64_PLT32 write+0xfffffffffffffffc
000000000000062a R_X86_64_PLT32 mmap+0xfffffffffffffffc
000000000000063c R_X86_64_PLT32 munmap+0xfffffffffffffffc
00000000000006c7 R_X86_64_PLT32 my_bkpt+0xfffffffffffffffc
00000000000006cf R_X86_64_PLT32 PF_to_PROT+0xfffffffffffffffc
00000000000006f5 R_X86_64_PLT32 mmap+0xfffffffffffffffc
0000000000000704 R_X86_64_PLT32 munmap+0xfffffffffffffffc
000000000000070c R_X86_64_PLT32 close+0xfffffffffffffffc
0000000000000716 R_X86_64_PLT32 PF_to_PROT+0xfffffffffffffffc
000000000000072c R_X86_64_PLT32 Pprotect+0xfffffffffffffffc
0000000000000747 R_X86_64_PLT32 munmap+0xfffffffffffffffc
000000000000075e R_X86_64_PLT32 my_bkpt+0xfffffffffffffffc
0000000000000784 R_X86_64_PLT32 my_bkpt+0xfffffffffffffffc
RELOCATION RECORDS FOR [NRV2E]:
OFFSET TYPE VALUE
@ -83,7 +105,7 @@ OFFSET TYPE VALUE
RELOCATION RECORDS FOR [SO_HEAD]:
OFFSET TYPE VALUE
0000000000000009 R_X86_64_PC32 upx_so_main+0xfffffffffffffffc
0000000000000013 R_X86_64_PC32 upx_so_main+0xfffffffffffffffc
RELOCATION RECORDS FOR [LZMA_ELF00]:
OFFSET TYPE VALUE