1 /* i386-linux.elf.interp-main.c -- stub loader for Linux x86 separate PT_INTERP
2 
3    This file is part of the UPX executable compressor.
4 
5    Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
6    Copyright (C) 1996-2020 Laszlo Molnar
7    Copyright (C) 2000-2020 John F. Reiser
8    All Rights Reserved.
9 
10    UPX and the UCL library are free software; you can redistribute them
11    and/or modify them under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2 of
13    the License, or (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; see the file COPYING.
22    If not, write to the Free Software Foundation, Inc.,
23    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25    Markus F.X.J. Oberhumer              Laszlo Molnar
26    <markus@oberhumer.com>               <ezerotven+github@gmail.com>
27 
28    John F. Reiser
29    <jreiser@users.sourceforge.net>
30  */
31 
32 
33 #include "include/linux.h"
34 
35 
36 /*************************************************************************
37 // configuration section
38 **************************************************************************/
39 
40 // In order to make it much easier to move this code at runtime and execute
41 // it at an address different from it load address:  there must be no
42 // static data, and no string constants.
43 
44 #define MAX_ELF_HDR 512  // Elf32_Ehdr + n*Elf32_Phdr must fit in this
45 
46 
47 /*************************************************************************
48 // "file" util
49 **************************************************************************/
50 
51 struct Extent {
52     size_t size;  // must be first to match size[0] uncompressed size
53     char *buf;
54 };
55 
56 
57 static void
58 #if (ACC_CC_GNUC >= 0x030300)
59 __attribute__((__noinline__, __used__, regparm(3), stdcall))
60 #endif
xread(struct Extent * x,char * buf,size_t count)61 xread(struct Extent *x, char *buf, size_t count)
62 {
63     char *p=x->buf, *q=buf;
64     size_t j;
65     if (x->size < count) {
66         exit(127);
67     }
68     for (j = count; 0!=j--; ++p, ++q) {
69         *q = *p;
70     }
71     x->buf  += count;
72     x->size -= count;
73 }
74 
75 
76 /*************************************************************************
77 // util
78 **************************************************************************/
79 
80 #if 1  //{  save space
81 #define ERR_LAB error: exit(127);
82 #define err_exit(a) goto error
83 #else  //}{  save debugging time
84 #define ERR_LAB /*empty*/
85 static void
err_exit(int a)86 err_exit(int a)
87 {
88     (void)a;  // debugging convenience
89     exit(127);
90 }
91 #endif  //}
92 
93 static void *
do_brk(void * addr)94 do_brk(void *addr)
95 {
96     return brk(addr);
97 }
98 
99 extern char *mmap(void *addr, size_t len,
100     int prot, int flags, int fd, off_t offset);
101 
102 /*************************************************************************
103 // UPX & NRV stuff
104 **************************************************************************/
105 
106 typedef void f_unfilter(
107     nrv_byte *,  // also addvalue
108     nrv_uint,
109     unsigned cto8 // junk in high 24 bits
110 );
111 typedef int f_expand(
112     const nrv_byte *, nrv_uint,
113           nrv_byte *, nrv_uint *, int method
114 );
115 
116 static void
unpackExtent(struct Extent * const xi,struct Extent * const xo,f_expand * (* get_fexp (int)),f_unfilter * (* get_funf (int)))117 unpackExtent(
118     struct Extent *const xi,  // input
119     struct Extent *const xo,  // output
120     f_expand   *(*get_fexp(int)),
121     f_unfilter *(*get_funf(int))
122 )
123 {
124     while (xo->size) {
125         struct b_info h;
126         //   Note: if h.sz_unc == h.sz_cpr then the block was not
127         //   compressible and is stored in its uncompressed form.
128 
129         // Read and check block sizes.
130         xread(xi, (char *)&h, sizeof(h));
131         if (h.sz_unc == 0) {                     // uncompressed size 0 -> EOF
132             if (h.sz_cpr != UPX_MAGIC_LE32)      // h.sz_cpr must be h->magic
133                 err_exit(2);
134             if (xi->size != 0)                 // all bytes must be written
135                 err_exit(3);
136             break;
137         }
138         if (h.sz_cpr <= 0) {
139             err_exit(4);
140 ERR_LAB
141         }
142         if (h.sz_cpr > h.sz_unc
143         ||  h.sz_unc > xo->size ) {
144             err_exit(5);
145         }
146         // Now we have:
147         //   assert(h.sz_cpr <= h.sz_unc);
148         //   assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
149         //   assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
150 
151         if (h.sz_cpr < h.sz_unc) { // Decompress block
152             nrv_uint out_len = h.sz_unc;  // EOF for lzma
153             int const j = (*get_fexp(h.b_method))((unsigned char *)xi->buf, h.sz_cpr,
154                 (unsigned char *)xo->buf, &out_len, *(int *)(void *)&h.b_method);
155             if (j != 0 || out_len != (nrv_uint)h.sz_unc)
156                 err_exit(7);
157             if (h.b_ftid!=0) {
158                 (*get_funf(h.b_ftid))((unsigned char *)xo->buf, out_len, h.b_cto8);
159             }
160             xi->buf  += h.sz_cpr;
161             xi->size -= h.sz_cpr;
162         }
163         else { // copy literal block
164             xread(xi, xo->buf, h.sz_cpr);
165         }
166         xo->buf  += h.sz_unc;
167         xo->size -= h.sz_unc;
168     }
169 }
170 
171 // Create (or find) an escape hatch to use when munmapping ourselves the stub.
172 // Called by do_xmap to create it, and by assembler code to find it.
173 static void *
make_hatch(Elf32_Phdr const * const phdr)174 make_hatch(Elf32_Phdr const *const phdr)
175 {
176     unsigned *hatch = 0;
177     if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
178         // The format of the 'if' is
179         //  if ( ( (hatch = loc1), test_loc1 )
180         //  ||   ( (hatch = loc2), test_loc2 ) ) {
181         //      action
182         //  }
183         // which uses the comma to save bytes when test_locj involves locj
184         // and the action is the same when either test succeeds.
185 
186         // Try page fragmentation just beyond .text .
187         if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)),
188                 ( phdr->p_memsz==phdr->p_filesz  // don't pollute potential .bss
189                 &&  4<=(~PAGE_MASK & -(int)hatch) ) ) // space left on page
190         // Try Elf32_Ehdr.e_ident[12..15] .  warning: 'const' cast away
191         ||   ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])),
192                 (phdr->p_offset==0) ) ) {
193             // Omitting 'const' saves repeated literal in gcc.
194             unsigned /*const*/ escape = 0xc36180cd;  // "int $0x80; popa; ret"
195             // Don't store into read-only page if value is already there.
196             if (* (volatile unsigned*) hatch != escape) {
197                 * hatch  = escape;
198             }
199         }
200     }
201     return hatch;
202 }
203 
204 static void
205 __attribute__((regparm(2), stdcall))
upx_bzero(char * p,size_t len)206 upx_bzero(char *p, size_t len)
207 {
208     if (len) do {
209         *p++= 0;
210     } while (--len);
211 }
212 #define bzero upx_bzero
213 
214 
215 static void
216 __attribute__((regparm(3), stdcall))
auxv_up(Elf32_auxv_t * av,unsigned const type,unsigned const value)217 auxv_up(Elf32_auxv_t *av, unsigned const type, unsigned const value)
218 {
219     if (av && 0==(1&(int)av))  /* PT_INTERP usually inhibits, except for hatch */
220     for (;; ++av) {
221         if (av->a_type==type || (av->a_type==AT_IGNORE && type!=AT_NULL)) {
222             av->a_type = type;
223             av->a_un.a_val = value;
224             return;
225         }
226         if (av->a_type==AT_NULL) {
227             // We can't do this as part of the for loop because we overwrite
228             // AT_NULL too.
229             return;
230         }
231     }
232 }
233 
234 // The PF_* and PROT_* bits are {1,2,4}; the conversion table fits in 32 bits.
235 #define REP8(x) \
236     ((x)|((x)<<4)|((x)<<8)|((x)<<12)|((x)<<16)|((x)<<20)|((x)<<24)|((x)<<28))
237 #define EXP8(y) \
238     ((1&(y)) ? 0xf0f0f0f0 : (2&(y)) ? 0xff00ff00 : (4&(y)) ? 0xffff0000 : 0)
239 #define PF_TO_PROT(pf) \
240     ((PROT_READ|PROT_WRITE|PROT_EXEC) & ( \
241         ( (REP8(PROT_EXEC ) & EXP8(PF_X)) \
242          |(REP8(PROT_READ ) & EXP8(PF_R)) \
243          |(REP8(PROT_WRITE) & EXP8(PF_W)) \
244         ) >> ((pf & (PF_R|PF_W|PF_X))<<2) ))
245 
246 
247 // Find convex hull of PT_LOAD (the minimal interval which covers all PT_LOAD),
248 // and mmap that much, to be sure that a kernel using exec-shield-randomize
249 // won't place the first piece in a way that leaves no room for the rest.
250 static unsigned long  // returns relocation constant
251 __attribute__((regparm(3), stdcall))
xfind_pages(unsigned mflags,Elf32_Phdr const * phdr,int phnum,char ** const p_brk)252 xfind_pages(unsigned mflags, Elf32_Phdr const *phdr, int phnum,
253     char **const p_brk
254 )
255 {
256     size_t lo= ~0, hi= 0, szlo= 0;
257     char *addr;
258     mflags += MAP_PRIVATE | MAP_ANONYMOUS;  // '+' can optimize better than '|'
259     for (; --phnum>=0; ++phdr) if (PT_LOAD==phdr->p_type) {
260         if (phdr->p_vaddr < lo) {
261             lo = phdr->p_vaddr;
262             szlo = phdr->p_filesz;
263         }
264         if (hi < (phdr->p_memsz + phdr->p_vaddr)) {
265             hi =  phdr->p_memsz + phdr->p_vaddr;
266         }
267     }
268     szlo += ~PAGE_MASK & lo;  // page fragment on lo edge
269     lo   -= ~PAGE_MASK & lo;  // round down to page boundary
270     hi    =  PAGE_MASK & (hi - lo - PAGE_MASK -1);  // page length
271     szlo  =  PAGE_MASK & (szlo    - PAGE_MASK -1);  // page length
272     addr = mmap((void *)lo, hi, PROT_READ|PROT_WRITE|PROT_EXEC, mflags, 0, 0);
273     *p_brk = hi + addr;  // the logical value of brk(0)
274     munmap(szlo + addr, hi - szlo);  // desirable if PT_LOAD non-contiguous
275     return (unsigned long)addr - lo;
276 }
277 
278 static Elf32_Addr  // entry address
do_xmap(int const fdi,f_unfilter * (* get_funf (int)),Elf32_Ehdr const * const ehdr,struct Extent * const xi,Elf32_auxv_t * const av)279 do_xmap(
280     int const fdi,
281     f_unfilter *(*get_funf(int)),
282     Elf32_Ehdr const *const ehdr,
283     struct Extent *const xi,
284     Elf32_auxv_t *const av)
285 {
286     f_expand   *(*(*get_fexp)(int));
287     Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
288         (char const *)ehdr);
289     char *v_brk;
290     unsigned long const reloc = xfind_pages(
291         ((ET_DYN!=ehdr->e_type) ? MAP_FIXED : 0), phdr, ehdr->e_phnum, &v_brk);
292     int j;
293 
294     *(int *)(void *)&get_fexp = fdi;
295     for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
296     if (PT_PHDR==phdr->p_type) {
297         auxv_up(av, AT_PHDR, phdr->p_vaddr + reloc);
298     }
299     else if (PT_LOAD==phdr->p_type) {
300         unsigned const prot = PF_TO_PROT(phdr->p_flags);
301         struct Extent xo;
302         size_t mlen = xo.size = phdr->p_filesz;
303         char  *addr = xo.buf  =                 (char *)phdr->p_vaddr;
304         char *haddr =           phdr->p_memsz +                  addr;
305         size_t frag  = (int)addr &~ PAGE_MASK;
306         mlen += frag;
307         addr -= frag;
308         addr  += reloc;
309         haddr += reloc;
310 
311         // Decompressor can overrun the destination by 3 bytes.
312         if (addr != mmap(addr, mlen + (xi ? 3 : 0), PROT_READ | PROT_WRITE,
313                 MAP_FIXED | MAP_PRIVATE | (xi ? MAP_ANONYMOUS : 0),
314                 fdi, phdr->p_offset - frag) ) {
315             err_exit(8);
316         }
317         if (xi) {
318             unpackExtent(xi, &xo, get_fexp, get_funf);
319         }
320         bzero(addr, frag);  // fragment at lo end
321         frag = (-mlen) &~ PAGE_MASK;  // distance to next page boundary
322         bzero(mlen+addr, frag);  // fragment at hi end
323         if (xi) {
324             void *const hatch = make_hatch(phdr);
325             if (0!=hatch) {
326                 /* always update AT_NULL, especially for compressed PT_INTERP */
327                 auxv_up((Elf32_auxv_t *)(~1 & (int)av), AT_NULL, (unsigned)hatch);
328             }
329         }
330         if (0!=mprotect(addr, mlen, prot)) {
331             err_exit(10);
332 ERR_LAB
333         }
334         addr += mlen + frag;  /* page boundary on hi end */
335         if (addr < haddr) { // need pages for .bss
336             if (addr != mmap(addr, haddr - addr, prot,
337                     MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ) ) {
338                 err_exit(9);
339             }
340         }
341         else if (xi) { // cleanup if decompressor overrun crosses page boundary
342             mlen = ~PAGE_MASK & (3+ mlen);
343             if (mlen<=3) { // page fragment was overrun buffer only
344                 munmap(addr, mlen);
345             }
346         }
347     }
348     if (!xi) { // 2nd call (PT_INTERP); close()+check is smaller here
349         if (0!=close((int)fdi)) {
350             err_exit(11);
351         }
352     }
353     else { // 1st call (main); also have (0!=av) here
354         if (ET_DYN!=ehdr->e_type) {
355             // Needed only if compressed shell script invokes compressed shell.
356             do_brk(v_brk);
357         }
358     }
359     return ehdr->e_entry + reloc;
360 }
361 
362 
363 /*************************************************************************
364 // pti_main - called by our entry code
365 //
366 // This function is optimized for size.
367 **************************************************************************/
368 
369 void *pti_main(
370     Elf32_auxv_t *const av,
371     unsigned const sz_compressed,
372     f_expand *(*get_fexp(int)),
373     Elf32_Ehdr *const ehdr,
374     struct Extent xo,
375     struct Extent xi,
376     f_unfilter *(*get_funf(int))
377 ) __asm__("pti_main");
378 
pti_main(Elf32_auxv_t * const av,unsigned const sz_compressed,f_expand * (* get_fexp (int)),Elf32_Ehdr * const ehdr,struct Extent xo,struct Extent xi,f_unfilter * (* get_funf (int)))379 void *pti_main(
380     Elf32_auxv_t *const av,
381     unsigned const sz_compressed,
382     f_expand *(*get_fexp(int)),
383     Elf32_Ehdr *const ehdr,  // temp char[MAX_ELF_HDR+OVERHEAD]
384     struct Extent xo,  // {sz_unc, ehdr}    for ELF headers
385     struct Extent xi,  // {sz_cpr, &b_info} for ELF headers
386     f_unfilter *(*get_funf(int))
387 )
388 {
389     Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ ehdr);
390     Elf32_Addr entry;
391 
392     // sizeof(Ehdr+Phdrs),   compressed; including b_info header
393     size_t const sz_pckhdrs = xi.size;
394 
395     // Uncompress Ehdr and Phdrs.
396     unpackExtent(&xi, &xo, get_fexp, get_funf);
397 
398     // Prepare to decompress the Elf headers again, into the first PT_LOAD.
399     xi.buf  -= sz_pckhdrs;
400     xi.size  = sz_compressed;
401 
402     // AT_PHDR.a_un.a_val  is set again by do_xmap if PT_PHDR is present.
403     auxv_up(av, AT_PHDR  , (unsigned)(1+(Elf32_Ehdr *)phdr->p_vaddr));
404     auxv_up(av, AT_PHENT , ehdr->e_phentsize);
405     auxv_up(av, AT_PHNUM , ehdr->e_phnum);
406     //auxv_up(av, AT_PAGESZ, PAGE_SIZE);  /* ld-linux.so.2 does not need this */
407     auxv_up(av, AT_ENTRY , (unsigned)ehdr->e_entry);
408     entry = do_xmap((int)get_fexp, get_funf, ehdr, &xi, av);
409 
410   { // Map PT_INTERP program interpreter
411     int j;
412     for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
413         char const *const iname = (char const *)phdr->p_vaddr;
414         int const fdi = open(iname, O_RDONLY, 0);
415         if (0 > fdi) {
416             err_exit(18);
417         }
418         if (MAX_ELF_HDR!=read(fdi, (void *)ehdr, MAX_ELF_HDR)) {
419 ERR_LAB
420             err_exit(19);
421         }
422         entry = do_xmap(fdi, 0, ehdr, 0, 0);
423         break;
424     }
425   }
426 
427     return (void *)entry;
428 }
429 
430 /* vim:set ts=4 sw=4 et: */
431