~ubuntu-branches/debian/sid/upx-ucl/sid

« back to all changes in this revision

Viewing changes to src/stub/l_lx_elf.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Luberda
  • Date: 2006-06-13 21:23:23 UTC
  • mfrom: (1.3.1 upstream) (3.1.2 edgy)
  • Revision ID: james.westby@ubuntu.com-20060613212323-343yzs4jt6vr5483
* New upstream version.
* Standards-Version: 3.7.2 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* l_lx_elf.c -- stub loader for Linux x86 ELF executable
 
2
 
 
3
   This file is part of the UPX executable compressor.
 
4
 
 
5
   Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer
 
6
   Copyright (C) 1996-2004 Laszlo Molnar
 
7
   Copyright (C) 2000-2004 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
   <mfx@users.sourceforge.net>          <ml1050@users.sourceforge.net>
 
27
 
 
28
   John F. Reiser
 
29
   <jreiser@users.sourceforge.net>
 
30
 */
 
31
 
 
32
 
 
33
#include "linux.hh"
 
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
 
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
 
85
static void
 
86
err_exit(int a) __attribute__ ((__noreturn__));
 
87
{
 
88
    (void)a;  // debugging convenience
 
89
    exit(127);
 
90
}
 
91
#endif  //}
 
92
 
 
93
static void *
 
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
    unsigned ftid
 
111
);
 
112
typedef int f_expand(
 
113
    const nrv_byte *, nrv_uint,
 
114
          nrv_byte *, nrv_uint *, unsigned );
 
115
 
 
116
static void
 
117
unpackExtent(
 
118
    struct Extent *const xi,  // input
 
119
    struct Extent *const xo,  // output
 
120
    f_expand *const f_decompress,
 
121
    f_unfilter *f_unf
 
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;
 
153
            int const j = (*f_decompress)((unsigned char *)xi->buf, h.sz_cpr,
 
154
                (unsigned char *)xo->buf, &out_len, h.b_method );
 
155
            if (j != 0 || out_len != (nrv_uint)h.sz_unc)
 
156
                err_exit(7);
 
157
            // Skip Ehdr+Phdrs: separate 1st block, not filtered
 
158
            if (h.b_ftid!=0 && f_unf  // have filter
 
159
            &&  ((512 < out_len)  // this block is longer than Ehdr+Phdrs
 
160
              || (xo->size==(unsigned)h.sz_unc) )  // block is last in Extent
 
161
            ) {
 
162
                (*f_unf)((unsigned char *)xo->buf, out_len, h.b_cto8, h.b_ftid);
 
163
            }
 
164
            xi->buf  += h.sz_cpr;
 
165
            xi->size -= h.sz_cpr;
 
166
        }
 
167
        else { // copy literal block
 
168
            xread(xi, xo->buf, h.sz_cpr);
 
169
        }
 
170
        xo->buf  += h.sz_unc;
 
171
        xo->size -= h.sz_unc;
 
172
    }
 
173
}
 
174
 
 
175
// Create (or find) an escape hatch to use when munmapping ourselves the stub.
 
176
// Called by do_xmap to create it; remembered in AT_NULL.d_val
 
177
static void *
 
178
make_hatch(Elf32_Phdr const *const phdr, unsigned const reloc)
 
179
{
 
180
    unsigned *hatch = 0;
 
181
    if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
 
182
        // The format of the 'if' is
 
183
        //  if ( ( (hatch = loc1), test_loc1 )
 
184
        //  ||   ( (hatch = loc2), test_loc2 ) ) {
 
185
        //      action
 
186
        //  }
 
187
        // which uses the comma to save bytes when test_locj involves locj
 
188
        // and the action is the same when either test succeeds.
 
189
 
 
190
        // Try page fragmentation just beyond .text .
 
191
        if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr + reloc)),
 
192
                ( phdr->p_memsz==phdr->p_filesz  // don't pollute potential .bss
 
193
                &&  4<=(~PAGE_MASK & -(int)hatch) ) ) // space left on page
 
194
        // Try Elf32_Ehdr.e_ident[12..15] .  warning: 'const' cast away
 
195
        ||   ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr + reloc)->e_ident[12])),
 
