.. | .. |
---|
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 | } |
---|