| .. | .. |
|---|
| 42 | 42 | #include <asm/unaligned.h> |
|---|
| 43 | 43 | #include <asm/cacheflush.h> |
|---|
| 44 | 44 | #include <asm/page.h> |
|---|
| 45 | +#include <asm/flat.h> |
|---|
| 46 | + |
|---|
| 47 | +#ifndef flat_get_relocate_addr |
|---|
| 48 | +#define flat_get_relocate_addr(rel) (rel) |
|---|
| 49 | +#endif |
|---|
| 45 | 50 | |
|---|
| 46 | 51 | /****************************************************************************/ |
|---|
| 47 | 52 | |
|---|
| .. | .. |
|---|
| 62 | 67 | |
|---|
| 63 | 68 | #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ |
|---|
| 64 | 69 | #define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ |
|---|
| 70 | + |
|---|
| 71 | +#ifdef CONFIG_BINFMT_SHARED_FLAT |
|---|
| 72 | +#define MAX_SHARED_LIBS (4) |
|---|
| 73 | +#else |
|---|
| 74 | +#define MAX_SHARED_LIBS (1) |
|---|
| 75 | +#endif |
|---|
| 65 | 76 | |
|---|
| 66 | 77 | struct lib_info { |
|---|
| 67 | 78 | struct { |
|---|
| .. | .. |
|---|
| 120 | 131 | |
|---|
| 121 | 132 | sp -= bprm->envc + 1; |
|---|
| 122 | 133 | sp -= bprm->argc + 1; |
|---|
| 123 | | - sp -= flat_argvp_envp_on_stack() ? 2 : 0; |
|---|
| 134 | + if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) |
|---|
| 135 | + sp -= 2; /* argvp + envp */ |
|---|
| 124 | 136 | sp -= 1; /* &argc */ |
|---|
| 125 | 137 | |
|---|
| 126 | 138 | current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN; |
|---|
| 127 | 139 | sp = (unsigned long __user *)current->mm->start_stack; |
|---|
| 128 | 140 | |
|---|
| 129 | | - __put_user(bprm->argc, sp++); |
|---|
| 130 | | - if (flat_argvp_envp_on_stack()) { |
|---|
| 141 | + if (put_user(bprm->argc, sp++)) |
|---|
| 142 | + return -EFAULT; |
|---|
| 143 | + if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) { |
|---|
| 131 | 144 | unsigned long argv, envp; |
|---|
| 132 | 145 | argv = (unsigned long)(sp + 2); |
|---|
| 133 | 146 | envp = (unsigned long)(sp + 2 + bprm->argc + 1); |
|---|
| 134 | | - __put_user(argv, sp++); |
|---|
| 135 | | - __put_user(envp, sp++); |
|---|
| 147 | + if (put_user(argv, sp++) || put_user(envp, sp++)) |
|---|
| 148 | + return -EFAULT; |
|---|
| 136 | 149 | } |
|---|
| 137 | 150 | |
|---|
| 138 | 151 | current->mm->arg_start = (unsigned long)p; |
|---|
| 139 | 152 | for (i = bprm->argc; i > 0; i--) { |
|---|
| 140 | | - __put_user((unsigned long)p, sp++); |
|---|
| 153 | + if (put_user((unsigned long)p, sp++)) |
|---|
| 154 | + return -EFAULT; |
|---|
| 141 | 155 | len = strnlen_user(p, MAX_ARG_STRLEN); |
|---|
| 142 | 156 | if (!len || len > MAX_ARG_STRLEN) |
|---|
| 143 | 157 | return -EINVAL; |
|---|
| 144 | 158 | p += len; |
|---|
| 145 | 159 | } |
|---|
| 146 | | - __put_user(0, sp++); |
|---|
| 160 | + if (put_user(0, sp++)) |
|---|
| 161 | + return -EFAULT; |
|---|
| 147 | 162 | current->mm->arg_end = (unsigned long)p; |
|---|
| 148 | 163 | |
|---|
| 149 | 164 | current->mm->env_start = (unsigned long) p; |
|---|
| 150 | 165 | for (i = bprm->envc; i > 0; i--) { |
|---|
| 151 | | - __put_user((unsigned long)p, sp++); |
|---|
| 166 | + if (put_user((unsigned long)p, sp++)) |
|---|
| 167 | + return -EFAULT; |
|---|
| 152 | 168 | len = strnlen_user(p, MAX_ARG_STRLEN); |
|---|
| 153 | 169 | if (!len || len > MAX_ARG_STRLEN) |
|---|
| 154 | 170 | return -EINVAL; |
|---|
| 155 | 171 | p += len; |
|---|
| 156 | 172 | } |
|---|
| 157 | | - __put_user(0, sp++); |
|---|
| 173 | + if (put_user(0, sp++)) |
|---|
| 174 | + return -EFAULT; |
|---|
| 158 | 175 | current->mm->env_end = (unsigned long)p; |
|---|
| 159 | 176 | |
|---|
| 160 | 177 | return 0; |
|---|
| .. | .. |
|---|
| 345 | 362 | start_code = p->lib_list[id].start_code; |
|---|
| 346 | 363 | text_len = p->lib_list[id].text_len; |
|---|
| 347 | 364 | |
|---|
| 348 | | - if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { |
|---|
| 365 | + if (r > start_brk - start_data + text_len) { |
|---|
| 349 | 366 | pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)", |
|---|
| 350 | 367 | r, start_brk-start_data+text_len, text_len); |
|---|
| 351 | 368 | goto failed; |
|---|
| .. | .. |
|---|
| 368 | 385 | |
|---|
| 369 | 386 | /****************************************************************************/ |
|---|
| 370 | 387 | |
|---|
| 388 | +#ifdef CONFIG_BINFMT_FLAT_OLD |
|---|
| 371 | 389 | static void old_reloc(unsigned long rl) |
|---|
| 372 | 390 | { |
|---|
| 373 | 391 | static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; |
|---|
| .. | .. |
|---|
| 405 | 423 | |
|---|
| 406 | 424 | pr_debug("Relocation became %lx\n", val); |
|---|
| 407 | 425 | } |
|---|
| 426 | +#endif /* CONFIG_BINFMT_FLAT_OLD */ |
|---|
| 408 | 427 | |
|---|
| 409 | 428 | /****************************************************************************/ |
|---|
| 429 | + |
|---|
| 430 | +static inline u32 __user *skip_got_header(u32 __user *rp) |
|---|
| 431 | +{ |
|---|
| 432 | + if (IS_ENABLED(CONFIG_RISCV)) { |
|---|
| 433 | + /* |
|---|
| 434 | + * RISC-V has a 16 byte GOT PLT header for elf64-riscv |
|---|
| 435 | + * and 8 byte GOT PLT header for elf32-riscv. |
|---|
| 436 | + * Skip the whole GOT PLT header, since it is reserved |
|---|
| 437 | + * for the dynamic linker (ld.so). |
|---|
| 438 | + */ |
|---|
| 439 | + u32 rp_val0, rp_val1; |
|---|
| 440 | + |
|---|
| 441 | + if (get_user(rp_val0, rp)) |
|---|
| 442 | + return rp; |
|---|
| 443 | + if (get_user(rp_val1, rp + 1)) |
|---|
| 444 | + return rp; |
|---|
| 445 | + |
|---|
| 446 | + if (rp_val0 == 0xffffffff && rp_val1 == 0xffffffff) |
|---|
| 447 | + rp += 4; |
|---|
| 448 | + else if (rp_val0 == 0xffffffff) |
|---|
| 449 | + rp += 2; |
|---|
| 450 | + } |
|---|
| 451 | + return rp; |
|---|
| 452 | +} |
|---|
| 410 | 453 | |
|---|
| 411 | 454 | static int load_flat_file(struct linux_binprm *bprm, |
|---|
| 412 | 455 | struct lib_info *libinfo, int id, unsigned long *extra_stack) |
|---|
| .. | .. |
|---|
| 415 | 458 | unsigned long textpos, datapos, realdatastart; |
|---|
| 416 | 459 | u32 text_len, data_len, bss_len, stack_len, full_data, flags; |
|---|
| 417 | 460 | unsigned long len, memp, memp_size, extra, rlim; |
|---|
| 418 | | - u32 __user *reloc, *rp; |
|---|
| 419 | | - struct inode *inode; |
|---|
| 461 | + __be32 __user *reloc; |
|---|
| 462 | + u32 __user *rp; |
|---|
| 420 | 463 | int i, rev, relocs; |
|---|
| 421 | 464 | loff_t fpos; |
|---|
| 422 | 465 | unsigned long start_code, end_code; |
|---|
| .. | .. |
|---|
| 424 | 467 | int ret; |
|---|
| 425 | 468 | |
|---|
| 426 | 469 | hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ |
|---|
| 427 | | - inode = file_inode(bprm->file); |
|---|
| 428 | 470 | |
|---|
| 429 | 471 | text_len = ntohl(hdr->data_start); |
|---|
| 430 | 472 | data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); |
|---|
| .. | .. |
|---|
| 454 | 496 | if (flags & FLAT_FLAG_KTRACE) |
|---|
| 455 | 497 | pr_info("Loading file: %s\n", bprm->filename); |
|---|
| 456 | 498 | |
|---|
| 499 | +#ifdef CONFIG_BINFMT_FLAT_OLD |
|---|
| 457 | 500 | if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { |
|---|
| 458 | 501 | pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n", |
|---|
| 459 | 502 | rev, FLAT_VERSION, OLD_FLAT_VERSION); |
|---|
| .. | .. |
|---|
| 470 | 513 | } |
|---|
| 471 | 514 | |
|---|
| 472 | 515 | /* |
|---|
| 516 | + * fix up the flags for the older format, there were all kinds |
|---|
| 517 | + * of endian hacks, this only works for the simple cases |
|---|
| 518 | + */ |
|---|
| 519 | + if (rev == OLD_FLAT_VERSION && |
|---|
| 520 | + (flags || IS_ENABLED(CONFIG_BINFMT_FLAT_OLD_ALWAYS_RAM))) |
|---|
| 521 | + flags = FLAT_FLAG_RAM; |
|---|
| 522 | + |
|---|
| 523 | +#else /* CONFIG_BINFMT_FLAT_OLD */ |
|---|
| 524 | + if (rev != FLAT_VERSION) { |
|---|
| 525 | + pr_err("bad flat file version 0x%x (supported 0x%lx)\n", |
|---|
| 526 | + rev, FLAT_VERSION); |
|---|
| 527 | + ret = -ENOEXEC; |
|---|
| 528 | + goto err; |
|---|
| 529 | + } |
|---|
| 530 | +#endif /* !CONFIG_BINFMT_FLAT_OLD */ |
|---|
| 531 | + |
|---|
| 532 | + /* |
|---|
| 473 | 533 | * Make sure the header params are sane. |
|---|
| 474 | 534 | * 28 bits (256 MB) is way more than reasonable in this case. |
|---|
| 475 | 535 | * If some top bits are set we have probable binary corruption. |
|---|
| .. | .. |
|---|
| 479 | 539 | ret = -ENOEXEC; |
|---|
| 480 | 540 | goto err; |
|---|
| 481 | 541 | } |
|---|
| 482 | | - |
|---|
| 483 | | - /* |
|---|
| 484 | | - * fix up the flags for the older format, there were all kinds |
|---|
| 485 | | - * of endian hacks, this only works for the simple cases |
|---|
| 486 | | - */ |
|---|
| 487 | | - if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags)) |
|---|
| 488 | | - flags = FLAT_FLAG_RAM; |
|---|
| 489 | 542 | |
|---|
| 490 | 543 | #ifndef CONFIG_BINFMT_ZFLAT |
|---|
| 491 | 544 | if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { |
|---|
| .. | .. |
|---|
| 510 | 563 | |
|---|
| 511 | 564 | /* Flush all traces of the currently running executable */ |
|---|
| 512 | 565 | if (id == 0) { |
|---|
| 513 | | - ret = flush_old_exec(bprm); |
|---|
| 566 | + ret = begin_new_exec(bprm); |
|---|
| 514 | 567 | if (ret) |
|---|
| 515 | 568 | goto err; |
|---|
| 516 | 569 | |
|---|
| .. | .. |
|---|
| 587 | 640 | goto err; |
|---|
| 588 | 641 | } |
|---|
| 589 | 642 | |
|---|
| 590 | | - reloc = (u32 __user *) |
|---|
| 643 | + reloc = (__be32 __user *) |
|---|
| 591 | 644 | (datapos + (ntohl(hdr->reloc_start) - text_len)); |
|---|
| 592 | 645 | memp = realdatastart; |
|---|
| 593 | 646 | memp_size = len; |
|---|
| .. | .. |
|---|
| 612 | 665 | MAX_SHARED_LIBS * sizeof(u32), |
|---|
| 613 | 666 | FLAT_DATA_ALIGN); |
|---|
| 614 | 667 | |
|---|
| 615 | | - reloc = (u32 __user *) |
|---|
| 668 | + reloc = (__be32 __user *) |
|---|
| 616 | 669 | (datapos + (ntohl(hdr->reloc_start) - text_len)); |
|---|
| 617 | 670 | memp = textpos; |
|---|
| 618 | 671 | memp_size = len; |
|---|
| .. | .. |
|---|
| 745 | 798 | * image. |
|---|
| 746 | 799 | */ |
|---|
| 747 | 800 | if (flags & FLAT_FLAG_GOTPIC) { |
|---|
| 748 | | - for (rp = (u32 __user *)datapos; ; rp++) { |
|---|
| 801 | + rp = skip_got_header((u32 __user *) datapos); |
|---|
| 802 | + for (; ; rp++) { |
|---|
| 749 | 803 | u32 addr, rp_val; |
|---|
| 750 | 804 | if (get_user(rp_val, rp)) |
|---|
| 751 | 805 | return -EFAULT; |
|---|
| .. | .. |
|---|
| 775 | 829 | * __start to address 4 so that is okay). |
|---|
| 776 | 830 | */ |
|---|
| 777 | 831 | if (rev > OLD_FLAT_VERSION) { |
|---|
| 778 | | - u32 __maybe_unused persistent = 0; |
|---|
| 779 | 832 | for (i = 0; i < relocs; i++) { |
|---|
| 780 | 833 | u32 addr, relval; |
|---|
| 834 | + __be32 tmp; |
|---|
| 781 | 835 | |
|---|
| 782 | 836 | /* |
|---|
| 783 | 837 | * Get the address of the pointer to be |
|---|
| 784 | 838 | * relocated (of course, the address has to be |
|---|
| 785 | 839 | * relocated first). |
|---|
| 786 | 840 | */ |
|---|
| 787 | | - if (get_user(relval, reloc + i)) |
|---|
| 841 | + if (get_user(tmp, reloc + i)) |
|---|
| 788 | 842 | return -EFAULT; |
|---|
| 789 | | - relval = ntohl(relval); |
|---|
| 790 | | - if (flat_set_persistent(relval, &persistent)) |
|---|
| 791 | | - continue; |
|---|
| 843 | + relval = ntohl(tmp); |
|---|
| 792 | 844 | addr = flat_get_relocate_addr(relval); |
|---|
| 793 | 845 | rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1); |
|---|
| 794 | 846 | if (rp == (u32 __user *)RELOC_FAILED) { |
|---|
| .. | .. |
|---|
| 797 | 849 | } |
|---|
| 798 | 850 | |
|---|
| 799 | 851 | /* Get the pointer's value. */ |
|---|
| 800 | | - ret = flat_get_addr_from_rp(rp, relval, flags, |
|---|
| 801 | | - &addr, &persistent); |
|---|
| 852 | + ret = flat_get_addr_from_rp(rp, relval, flags, &addr); |
|---|
| 802 | 853 | if (unlikely(ret)) |
|---|
| 803 | 854 | goto err; |
|---|
| 804 | 855 | |
|---|
| .. | .. |
|---|
| 807 | 858 | * Do the relocation. PIC relocs in the data section are |
|---|
| 808 | 859 | * already in target order |
|---|
| 809 | 860 | */ |
|---|
| 810 | | - if ((flags & FLAT_FLAG_GOTPIC) == 0) |
|---|
| 811 | | - addr = ntohl(addr); |
|---|
| 861 | + if ((flags & FLAT_FLAG_GOTPIC) == 0) { |
|---|
| 862 | + /* |
|---|
| 863 | + * Meh, the same value can have a different |
|---|
| 864 | + * byte order based on a flag.. |
|---|
| 865 | + */ |
|---|
| 866 | + addr = ntohl((__force __be32)addr); |
|---|
| 867 | + } |
|---|
| 812 | 868 | addr = calc_reloc(addr, libinfo, id, 0); |
|---|
| 813 | 869 | if (addr == RELOC_FAILED) { |
|---|
| 814 | 870 | ret = -ENOEXEC; |
|---|
| .. | .. |
|---|
| 821 | 877 | goto err; |
|---|
| 822 | 878 | } |
|---|
| 823 | 879 | } |
|---|
| 880 | +#ifdef CONFIG_BINFMT_FLAT_OLD |
|---|
| 824 | 881 | } else { |
|---|
| 825 | 882 | for (i = 0; i < relocs; i++) { |
|---|
| 826 | | - u32 relval; |
|---|
| 883 | + __be32 relval; |
|---|
| 827 | 884 | if (get_user(relval, reloc + i)) |
|---|
| 828 | 885 | return -EFAULT; |
|---|
| 829 | | - relval = ntohl(relval); |
|---|
| 830 | | - old_reloc(relval); |
|---|
| 886 | + old_reloc(ntohl(relval)); |
|---|
| 831 | 887 | } |
|---|
| 888 | +#endif /* CONFIG_BINFMT_FLAT_OLD */ |
|---|
| 832 | 889 | } |
|---|
| 833 | 890 | |
|---|
| 834 | | - flush_icache_range(start_code, end_code); |
|---|
| 891 | + flush_icache_user_range(start_code, end_code); |
|---|
| 835 | 892 | |
|---|
| 836 | 893 | /* zero the BSS, BRK and stack areas */ |
|---|
| 837 | 894 | if (clear_user((void __user *)(datapos + data_len), bss_len + |
|---|
| .. | .. |
|---|
| 940 | 997 | } |
|---|
| 941 | 998 | } |
|---|
| 942 | 999 | |
|---|
| 943 | | - install_exec_creds(bprm); |
|---|
| 944 | | - |
|---|
| 945 | 1000 | set_binfmt(&flat_format); |
|---|
| 946 | 1001 | |
|---|
| 947 | 1002 | #ifdef CONFIG_MMU |
|---|
| .. | .. |
|---|
| 975 | 1030 | unsigned long __user *sp; |
|---|
| 976 | 1031 | current->mm->start_stack -= sizeof(unsigned long); |
|---|
| 977 | 1032 | sp = (unsigned long __user *)current->mm->start_stack; |
|---|
| 978 | | - __put_user(start_addr, sp); |
|---|
| 1033 | + if (put_user(start_addr, sp)) |
|---|
| 1034 | + return -EFAULT; |
|---|
| 979 | 1035 | start_addr = libinfo.lib_list[i].entry; |
|---|
| 980 | 1036 | } |
|---|
| 981 | 1037 | } |
|---|