196
                (phdr->p_offset==0) ) ) {
 
197
            // Omitting 'const' saves repeated literal in gcc.
 
198
            unsigned /*const*/ escape = 0xc36180cd;  // "int $0x80; popa; ret"
 
199
            // Don't store into read-only page if value is already there.
 
200
            if (* (volatile unsigned*) hatch != escape) {
 
201
                * hatch  = escape;
 
202
            }
 
203
        }
 
204
    }
 
205
    return hatch;
 
206
}
 
207
 
 
208
static void
 
209
__attribute__((regparm(2), stdcall))
 
210
upx_bzero(char *p, size_t len)
 
211
{
 
212
    if (len) do {
 
213
        *p++= 0;
 
214
    } while (--len);
 
215
}
 
216
#define bzero upx_bzero
 
217
 
 
218
 
 
219
static void
 
220
__attribute__((regparm(3), stdcall))
 
221
auxv_up(Elf32_auxv_t *av, unsigned const type, unsigned const value)
 
222
{
 
223
    if (av && 0==(1&(int)av))  /* PT_INTERP usually inhibits, except for hatch */
 
224
    for (;; ++av) {
 
225
        if (av->a_type==type || (av->a_type==AT_IGNORE && type!=AT_NULL)) {
 
226
            av->a_type = type;
 
227
            av->a_un.a_val = value;
 
228
            return;
 
229
        }
 
230
    }
 
231
}
 
232
 
 
233
// The PF_* and PROT_* bits are {1,2,4}; the conversion table fits in 32 bits.
 
234
#define REP8(x) \
 
235
    ((x)|((x)<<4)|((x)<<8)|((x)<<12)|((x)<<16)|((x)<<20)|((x)<<24)|((x)<<28))
 
236
#define EXP8(y) \
 
237
    ((1&(y)) ? 0xf0f0f0f0 : (2&(y)) ? 0xff00ff00 : (4&(y)) ? 0xffff0000 : 0)
 
238
#define PF_TO_PROT(pf) \
 
239
    ((PROT_READ|PROT_WRITE|PROT_EXEC) & ( \
 
240
        ( (REP8(PROT_EXEC ) & EXP8(PF_X)) \
 
241
         |(REP8(PROT_READ ) & EXP8(PF_R)) \
 
242
         |(REP8(PROT_WRITE) & EXP8(PF_W)) \
 
243
        ) >> ((pf & (PF_R|PF_W|PF_X))<<2) ))
 
244
 
 
245
 
 
246
// Find convex hull of PT_LOAD (the minimal interval which covers all PT_LOAD),
 
247
// and mmap that much, to be sure that a kernel using exec-shield-randomize
 
248
// won't place the first piece in a way that leaves no room for the rest.
 
249
static unsigned long  // returns relocation constant
 
250
__attribute__((regparm(3), stdcall))
 
251
xfind_pages(unsigned mflags, Elf32_Phdr const *phdr, int phnum,
 
252
    char **const p_brk
 
253
)
 
254
{
 
255
    size_t lo= ~0, hi= 0, szlo= 0;
 
256
    char *addr;
 
257
    mflags += MAP_PRIVATE | MAP_ANONYMOUS;  // '+' can optimize better than '|'
 
258
    for (; --phnum>=0; ++phdr) if (PT_LOAD==phdr->p_type) {
 
259
        if (phdr->p_vaddr < lo) {
 
260
            lo = phdr->p_vaddr;
 
261
            szlo = phdr->p_filesz;
 
262
        }
 
263
        if (hi < (phdr->p_memsz + phdr->p_vaddr)) {
 
264
            hi =  phdr->p_memsz + phdr->p_vaddr;
 
265
        }
 
266
    }
 
267
    szlo += ~PAGE_MASK & lo;  // page fragment on lo edge
 
268
    lo   -= ~PAGE_MASK & lo;  // round down to page boundary
 
269
    hi    =  PAGE_MASK & (hi - lo - PAGE_MASK -1);  // page length
 
270
    szlo  =  PAGE_MASK & (szlo    - PAGE_MASK -1);  // page length
 
271
    addr = mmap((void *)lo, hi, PROT_NONE, mflags, -1, 0);
 
272
    *p_brk = hi + addr;  // the logical value of brk(0)
 
273
    //mprotect(szlo + addr, hi - szlo, PROT_NONE);  // no access, but keep the frames!
 
274
    return (unsigned long)addr - lo;
 
275
}
 
276
 
 
277
static Elf32_Addr  // entry address
 
278
do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi,
 
279
    Elf32_auxv_t *const av, unsigned *p_reloc)
 
280
{
 
281
    Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
 
282
        (char const *)ehdr);
 
283
    char *v_brk;
 
284
    unsigned const reloc = xfind_pages(
 
285
        ((ET_EXEC==ehdr->e_type) ? MAP_FIXED : 0), phdr, ehdr->e_phnum, &v_brk);
 
286
    int j;
 
287
    for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
 
288
    if (PT_PHDR==phdr->p_type) {
 
289
        auxv_up(av, AT_PHDR, phdr->p_vaddr + reloc);
 
290
    }
 
291
    else if (PT_LOAD==phdr->p_type) {
 
292
        unsigned const prot = PF_TO_PROT(phdr->p_flags);
 
293
        struct Extent xo;
 
294
        size_t mlen = xo.size = phdr->p_filesz;
 
295
        char  *addr = xo.buf  =  (char *)(phdr->p_vaddr + reloc);
 
296
        char *haddr =           phdr->p_memsz + addr;
 
297
        size_t frag  = (int)addr &~ PAGE_MASK;
 
298
        mlen += frag;
 
299
        addr -= frag;
 
300
 
 
301
        // Decompressor can overrun the destination by 3 bytes.
 
302
        if (addr != mmap(addr, mlen + (xi ? 3 : 0), prot | (xi ? PROT_WRITE : 0),
 
303
                MAP_FIXED | MAP_PRIVATE | (xi ? MAP_ANONYMOUS : 0),
 
304
                (xi ? -1 : fdi), phdr->p_offset - frag) ) {
 
305
            err_exit(8);
 
306
        }
 
307
        if (xi) {
 
308
            unpackExtent(xi, &xo, (f_expand *)fdi,
 
309
                ((PROT_EXEC & prot) ? (f_unfilter *)(2+ fdi) : 0));
 
310
        }
 
311
        // Linux does not fixup the low end, so neither do we.
 
312
        //if (PROT_WRITE & prot) {
 
313
        //    bzero(addr, frag);  // fragment at lo end
 
314
        //}
 
315
        frag = (-mlen) &~ PAGE_MASK;  // distance to next page boundary
 
316
        if (PROT_WRITE & prot) { // note: read-only .bss not supported here
 
317
            bzero(mlen+addr, frag);  // fragment at hi end
 
318
        }
 
319
        if (xi) {
 
320
            void *const hatch = make_hatch(phdr, reloc);
 
321
            if (0!=hatch) {
 
322
                /* always update AT_NULL, especially for compressed PT_INTERP */
 
323
                auxv_up((Elf32_auxv_t *)(~1 & (int)av), AT_NULL, (unsigned)hatch);
 
324
            }
 
325
            if (0!=mprotect(addr, mlen, prot)) {
 
326
                err_exit(10);
 
327
ERR_LAB
 
328
            }
 
329
        }
 
330
        addr += mlen + frag;  /* page boundary on hi end */
 
331
        if (addr < haddr) { // need pages for .bss
 
332
            if (addr != mmap(addr, haddr - addr, prot,
 
333
                    MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ) ) {
 
334
                err_exit(9);
 
335
            }
 
336
        }
 
337
        else if (xi) { // cleanup if decompressor overrun crosses page boundary
 
338
            mlen = ~PAGE_MASK & (3+ mlen);
 
339
            if (mlen<=3) { // page fragment was overrun buffer only
 
340
                munmap(addr, mlen);
 
341
            }
 
342
        }
 
343
    }
 
344
    if (!xi) { // 2nd call (PT_INTERP); close()+check is smaller here
 
345
        if (0!=close(fdi)) {
 
346
            err_exit(11);
 
347
        }
 
348
    }
 
349
    else { // 1st call (main); also have (0!=av) here
 
350
        if (ET_DYN!=ehdr->e_type) {
 
351
            // Needed only if compressed shell script invokes compressed shell.
 
352
            do_brk(v_brk);
 
353
        }
 
354
    }
 
355
    if (0!=p_reloc) {
 
356
        *p_reloc = reloc;
 
357
    }
 
358
    return ehdr->e_entry + reloc;
 
359
}
 
360
 
 
361
 
 
362
/*************************************************************************
 
363
// upx_main - called by our entry code
 
364
//
 
365
// This function is optimized for size.
 
366
**************************************************************************/
 
367
 
 
368
void *upx_main(
 
369
    Elf32_auxv_t *const av,
 
370
    unsigned const sz_compressed,
 
371
    f_expand *const f_decompress,
 
372
    int junk,  // %esp from 'pusha'
 
373
    struct Extent xo,
 
374
    struct Extent xi,
 
375
    unsigned const volatile dynbase
 
376
) __asm__("upx_main");
 
377
 
 
378
void *upx_main(
 
379
    Elf32_auxv_t *const av,
 
380
    unsigned const sz_compressed,
 
381
    f_expand *const f_decompress,
 
382
    int junk,  // %esp from 'pusha'
 
383
    struct Extent xo,  // {sz_unc, ehdr}    for ELF headers
 
384
    struct Extent xi,  // {sz_cpr, &b_info} for ELF headers
 
385
    unsigned const volatile dynbase  // value+result: compiler must not change
 
386
)
 
387
{
 
388
    Elf32_Ehdr *const ehdr = (Elf32_Ehdr *)xo.buf;  // temp char[MAX_ELF_HDR+OVERHEAD]
 
389
    Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ ehdr);
 
390
    Elf32_Addr reloc;
 
391
    Elf32_Addr entry;
 
392
 
 
393
    // sizeof(Ehdr+Phdrs),   compressed; including b_info header
 
394
    size_t const sz_pckhdrs = xi.size;
 
395
 
 
396
    (void)junk;
 
397
 
 
398
    // Uncompress Ehdr and Phdrs.
 
399
    unpackExtent(&xi, &xo, f_decompress, 0);
 
400
 
 
401
    // Prepare to decompress the Elf headers again, into the first PT_LOAD.
 
402
    xi.buf  -= sz_pckhdrs;
 
403
    xi.size  = sz_compressed;
 
404
 
 
405
    // Some kernels omit AT_PHNUM,AT_PHENT,AT_PHDR because this stub has no PT_INTERP.
 
406
    // That is "too much" optimization.  Linux 2.6.x seems to give all AT_*.
 
407
    //auxv_up(av, AT_PAGESZ, PAGE_SIZE);  /* ld-linux.so.2 does not need this */
 
408
    auxv_up(av, AT_PHNUM , ehdr->e_phnum);
 
409
    auxv_up(av, AT_PHENT , ehdr->e_phentsize);
 
410
    auxv_up(av, AT_PHDR  , dynbase + (unsigned)(1+(Elf32_Ehdr *)phdr->p_vaddr));
 
411
    // AT_PHDR.a_un.a_val  is set again by do_xmap if PT_PHDR is present.
 
412
    // This is necessary for ET_DYN if|when we override a prelink address.
 
413
 
 
414
    entry = do_xmap((int)f_decompress, ehdr, &xi, av, &reloc);
 
415
    auxv_up(av, AT_ENTRY , entry);  // might not be necessary?
 
416
 
 
417
  { // Map PT_INTERP program interpreter
 
418
    int j;
 
419
    for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
 
420
        int const fdi = open(reloc + (char const *)phdr->p_vaddr, O_RDONLY, 0);
 
421
        if (0 > fdi) {
 
422
            err_exit(18);
 
423
        }
 
424
        if (MAX_ELF_HDR!=read(fdi, (void *)ehdr, MAX_ELF_HDR)) {
 
425
ERR_LAB
 
426
            err_exit(19);
 
427
        }
 
428
        entry = do_xmap(fdi, ehdr, 0, 0, 0);
 
429
        break;
 
430
    }
 
431
  }
 
432
 
 
433
    return (void *)entry;
 
434
}
 
435
 
 
436
 
 
437
/*
 
438
vi:ts=4:et:nowrap
 
439
*/
 
440