1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37: #include <stdio.h>
38: #include <stdlib.h>
39: #include <errno.h>
40: #include <sys/mman.h>
41: #include <unistd.h>
42:
43: #include "qemu.h"
44: #include "flat.h"
45:
46:
47:
48: #ifdef DEBUG
49: #define DBG_FLT(a...) printf(a)
50: #else
51: #define DBG_FLT(a...)
52: #endif
53:
54: #define flat_reloc_valid(reloc, size) ((reloc) <= (size))
55: #define flat_old_ram_flag(flag) (flag)
56: #ifdef TARGET_WORDS_BIGENDIAN
57: #define flat_get_relocate_addr(relval) (relval)
58: #else
59: #define flat_get_relocate_addr(relval) bswap32(relval)
60: #endif
61:
62: #define RELOC_FAILED 0xff00ff01
63: #define UNLOADED_LIB 0x7ff000ff
64:
65: struct lib_info {
66: abi_ulong start_code;
67: abi_ulong start_data;
68: abi_ulong end_data;
69: abi_ulong start_brk;
70: abi_ulong text_len;
71: abi_ulong entry;
72: abi_ulong build_date;
73: short loaded;
74: };
75:
76: #ifdef CONFIG_BINFMT_SHARED_FLAT
77: static int load_flat_shared_library(int id, struct lib_info *p);
78: #endif
79:
80: struct linux_binprm;
81:
82: #define ntohl(x) be32_to_cpu(x)
83:
84:
85:
86:
87:
88:
89:
90:
91:
92: static abi_ulong copy_strings(abi_ulong p, int n, char **s)
93: {
94: int len;
95:
96: while (n-- > 0) {
97: len = strlen(s[n]) + 1;
98: p -= len;
99: memcpy_to_target(p, s[n], len);
100: }
101:
102: return p;
103: }
104:
105: int target_pread(int fd, abi_ulong ptr, abi_ulong len,
106: abi_ulong offset)
107: {
108: void *buf;
109: int ret;
110:
111: buf = lock_user(VERIFY_WRITE, ptr, len, 0);
112: ret = pread(fd, buf, len, offset);
113: unlock_user(buf, ptr, len);
114: return ret;
115: }
116:
117:
118: #ifdef CONFIG_BINFMT_ZFLAT
119:
120: #include <linux/zlib.h>
121:
122: #define LBUFSIZE 4000
123:
124:
125: #define ASCII_FLAG 0x01
126: #define CONTINUATION 0x02
127: #define EXTRA_FIELD 0x04
128: #define ORIG_NAME 0x08
129: #define COMMENT 0x10
130: #define ENCRYPTED 0x20
131: #define RESERVED 0xC0
132:
133: static int decompress_exec(
134: struct linux_binprm *bprm,
135: unsigned long offset,
136: char *dst,
137: long len,
138: int fd)
139: {
140: unsigned char *buf;
141: z_stream strm;
142: loff_t fpos;
143: int ret, retval;
144:
145: DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
146:
147: memset(&strm, 0, sizeof(strm));
148: strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
149: if (strm.workspace == NULL) {
150: DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
151: return -ENOMEM;
152: }
153: buf = kmalloc(LBUFSIZE, GFP_KERNEL);
154: if (buf == NULL) {
155: DBG_FLT("binfmt_flat: no memory for read buffer\n");
156: retval = -ENOMEM;
157: goto out_free;
158: }
159:
160:
161: fpos = offset;
162: ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
163:
164: strm.next_in = buf;
165: strm.avail_in = ret;
166: strm.total_in = 0;
167:
168: retval = -ENOEXEC;
169:
170:
171: if (ret < 10) {
172: DBG_FLT("binfmt_flat: file too small?\n");
173: goto out_free_buf;
174: }
175:
176:
177: if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
178: DBG_FLT("binfmt_flat: unknown compression magic?\n");
179: goto out_free_buf;
180: }
181:
182:
183: if (buf[2] != 8) {
184: DBG_FLT("binfmt_flat: unknown compression method?\n");
185: goto out_free_buf;
186: }
187:
188: if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
189: (buf[3] & RESERVED)) {
190: DBG_FLT("binfmt_flat: unknown flags?\n");
191: goto out_free_buf;
192: }
193:
194: ret = 10;
195: if (buf[3] & EXTRA_FIELD) {
196: ret += 2 + buf[10] + (buf[11] << 8);
197: if (unlikely(LBUFSIZE == ret)) {
198: DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
199: goto out_free_buf;
200: }
201: }
202: if (buf[3] & ORIG_NAME) {
203: for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
204: ;
205: if (unlikely(LBUFSIZE == ret)) {
206: DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
207: goto out_free_buf;
208: }
209: }
210: if (buf[3] & COMMENT) {
211: for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
212: ;
213: if (unlikely(LBUFSIZE == ret)) {
214: DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
215: goto out_free_buf;
216: }
217: }
218:
219: strm.next_in += ret;
220: strm.avail_in -= ret;
221:
222: strm.next_out = dst;
223: strm.avail_out = len;
224: strm.total_out = 0;
225:
226: if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
227: DBG_FLT("binfmt_flat: zlib init failed?\n");
228: goto out_free_buf;
229: }
230:
231: while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
232: ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
233: if (ret <= 0)
234: break;
235: if (ret >= (unsigned long) -4096)
236: break;
237: len -= ret;
238:
239: strm.next_in = buf;
240: strm.avail_in = ret;
241: strm.total_in = 0;
242: }
243:
244: if (ret < 0) {
245: DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
246: ret, strm.msg);
247: goto out_zlib;
248: }
249:
250: retval = 0;
251: out_zlib:
252: zlib_inflateEnd(&strm);
253: out_free_buf:
254: kfree(buf);
255: out_free:
256: kfree(strm.workspace);
257: out:
258: return retval;
259: }
260:
261: #endif
262:
263:
264:
265: static abi_ulong
266: calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
267: {
268: abi_ulong addr;
269: int id;
270: abi_ulong start_brk;
271: abi_ulong start_data;
272: abi_ulong text_len;
273: abi_ulong start_code;
274:
275: #ifdef CONFIG_BINFMT_SHARED_FLAT
276: #error needs checking
277: if (r == 0)
278: id = curid;
279: else {
280: id = (r >> 24) & 0xff;
281: r &= 0x00ffffff;
282: }
283: if (id >= MAX_SHARED_LIBS) {
284: fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
285: (unsigned) r, id);
286: goto failed;
287: }
288: if (curid != id) {
289: if (internalp) {
290: fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
291: "in same module (%d != %d)\n",
292: (unsigned) r, curid, id);
293: goto failed;
294: } else if ( ! p[id].loaded &&
295: load_flat_shared_library(id, p) > (unsigned long) -4096) {
296: fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
297: goto failed;
298: }
299:
300: if (p[id].build_date && p[curid].build_date
301: && p[curid].build_date < p[id].build_date) {
302: fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
303: id, curid);
304: goto failed;
305: }
306: }
307: #else
308: id = 0;
309: #endif
310:
311: start_brk = p[id].start_brk;
312: start_data = p[id].start_data;
313: start_code = p[id].start_code;
314: text_len = p[id].text_len;
315:
316: if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
317: fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x "
318: "(0 - 0x%x/0x%x)\n",
319: (int) r,(int)(start_brk-start_code),(int)text_len);
320: goto failed;
321: }
322:
323: if (r < text_len)
324: addr = r + start_code;
325: else
326: addr = r - text_len + start_data;
327:
328:
329: return(addr);
330:
331: failed:
332: abort();
333: return RELOC_FAILED;
334: }
335:
336:
337:
338:
339: void old_reloc(struct lib_info *libinfo, uint32_t rl)
340: {
341: #ifdef DEBUG
342: char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
343: #endif
344: uint32_t *ptr;
345: uint32_t offset;
346: int reloc_type;
347:
348: offset = rl & 0x3fffffff;
349: reloc_type = rl >> 30;
350:
351: #if defined(CONFIG_COLDFIRE)
352: ptr = (uint32_t *) (libinfo->start_code + offset);
353: #else
354: ptr = (uint32_t *) (libinfo->start_data + offset);
355: #endif
356:
357: #ifdef DEBUG
358: fprintf(stderr, "Relocation of variable at DATASEG+%x "
359: "(address %p, currently %x) into segment %s\n",
360: offset, ptr, (int)*ptr, segment[reloc_type]);
361: #endif
362:
363: switch (reloc_type) {
364: case OLD_FLAT_RELOC_TYPE_TEXT:
365: *ptr += libinfo->start_code;
366: break;
367: case OLD_FLAT_RELOC_TYPE_DATA:
368: *ptr += libinfo->start_data;
369: break;
370: case OLD_FLAT_RELOC_TYPE_BSS:
371: *ptr += libinfo->end_data;
372: break;
373: default:
374: fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n",
375: reloc_type);
376: break;
377: }
378: DBG_FLT("Relocation became %x\n", (int)*ptr);
379: }
380:
381:
382:
383: static int load_flat_file(struct linux_binprm * bprm,
384: struct lib_info *libinfo, int id, abi_ulong *extra_stack)
385: {
386: struct flat_hdr * hdr;
387: abi_ulong textpos = 0, datapos = 0, result;
388: abi_ulong realdatastart = 0;
389: abi_ulong text_len, data_len, bss_len, stack_len, flags;
390: abi_ulong memp = 0;
391: abi_ulong extra;
392: abi_ulong reloc = 0, rp;
393: int i, rev, relocs = 0;
394: abi_ulong fpos;
395: abi_ulong start_code, end_code;
396: abi_ulong indx_len;
397:
398: hdr = ((struct flat_hdr *) bprm->buf);
399:
400: text_len = ntohl(hdr->data_start);
401: data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start);
402: bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
403: stack_len = ntohl(hdr->stack_size);
404: if (extra_stack) {
405: stack_len += *extra_stack;
406: *extra_stack = stack_len;
407: }
408: relocs = ntohl(hdr->reloc_count);
409: flags = ntohl(hdr->flags);
410: rev = ntohl(hdr->rev);
411:
412: DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
413:
414: if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
415: fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
416: rev, (int) FLAT_VERSION);
417: return -ENOEXEC;
418: }
419:
420:
421: if (rev == OLD_FLAT_VERSION && id != 0) {
422: fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
423: return -ENOEXEC;
424: }
425:
426:
427:
428:
429:
430: if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
431: flags = FLAT_FLAG_RAM;
432:
433: #ifndef CONFIG_BINFMT_ZFLAT
434: if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
435: fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
436: return -ENOEXEC;
437: }
438: #endif
439:
440:
441:
442:
443: extra = relocs * sizeof(abi_ulong);
444: if (extra < bss_len + stack_len)
445: extra = bss_len + stack_len;
446:
447:
448:
449: indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong);
450: indx_len = (indx_len + 15) & ~(abi_ulong)15;
451:
452:
453:
454:
455:
456:
457: if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
458:
459:
460:
461:
462: DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
463:
464: textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
465: MAP_PRIVATE, bprm->fd, 0);
466: if (textpos == -1) {
467: fprintf(stderr, "Unable to mmap process text\n");
468: return -1;
469: }
470:
471: realdatastart = target_mmap(0, data_len + extra + indx_len,
472: PROT_READ|PROT_WRITE|PROT_EXEC,
473: MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
474:
475: if (realdatastart == -1) {
476: fprintf(stderr, "Unable to allocate RAM for process data\n");
477: return realdatastart;
478: }
479: datapos = realdatastart + indx_len;
480:
481: DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
482: (int)(data_len + bss_len + stack_len), (int)datapos);
483:
484: fpos = ntohl(hdr->data_start);
485: #ifdef CONFIG_BINFMT_ZFLAT
486: if (flags & FLAT_FLAG_GZDATA) {
487: result = decompress_exec(bprm, fpos, (char *) datapos,
488: data_len + (relocs * sizeof(abi_ulong)))
489: } else
490: #endif
491: {
492: result = target_pread(bprm->fd, datapos,
493: data_len + (relocs * sizeof(abi_ulong)),
494: fpos);
495: }
496: if (result < 0) {
497: fprintf(stderr, "Unable to read data+bss\n");
498: return result;
499: }
500:
501: reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
502: memp = realdatastart;
503:
504: } else {
505:
506: textpos = target_mmap(0, text_len + data_len + extra + indx_len,
507: PROT_READ | PROT_EXEC | PROT_WRITE,
508: MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
509: if (textpos == -1 ) {
510: fprintf(stderr, "Unable to allocate RAM for process text/data\n");
511: return -1;
512: }
513:
514: realdatastart = textpos + ntohl(hdr->data_start);
515: datapos = realdatastart + indx_len;
516: reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
517: memp = textpos;
518:
519: #ifdef CONFIG_BINFMT_ZFLAT
520: #error code needs checking
521:
522:
523:
524: if (flags & FLAT_FLAG_GZIP) {
525: result = decompress_exec(bprm, sizeof (struct flat_hdr),
526: (((char *) textpos) + sizeof (struct flat_hdr)),
527: (text_len + data_len + (relocs * sizeof(unsigned long))
528: - sizeof (struct flat_hdr)),
529: 0);
530: memmove((void *) datapos, (void *) realdatastart,
531: data_len + (relocs * sizeof(unsigned long)));
532: } else if (flags & FLAT_FLAG_GZDATA) {
533: fpos = 0;
534: result = bprm->file->f_op->read(bprm->file,
535: (char *) textpos, text_len, &fpos);
536: if (result < (unsigned long) -4096)
537: result = decompress_exec(bprm, text_len, (char *) datapos,
538: data_len + (relocs * sizeof(unsigned long)), 0);
539: }
540: else
541: