From ef17dc10ca3ab2485915cd4547f9598fdf90da85 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Wed, 11 Jul 2001 17:08:16 +0000 Subject: [PATCH] Fix Elf_auxv table. upx was duplicating AT_PHDR (and others) because Linux 2.4.5 supplies many more AT_ entries than before. First noticed by Sebastian . fold_elf86.asm fold_sh86.asm l_lx_sep86.asm l_lx_elf.c l_lx_sh.c l_lx_sep.c committer: jreiser 994871296 +0000 --- src/stub/fold_elf86.asm | 87 ++++++++++++++++++++++++---------------- src/stub/fold_sh86.asm | 88 ++++++++++++++++++++++++---------------- src/stub/l_lx_elf.c | 18 ++++----- src/stub/l_lx_sep.c | 17 ++++---- src/stub/l_lx_sep86.asm | 89 +++++++++++++++++++++++++---------------- src/stub/l_lx_sh.c | 16 ++++---- 6 files changed, 186 insertions(+), 129 deletions(-) diff --git a/src/stub/fold_elf86.asm b/src/stub/fold_elf86.asm index 303a4431..0d9da6b6 100644 --- a/src/stub/fold_elf86.asm +++ b/src/stub/fold_elf86.asm @@ -24,6 +24,7 @@ ; markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com ; +%define PAGE_SIZE ( 1<<12) %define szElf32_Ehdr 0x34 %define szElf32_Phdr 8*4 %define e_entry (16 + 2*2 + 4) @@ -31,7 +32,9 @@ %define szb_info 12 %define szl_info 12 %define szp_info 12 +%define a_type 0 %define a_val 4 +%define sz_auxv 8 %define __NR_munmap 91 @@ -46,17 +49,59 @@ fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program pop eax ; discard &sz_uncompressed pop eax ; discard sz_uncompressed -; Move argc,argv,envp down so that we can insert more Elf_auxv entries. +; Move argc,argv,envp down to make room for complete Elf_auxv table. +; Linux kernel 2.4.2 and earlier give only AT_HWCAP and AT_PLATFORM +; because we have no PT_INTERP. Linux kernel 2.4.5 (and later?) +; give not quite everything. It is simpler and smaller code for us +; to generate a "complete" table where Elf_auxv[k -1].a_type = k. ; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance -%define PAGE_SIZE ( 1<<12) -%define OVERHEAD 2048 -%define MAX_ELF_HDR 512 +%define AT_NULL 0 +%define AT_IGNORE 1 +%define AT_PHDR 3 +%define AT_NUMBER 20 mov esi, esp - sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL + sub esp, sz_auxv * AT_NUMBER ; more than 128 bytes mov edi, esp - call do_auxv +do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL + ; cld + +L10: ; move argc+argv + lodsd + stosd + test eax,eax + jne L10 + +L20: ; move envp + lodsd + stosd + test eax,eax + jne L20 + +; complete Elf_auxv table full of AT_IGNORE + push edi ; save base of resulting table + inc eax ; convert 0 to AT_IGNORE + mov ecx, 2 * (AT_NUMBER -1) + rep stosd + dec eax ; convert AT_IGNORE into AT_NULL + stosd ; terminate Elf_auxv + stosd + pop edi ; base of resulting table + +L30: ; distribute existing Elf32_auxv into new table + lodsd + test eax,eax ; AT_NULL ? + xchg eax,edx + lodsd + je L40 + mov [a_type + sz_auxv*(edx -1) + edi], edx + mov [a_val + sz_auxv*(edx -1) + edi], eax + jmp L30 +L40: + +%define OVERHEAD 2048 +%define MAX_ELF_HDR 512 push ebx ; save &Elf32_Ehdr of this stub sub esp, dword MAX_ELF_HDR + OVERHEAD @@ -67,14 +112,14 @@ fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program mov edx, esp ; mov ecx, [4+ eax] ; length of compressed ELF headers add ecx, byte szb_info - pusha ; (AT_next, sz_cpr, f_expand, &tmp_ehdr, {sz_unc, &tmp}, {sz_cpr, &b1st_info} ) + pusha ; (AT_table, sz_cpr, f_expand, &tmp_ehdr, {sz_unc, &tmp}, {sz_cpr, &b1st_info} ) EXTERN upx_main call upx_main ; returns entry address add esp, dword 8*4 + MAX_ELF_HDR + OVERHEAD ; remove 8 params, temp space pop ebx ; &Elf32_Ehdr of this stub push eax ; save entry address - mov edi, [a_val + edi] ; AT_PHDR + mov edi, [a_val + sz_auxv * (AT_PHDR -1) + edi] find_hatch: push edi EXTERN make_hatch @@ -104,31 +149,5 @@ EXTERN make_hatch mov eax, __NR_munmap ; do not dirty the stack with push byte + pop jmp edx ; unmap ourselves via escape hatch, then goto entry -do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL - ; cld - -L10: ; move argc+argv - lodsd - stosd - test eax,eax - jne L10 - -L20: ; move envp - lodsd - stosd - test eax,eax - jne L20 - -L30: ; move existing Elf32_auxv - lodsd - stosd - test eax,eax ; AT_NULL ? - lodsd - stosd - jne L30 - - sub edi, byte 8 ; point to AT_NULL - ret - ; vi:ts=8:et:nowrap diff --git a/src/stub/fold_sh86.asm b/src/stub/fold_sh86.asm index 175d5c7f..2baccc19 100644 --- a/src/stub/fold_sh86.asm +++ b/src/stub/fold_sh86.asm @@ -30,29 +30,75 @@ BITS 32 SECTION .text +%define PAGE_SIZE ( 1<<12) %define szElf32_Ehdr 0x34 %define szElf32_Phdr 8*4 %define e_entry (16 + 2*2 + 4) %define p_memsz 5*4 %define szl_info 12 %define szp_info 12 +%define a_type 0 +%define a_val 4 +%define sz_auxv 8 fold_begin: ; enter: %ebx= uncDst ; also edx= szElf32_Ehdr + 2*szElf32_Phdr + &Elf32_Ehdr pop eax ; discard &sz_uncompressed pop eax ; discard sz_uncompressed -; Move argc,argv,envp down so that we can insert more Elf_auxv entries. +; Move argc,argv,envp down to make room for complete Elf_auxv table. +; Linux kernel 2.4.2 and earlier give only AT_HWCAP and AT_PLATFORM +; because we have no PT_INTERP. Linux kernel 2.4.5 (and later?) +; give not quite everything. It is simpler and smaller code for us +; to generate a "complete" table where Elf_auxv[k -1].a_type = k. ; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance +%define AT_NULL 0 +%define AT_IGNORE 1 +%define AT_PHDR 3 +%define AT_NUMBER 20 + + mov esi, esp + sub esp, sz_auxv * AT_NUMBER ; more than 128 bytes + mov edi, esp +do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL + ; cld + +L10: ; move argc+argv + lodsd + stosd + test eax,eax + jne L10 + +L20: ; move envp + lodsd + stosd + test eax,eax + jne L20 + +; complete Elf_auxv table full of AT_IGNORE + push edi ; save base of resulting table + inc eax ; convert 0 to AT_IGNORE + mov ecx, 2 * (AT_NUMBER -1) + rep stosd + dec eax ; convert AT_IGNORE into AT_NULL + stosd ; terminate Elf_auxv + stosd + pop edi ; base of resulting table + +L30: ; distribute existing Elf32_auxv into new table + lodsd + test eax,eax ; AT_NULL ? + xchg eax,edx + lodsd + je L40 + mov [a_type + sz_auxv*(edx -1) + edi], edx + mov [a_val + sz_auxv*(edx -1) + edi], eax + jmp L30 +L40: + %define OVERHEAD 2048 %define MAX_ELF_HDR 512 -%define PAGE_SIZE ( 1<<12) - - mov esi, esp - sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL - mov edi, esp - call do_auxv ; edi= &AT_NEXT sub esp, dword MAX_ELF_HDR + OVERHEAD @@ -61,7 +107,7 @@ fold_begin: ; enter: %ebx= uncDst mov ecx, [ edx] ; sz_unc mov ebx, [4+ edx] ; sz_cpr mov esi, eax ; extra copy of uncDst - pusha ; (&AT_NEXT,uncDst,f_decpr,&ehdr,{sz_cpr,cprSrc},{sz_unc,uncDst}) + pusha ; (AT_table,uncDst,f_decpr,&ehdr,{sz_cpr,cprSrc},{sz_unc,uncDst}) EXTERN upx_main call upx_main ; entry = upx_main(...) pop ecx ; junk @@ -108,32 +154,6 @@ EXTERN upx_main popa ret -do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL - ; cld - -L10: ; move argc+argv - lodsd - stosd - test eax,eax - jne L10 - -L20: ; move envp - lodsd - stosd - test eax,eax - jne L20 - -L30: ; move existing Elf32_auxv - lodsd - stosd - test eax,eax ; AT_NULL ? - lodsd - stosd - jne L30 - - sub edi, byte 8 ; point to AT_NULL - ret - ; vi:ts=8:et:nowrap diff --git a/src/stub/l_lx_elf.c b/src/stub/l_lx_elf.c index 6a27626e..65d6e1c8 100644 --- a/src/stub/l_lx_elf.c +++ b/src/stub/l_lx_elf.c @@ -214,7 +214,7 @@ bzero(char *p, size_t len) static Elf32_Addr // entry address do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi, - Elf32_auxv_t *const a) + Elf32_auxv_t *const av) { Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff + (char const *)ehdr); @@ -222,7 +222,7 @@ do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi, int j; for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_PHDR==phdr->p_type) { - a->a_un.a_val = phdr->p_vaddr; + av[AT_PHDR -1].a_un.a_val = phdr->p_vaddr; } else if (PT_LOAD==phdr->p_type) { struct Extent xo; @@ -346,14 +346,12 @@ void *upx_main( xi.buf -= sz_pckhdrs; xi.size = sz_compressed; - // av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present. - // Caller of upx_main assumes that AT_PHDR will be set into av[0] . - av[0].a_type = AT_PHDR; av[0].a_un.a_ptr = 1+(Elf32_Ehdr *)phdr->p_vaddr; - av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize; - av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum; - av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGE_SIZE; - av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry; - av[5].a_type = AT_NULL; + // av[AT_PHDR -1].a_un.a_val is set again by do_xmap if PT_PHDR is present. + av[AT_PHDR -1].a_type = AT_PHDR ; av[AT_PHDR -1].a_un.a_ptr = 1+(Elf32_Ehdr *)phdr->p_vaddr; + av[AT_PHENT -1].a_type = AT_PHENT ; av[AT_PHENT -1].a_un.a_val = ehdr->e_phentsize; + av[AT_PHNUM -1].a_type = AT_PHNUM ; av[AT_PHNUM -1].a_un.a_val = ehdr->e_phnum; + av[AT_PAGESZ -1].a_type = AT_PAGESZ; av[AT_PAGESZ -1].a_un.a_val = PAGE_SIZE; + av[AT_ENTRY -1].a_type = AT_ENTRY ; av[AT_ENTRY -1].a_un.a_val = ehdr->e_entry; entry = do_xmap((int)f_decompress, ehdr, &xi, av); { // Map PT_INTERP program interpreter diff --git a/src/stub/l_lx_sep.c b/src/stub/l_lx_sep.c index 56f4ad27..e0724ac1 100644 --- a/src/stub/l_lx_sep.c +++ b/src/stub/l_lx_sep.c @@ -234,7 +234,7 @@ bzero(char *p, size_t len) static Elf32_Addr // entry address do_xmap(int fdi, Elf32_Ehdr const *const ehdr, f_expand *const f_decompress, - Elf32_auxv_t *const a) + Elf32_auxv_t *const av) { struct Extent x; Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff + @@ -243,7 +243,7 @@ do_xmap(int fdi, Elf32_Ehdr const *const ehdr, f_expand *const f_decompress, int j; for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_PHDR==phdr->p_type) { - a->a_un.a_val = phdr->p_vaddr; + av[AT_PHDR -1].a_un.a_val = phdr->p_vaddr; } else if (PT_LOAD==phdr->p_type) { size_t mlen = x.size = phdr->p_filesz; @@ -390,13 +390,12 @@ ERR_LAB if (lseek(fdi, -(sizeof(xo) + sz_pckhdrs), SEEK_CUR) < 0) { err_exit(17); } - // av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present - av[0].a_type = AT_PHDR; av[0].a_un.a_ptr = 1+(Elf32_Ehdr *)phdr->p_vaddr; - av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize; - av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum; - av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGE_SIZE; - av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry; - av[5].a_type = AT_NULL; + // av[AT_PHDR -1].a_un.a_val is set again by do_xmap if PT_PHDR is present. + av[AT_PHDR -1].a_type = AT_PHDR ; av[AT_PHDR -1].a_un.a_ptr = 1+(Elf32_Ehdr *)phdr->p_vaddr; + av[AT_PHENT -1].a_type = AT_PHENT ; av[AT_PHENT -1].a_un.a_val = ehdr->e_phentsize; + av[AT_PHNUM -1].a_type = AT_PHNUM ; av[AT_PHNUM -1].a_un.a_val = ehdr->e_phnum; + av[AT_PAGESZ -1].a_type = AT_PAGESZ; av[AT_PAGESZ -1].a_un.a_val = PAGE_SIZE; + av[AT_ENTRY -1].a_type = AT_ENTRY ; av[AT_ENTRY -1].a_un.a_val = ehdr->e_entry; entry = do_xmap(fdi, ehdr, f_decompress, av); // Map PT_INTERP program interpreter diff --git a/src/stub/l_lx_sep86.asm b/src/stub/l_lx_sep86.asm index f8ed7dfc..deff75ab 100644 --- a/src/stub/l_lx_sep86.asm +++ b/src/stub/l_lx_sep86.asm @@ -132,6 +132,9 @@ decompress: %define PAGE_MASK (~0<<12) %define PAGE_SIZE ( 1<<12) +%define a_type 0 +%define a_val 4 +%define sz_auxv 8 %define szElf32_Phdr 8*4 %define a_val 4 @@ -141,26 +144,69 @@ main: pop ebp ; &decompress cld -; Move argc,argv,envp down so that we can insert more Elf_auxv entries. +; Move argc,argv,envp down to make room for complete Elf_auxv table. +; Linux kernel 2.4.2 and earlier give only AT_HWCAP and AT_PLATFORM +; because we have no PT_INTERP. Linux kernel 2.4.5 (and later?) +; give not quite everything. It is simpler and smaller code for us +; to generate a "complete" table where Elf_auxv[k -1].a_type = k. ; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance +%define AT_NULL 0 +%define AT_IGNORE 1 +%define AT_PHDR 3 +%define AT_NUMBER 20 + + mov esi, esp + sub esp, sz_auxv * AT_NUMBER ; more than 128 bytes + mov edi, esp +do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL + ; cld + +L10: ; move argc+argv + lodsd + stosd + test eax,eax + jne L10 + +L20: ; move envp + lodsd + stosd + test eax,eax + jne L20 + +; complete Elf_auxv table full of AT_IGNORE + push edi ; save base of resulting table + inc eax ; convert 0 to AT_IGNORE + mov ecx, 2 * (AT_NUMBER -1) + rep stosd + dec eax ; convert AT_IGNORE into AT_NULL + stosd ; terminate Elf_auxv + stosd + pop edi ; base of resulting table + +L30: ; distribute existing Elf32_auxv into new table + lodsd + test eax,eax ; AT_NULL ? + xchg eax,edx + lodsd + je L40 + mov [a_type + sz_auxv*(edx -1) + edi], edx + mov [a_val + sz_auxv*(edx -1) + edi], eax + jmp L30 +L40: + %define OVERHEAD 2048 %define MAX_ELF_HDR 512 - mov esi, esp - sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL - mov edi, esp - call do_auxv ; edi= &AT_next - lea ecx, [4+esp] ; argv sub esp, dword MAX_ELF_HDR + OVERHEAD push esp ; argument: temp space - push edi ; argument: AT_next + push edi ; argument: AT_table push ebp ; argument: &decompress push ecx ; argument: argv EXTERN upx_main - call upx_main ; entry = upx_main(argv, &decompress, AT_next, tmp_ehdr) + call upx_main ; entry = upx_main(argv, &decompress, AT_table, tmp_ehdr) add esp, dword 4*4 + MAX_ELF_HDR + OVERHEAD ; remove temp space, args pop ecx ; argc @@ -169,7 +215,7 @@ EXTERN upx_main push ecx push eax ; save entry address - mov edi, [a_val + edi] ; AT_PHDR + mov edi, [a_val + sz_auxv * (AT_PHDR -1) + edi] find_hatch: push edi EXTERN make_hatch @@ -199,31 +245,6 @@ EXTERN make_hatch mov eax, __NR_munmap ; do not dirty the stack with push byte + pop jmp edx ; unmap ourselves, then goto entry -do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL - ; cld - -L10: ; move argc+argv - lodsd - stosd - test eax,eax - jne L10 - -L20: ; move envp - lodsd - stosd - test eax,eax - jne L20 - -L30: ; move existing Elf32_auxv - lodsd - stosd - test eax,eax ; AT_NULL ? - lodsd - stosd - jne L30 - - sub edi, byte 8 ; point to AT_NULL - ret ; vi:ts=8:et:nowrap diff --git a/src/stub/l_lx_sh.c b/src/stub/l_lx_sh.c index 18ad098c..21adadc6 100644 --- a/src/stub/l_lx_sh.c +++ b/src/stub/l_lx_sh.c @@ -172,7 +172,7 @@ bzero(char *p, size_t len) // Notice there is no make_hatch(), either. static Elf32_Addr // entry address -do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, Elf32_auxv_t *const a) +do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, Elf32_auxv_t *const av) { Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff + (char const *)ehdr); @@ -180,7 +180,7 @@ do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, Elf32_auxv_t *const a) int j; for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_PHDR==phdr->p_type) { - a->a_un.a_val = phdr->p_vaddr; + av[AT_PHDR -1].a_un.a_val = phdr->p_vaddr; } else if (PT_LOAD==phdr->p_type) { struct Extent xo; @@ -301,12 +301,12 @@ void *upx_main( entry = getexec(fn, ehdr, av); *efn = c; // replace terminator character - av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap - av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize; - av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum; - av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGE_SIZE; - av[4].a_type = AT_ENTRY; av[4].a_un.a_val = entry; - av[5].a_type = AT_NULL; + // av[AT_PHDR -1].a_un.a_val is set again by do_xmap if PT_PHDR is present. + av[AT_PHDR -1].a_type = AT_PHDR ; // av[AT_PHDR-1].a_un.a_val is set by do_xmap + av[AT_PHENT -1].a_type = AT_PHENT ; av[AT_PHENT -1].a_un.a_val = ehdr->e_phentsize; + av[AT_PHNUM -1].a_type = AT_PHNUM ; av[AT_PHNUM -1].a_un.a_val = ehdr->e_phnum; + av[AT_PAGESZ -1].a_type = AT_PAGESZ; av[AT_PAGESZ -1].a_un.a_val = PAGE_SIZE; + av[AT_ENTRY -1].a_type = AT_ENTRY ; av[AT_ENTRY -1].a_un.a_val = entry; } { // Map PT_INTERP program interpreter