1 /****************************************************************************/ 2 /* 3 * QEMU bFLT binary loader. Based on linux/fs/binfmt_flat.c 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, see <http://www.gnu.org/licenses/>. 17 * 18 * Copyright (C) 2006 CodeSourcery. 19 * Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com> 20 * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com> 21 * Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com> 22 * Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com> 23 * based heavily on: 24 * 25 * linux/fs/binfmt_aout.c: 26 * Copyright (C) 1991, 1992, 1996 Linus Torvalds 27 * linux/fs/binfmt_flat.c for 2.0 kernel 28 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> 29 * JAN/99 -- coded full program relocation (gerg@snapgear.com) 30 */ 31 32 /****************************************************************************/ 33 34 #include "qemu/osdep.h" 35 36 #include "qemu.h" 37 #include "user-internals.h" 38 #include "loader.h" 39 #include "user-mmap.h" 40 #include "flat.h" 41 #include "target_flat.h" 42 43 //#define DEBUG 44 45 #ifdef DEBUG 46 #define DBG_FLT(...) printf(__VA_ARGS__) 47 #else 48 #define DBG_FLT(...) 49 #endif 50 51 #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ 52 #define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ 53 54 struct lib_info { 55 abi_ulong start_code; /* Start of text segment */ 56 abi_ulong start_data; /* Start of data segment */ 57 abi_ulong end_data; /* Start of bss section */ 58 abi_ulong start_brk; /* End of data segment */ 59 abi_ulong text_len; /* Length of text segment */ 60 abi_ulong entry; /* Start address for this module */ 61 abi_ulong build_date; /* When this one was compiled */ 62 short loaded; /* Has this library been loaded? */ 63 }; 64 65 struct linux_binprm; 66 67 /****************************************************************************/ 68 /* 69 * create_flat_tables() parses the env- and arg-strings in new user 70 * memory and creates the pointer tables from them, and puts their 71 * addresses on the "stack", returning the new stack pointer value. 72 */ 73 74 /* Push a block of strings onto the guest stack. */ 75 static abi_ulong copy_strings(abi_ulong p, int n, char **s) 76 { 77 int len; 78 79 while (n-- > 0) { 80 len = strlen(s[n]) + 1; 81 p -= len; 82 memcpy_to_target(p, s[n], len); 83 } 84 85 return p; 86 } 87 88 static int target_pread(int fd, abi_ulong ptr, abi_ulong len, 89 abi_ulong offset) 90 { 91 void *buf; 92 int ret; 93 94 buf = lock_user(VERIFY_WRITE, ptr, len, 0); 95 if (!buf) { 96 return -EFAULT; 97 } 98 ret = pread(fd, buf, len, offset); 99 if (ret < 0) { 100 ret = -errno; 101 } 102 unlock_user(buf, ptr, len); 103 return ret; 104 } 105 106 /****************************************************************************/ 107 108 static abi_ulong 109 calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp) 110 { 111 abi_ulong addr; 112 int id; 113 abi_ulong start_brk; 114 abi_ulong start_data; 115 abi_ulong text_len; 116 abi_ulong start_code; 117 118 id = 0; 119 120 start_brk = p[id].start_brk; 121 start_data = p[id].start_data; 122 start_code = p[id].start_code; 123 text_len = p[id].text_len; 124 125 if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { 126 fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x " 127 "(0 - 0x%x/0x%x)\n", 128 (int) r,(int)(start_brk-start_code),(int)text_len); 129 goto failed; 130 } 131 132 if (r < text_len) /* In text segment */ 133 addr = r + start_code; 134 else /* In data segment */ 135 addr = r - text_len + start_data; 136 137 /* Range checked already above so doing the range tests is redundant...*/ 138 return(addr); 139 140 failed: 141 abort(); 142 return RELOC_FAILED; 143 } 144 145 /****************************************************************************/ 146 147 /* ??? This does not handle endianness correctly. */ 148 static void old_reloc(struct lib_info *libinfo, uint32_t rl) 149 { 150 #ifdef DEBUG 151 const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; 152 #endif 153 uint32_t *ptr; 154 uint32_t offset; 155 int reloc_type; 156 157 offset = rl & 0x3fffffff; 158 reloc_type = rl >> 30; 159 /* ??? How to handle this? */ 160 #if defined(CONFIG_COLDFIRE) 161 ptr = (uint32_t *) ((unsigned long) libinfo->start_code + offset); 162 #else 163 ptr = (uint32_t *) ((unsigned long) libinfo->start_data + offset); 164 #endif 165 166 #ifdef DEBUG 167 fprintf(stderr, "Relocation of variable at DATASEG+%x " 168 "(address %p, currently %x) into segment %s\n", 169 offset, ptr, (int)*ptr, segment[reloc_type]); 170 #endif 171 172 switch (reloc_type) { 173 case OLD_FLAT_RELOC_TYPE_TEXT: 174 *ptr += libinfo->start_code; 175 break; 176 case OLD_FLAT_RELOC_TYPE_DATA: 177 *ptr += libinfo->start_data; 178 break; 179 case OLD_FLAT_RELOC_TYPE_BSS: 180 *ptr += libinfo->end_data; 181 break; 182 default: 183 fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n", 184 reloc_type); 185 break; 186 } 187 DBG_FLT("Relocation became %x\n", (int)*ptr); 188 } 189 190 /****************************************************************************/ 191 192 static int load_flat_file(struct linux_binprm * bprm, 193 struct lib_info *libinfo, int id, abi_ulong *extra_stack) 194 { 195 struct flat_hdr * hdr; 196 abi_ulong textpos = 0, datapos = 0; 197 abi_long result; 198 abi_ulong realdatastart = 0; 199 abi_ulong text_len, data_len, bss_len, stack_len, flags; 200 abi_ulong extra; 201 abi_ulong reloc = 0, rp; 202 int i, rev, relocs = 0; 203 abi_ulong fpos; 204 abi_ulong start_code; 205 abi_ulong indx_len; 206 207 hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ 208 209 text_len = ntohl(hdr->data_start); 210 data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); 211 bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end); 212 stack_len = ntohl(hdr->stack_size); 213 if (extra_stack) { 214 stack_len += *extra_stack; 215 *extra_stack = stack_len; 216 } 217 relocs = ntohl(hdr->reloc_count); 218 flags = ntohl(hdr->flags); 219 rev = ntohl(hdr->rev); 220 221 DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename); 222 223 if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { 224 fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n", 225 rev, (int) FLAT_VERSION); 226 return -ENOEXEC; 227 } 228 229 /* Don't allow old format executables to use shared libraries */ 230 if (rev == OLD_FLAT_VERSION && id != 0) { 231 fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n"); 232 return -ENOEXEC; 233 } 234 235 /* 236 * fix up the flags for the older format, there were all kinds 237 * of endian hacks, this only works for the simple cases 238 */ 239 if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags)) 240 flags = FLAT_FLAG_RAM; 241 242 if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { 243 fprintf(stderr, "ZFLAT executables are not supported\n"); 244 return -ENOEXEC; 245 } 246 247 /* 248 * calculate the extra space we need to map in 249 */ 250 extra = relocs * sizeof(abi_ulong); 251 if (extra < bss_len + stack_len) 252 extra = bss_len + stack_len; 253 254 /* Add space for library base pointers. Make sure this does not 255 misalign the doesn't misalign the data segment. */ 256 indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong); 257 indx_len = (indx_len + 15) & ~(abi_ulong)15; 258 259 /* 260 * Allocate the address space. 261 */ 262 probe_guest_base(bprm->filename, 0, 263 text_len + data_len + extra + indx_len - 1); 264 265 /* 266 * there are a couple of cases here, the separate code/data 267 * case, and then the fully copied to RAM case which lumps 268 * it all together. 269 */ 270 if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) { 271 /* 272 * this should give us a ROM ptr, but if it doesn't we don't 273 * really care 274 */ 275 DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); 276 277 textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC, 278 MAP_PRIVATE, bprm->src.fd, 0); 279 if (textpos == -1) { 280 fprintf(stderr, "Unable to mmap process text\n"); 281 return -1; 282 } 283 284 realdatastart = target_mmap(0, data_len + extra + indx_len, 285 PROT_READ|PROT_WRITE|PROT_EXEC, 286 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 287 288 if (realdatastart == -1) { 289 fprintf(stderr, "Unable to allocate RAM for process data\n"); 290 return realdatastart; 291 } 292 datapos = realdatastart + indx_len; 293 294 DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", 295 (int)(data_len + bss_len + stack_len), (int)datapos); 296 297 fpos = ntohl(hdr->data_start); 298 result = target_pread(bprm->src.fd, datapos, 299 data_len + (relocs * sizeof(abi_ulong)), 300 fpos); 301 if (result < 0) { 302 fprintf(stderr, "Unable to read data+bss\n"); 303 return result; 304 } 305 306 reloc = datapos + (ntohl(hdr->reloc_start) - text_len); 307 308 } else { 309 310 textpos = target_mmap(0, text_len + data_len + extra + indx_len, 311 PROT_READ | PROT_EXEC | PROT_WRITE, 312 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 313 if (textpos == -1 ) { 314 fprintf(stderr, "Unable to allocate RAM for process text/data\n"); 315 return -1; 316 } 317 318 realdatastart = textpos + ntohl(hdr->data_start); 319 datapos = realdatastart + indx_len; 320 reloc = (textpos + ntohl(hdr->reloc_start) + indx_len); 321 322 result = target_pread(bprm->src.fd, textpos, 323 text_len, 0); 324 if (result >= 0) { 325 result = target_pread(bprm->src.fd, datapos, 326 data_len + (relocs * sizeof(abi_ulong)), 327 ntohl(hdr->data_start)); 328 } 329 if (result < 0) { 330 fprintf(stderr, "Unable to read code+data+bss\n"); 331 return result; 332 } 333 } 334 335 DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n", 336 (int)textpos, 0x00ffffff&ntohl(hdr->entry), 337 ntohl(hdr->data_start)); 338 339 /* The main program needs a little extra setup in the task structure */ 340 start_code = textpos + sizeof (struct flat_hdr); 341 342 DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", 343 id ? "Lib" : "Load", bprm->filename, 344 (int) start_code, (int) (textpos + text_len), 345 (int) datapos, 346 (int) (datapos + data_len), 347 (int) (datapos + data_len), 348 (int) (((datapos + data_len + bss_len) + 3) & ~3)); 349 350 text_len -= sizeof(struct flat_hdr); /* the real code len */ 351 352 /* Store the current module values into the global library structure */ 353 libinfo[id].start_code = start_code; 354 libinfo[id].start_data = datapos; 355 libinfo[id].end_data = datapos + data_len; 356 libinfo[id].start_brk = datapos + data_len + bss_len; 357 libinfo[id].text_len = text_len; 358 libinfo[id].loaded = 1; 359 libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; 360 libinfo[id].build_date = ntohl(hdr->build_date); 361 362 /* 363 * We just load the allocations into some temporary memory to 364 * help simplify all this mumbo jumbo 365 * 366 * We've got two different sections of relocation entries. 367 * The first is the GOT which resides at the beginning of the data segment 368 * and is terminated with a -1. This one can be relocated in place. 369 * The second is the extra relocation entries tacked after the image's 370 * data segment. These require a little more processing as the entry is 371 * really an offset into the image which contains an offset into the 372 * image. 373 */ 374 if (flags & FLAT_FLAG_GOTPIC) { 375 rp = datapos; 376 while (1) { 377 abi_ulong addr; 378 if (get_user_ual(addr, rp)) 379 return -EFAULT; 380 if (addr == -1) 381 break; 382 if (addr) { 383 addr = calc_reloc(addr, libinfo, id, 0); 384 if (addr == RELOC_FAILED) 385 return -ENOEXEC; 386 if (put_user_ual(addr, rp)) 387 return -EFAULT; 388 } 389 rp += sizeof(abi_ulong); 390 } 391 } 392 393 /* 394 * Now run through the relocation entries. 395 * We've got to be careful here as C++ produces relocatable zero 396 * entries in the constructor and destructor tables which are then 397 * tested for being not zero (which will always occur unless we're 398 * based from address zero). This causes an endless loop as __start 399 * is at zero. The solution used is to not relocate zero addresses. 400 * This has the negative side effect of not allowing a global data 401 * reference to be statically initialised to _stext (I've moved 402 * __start to address 4 so that is okay). 403 */ 404 if (rev > OLD_FLAT_VERSION) { 405 abi_ulong persistent = 0; 406 for (i = 0; i < relocs; i++) { 407 abi_ulong addr, relval; 408 409 /* Get the address of the pointer to be 410 relocated (of course, the address has to be 411 relocated first). */ 412 if (get_user_ual(relval, reloc + i * sizeof(abi_ulong))) 413 return -EFAULT; 414 relval = ntohl(relval); 415 if (flat_set_persistent(relval, &persistent)) 416 continue; 417 addr = flat_get_relocate_addr(relval); 418 rp = calc_reloc(addr, libinfo, id, 1); 419 if (rp == RELOC_FAILED) 420 return -ENOEXEC; 421 422 /* Get the pointer's value. */ 423 if (get_user_ual(addr, rp)) 424 return -EFAULT; 425 addr = flat_get_addr_from_rp(addr, relval, flags, &persistent); 426 if (addr != 0) { 427 /* 428 * Do the relocation. PIC relocs in the data section are 429 * already in target order 430 */ 431 if ((flags & FLAT_FLAG_GOTPIC) == 0) 432 addr = ntohl(addr); 433 addr = calc_reloc(addr, libinfo, id, 0); 434 if (addr == RELOC_FAILED) 435 return -ENOEXEC; 436 437 /* Write back the relocated pointer. */ 438 if (flat_put_addr_at_rp(rp, addr, relval)) 439 return -EFAULT; 440 } 441 } 442 } else { 443 for (i = 0; i < relocs; i++) { 444 abi_ulong relval; 445 if (get_user_ual(relval, reloc + i * sizeof(abi_ulong))) 446 return -EFAULT; 447 old_reloc(&libinfo[0], relval); 448 } 449 } 450 451 /* zero the BSS. */ 452 memset(g2h_untagged(datapos + data_len), 0, bss_len); 453 454 return 0; 455 } 456 457 458 /****************************************************************************/ 459 int load_flt_binary(struct linux_binprm *bprm, struct image_info *info) 460 { 461 struct lib_info libinfo[MAX_SHARED_LIBS]; 462 abi_ulong p; 463 abi_ulong stack_len; 464 abi_ulong start_addr; 465 abi_ulong sp; 466 int res; 467 int i, j; 468 469 memset(libinfo, 0, sizeof(libinfo)); 470 /* 471 * We have to add the size of our arguments to our stack size 472 * otherwise it's too easy for users to create stack overflows 473 * by passing in a huge argument list. And yes, we have to be 474 * pedantic and include space for the argv/envp array as it may have 475 * a lot of entries. 476 */ 477 stack_len = 0; 478 for (i = 0; i < bprm->argc; ++i) { 479 /* the argv strings */ 480 stack_len += strlen(bprm->argv[i]); 481 } 482 for (i = 0; i < bprm->envc; ++i) { 483 /* the envp strings */ 484 stack_len += strlen(bprm->envp[i]); 485 } 486 stack_len += (bprm->argc + 1) * 4; /* the argv array */ 487 stack_len += (bprm->envc + 1) * 4; /* the envp array */ 488 489 490 mmap_lock(); 491 res = load_flat_file(bprm, libinfo, 0, &stack_len); 492 mmap_unlock(); 493 494 if (is_error(res)) { 495 return res; 496 } 497 498 /* Update data segment pointers for all libraries */ 499 for (i=0; i<MAX_SHARED_LIBS; i++) { 500 if (libinfo[i].loaded) { 501 abi_ulong seg; 502 seg = libinfo[i].start_data; 503 for (j=0; j<MAX_SHARED_LIBS; j++) { 504 seg -= 4; 505 /* FIXME - handle put_user() failures */ 506 if (put_user_ual(libinfo[j].loaded 507 ? libinfo[j].start_data 508 : UNLOADED_LIB, 509 seg)) 510 return -EFAULT; 511 } 512 } 513 } 514 515 p = ((libinfo[0].start_brk + stack_len + 3) & ~3) - 4; 516 DBG_FLT("p=%x\n", (int)p); 517 518 /* Copy argv/envp. */ 519 p = copy_strings(p, bprm->envc, bprm->envp); 520 p = copy_strings(p, bprm->argc, bprm->argv); 521 /* Align stack. */ 522 sp = p & ~(abi_ulong)(sizeof(abi_ulong) - 1); 523 /* Enforce final stack alignment of 16 bytes. This is sufficient 524 for all current targets, and excess alignment is harmless. */ 525 stack_len = bprm->envc + bprm->argc + 2; 526 stack_len += flat_argvp_envp_on_stack() ? 2 : 0; /* argv, argp */ 527 stack_len += 1; /* argc */ 528 stack_len *= sizeof(abi_ulong); 529 sp -= (sp - stack_len) & 15; 530 sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 531 flat_argvp_envp_on_stack()); 532 533 /* Fake some return addresses to ensure the call chain will 534 * initialise library in order for us. We are required to call 535 * lib 1 first, then 2, ... and finally the main program (id 0). 536 */ 537 start_addr = libinfo[0].entry; 538 539 /* Stash our initial stack pointer into the mm structure */ 540 info->start_code = libinfo[0].start_code; 541 info->end_code = libinfo[0].start_code + libinfo[0].text_len; 542 info->start_data = libinfo[0].start_data; 543 info->end_data = libinfo[0].end_data; 544 info->brk = libinfo[0].start_brk; 545 info->start_stack = sp; 546 info->stack_limit = libinfo[0].start_brk; 547 info->entry = start_addr; 548 info->code_offset = info->start_code; 549 info->data_offset = info->start_data - libinfo[0].text_len; 550 551 DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n", 552 (int)info->entry, (int)info->start_stack); 553 554 return 0; 555 } 556