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