diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-05-02 19:52:17 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-07-03 18:44:02 -0400 |
commit | 468138d78510688fb5476f98d23f11ac6a63229a (patch) | |
tree | 5f235bc85343bf3f314201a1d281881625d67abe /fs/binfmt_flat.c | |
parent | 2ea659a9ef488125eb46da6eb571de5eae5c43f6 (diff) |
binfmt_flat: flat_{get,put}_addr_from_rp() should be able to fail
on MMU targets EFAULT is possible here. Make both return 0 or error,
passing what used to be the return value of flat_get_addr_from_rp()
by reference.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/binfmt_flat.c')
-rw-r--r-- | fs/binfmt_flat.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 2edcefc0a294..69ec23daa25e 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c | |||
@@ -422,9 +422,9 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
422 | { | 422 | { |
423 | struct flat_hdr *hdr; | 423 | struct flat_hdr *hdr; |
424 | unsigned long textpos, datapos, realdatastart; | 424 | unsigned long textpos, datapos, realdatastart; |
425 | unsigned long text_len, data_len, bss_len, stack_len, full_data, flags; | 425 | u32 text_len, data_len, bss_len, stack_len, full_data, flags; |
426 | unsigned long len, memp, memp_size, extra, rlim; | 426 | unsigned long len, memp, memp_size, extra, rlim; |
427 | unsigned long __user *reloc, *rp; | 427 | u32 __user *reloc, *rp; |
428 | struct inode *inode; | 428 | struct inode *inode; |
429 | int i, rev, relocs; | 429 | int i, rev, relocs; |
430 | loff_t fpos; | 430 | loff_t fpos; |
@@ -596,13 +596,13 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
596 | goto err; | 596 | goto err; |
597 | } | 597 | } |
598 | 598 | ||
599 | reloc = (unsigned long __user *) | 599 | reloc = (u32 __user *) |
600 | (datapos + (ntohl(hdr->reloc_start) - text_len)); | 600 | (datapos + (ntohl(hdr->reloc_start) - text_len)); |
601 | memp = realdatastart; | 601 | memp = realdatastart; |
602 | memp_size = len; | 602 | memp_size = len; |
603 | } else { | 603 | } else { |
604 | 604 | ||
605 | len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); | 605 | len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(u32); |
606 | len = PAGE_ALIGN(len); | 606 | len = PAGE_ALIGN(len); |
607 | textpos = vm_mmap(NULL, 0, len, | 607 | textpos = vm_mmap(NULL, 0, len, |
608 | PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); | 608 | PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); |
@@ -618,10 +618,10 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
618 | 618 | ||
619 | realdatastart = textpos + ntohl(hdr->data_start); | 619 | realdatastart = textpos + ntohl(hdr->data_start); |
620 | datapos = ALIGN(realdatastart + | 620 | datapos = ALIGN(realdatastart + |
621 | MAX_SHARED_LIBS * sizeof(unsigned long), | 621 | MAX_SHARED_LIBS * sizeof(u32), |
622 | FLAT_DATA_ALIGN); | 622 | FLAT_DATA_ALIGN); |
623 | 623 | ||
624 | reloc = (unsigned long __user *) | 624 | reloc = (u32 __user *) |
625 | (datapos + (ntohl(hdr->reloc_start) - text_len)); | 625 | (datapos + (ntohl(hdr->reloc_start) - text_len)); |
626 | memp = textpos; | 626 | memp = textpos; |
627 | memp_size = len; | 627 | memp_size = len; |
@@ -694,7 +694,7 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
694 | ret = result; | 694 | ret = result; |
695 | pr_err("Unable to read code+data+bss, errno %d\n", ret); | 695 | pr_err("Unable to read code+data+bss, errno %d\n", ret); |
696 | vm_munmap(textpos, text_len + data_len + extra + | 696 | vm_munmap(textpos, text_len + data_len + extra + |
697 | MAX_SHARED_LIBS * sizeof(unsigned long)); | 697 | MAX_SHARED_LIBS * sizeof(u32)); |
698 | goto err; | 698 | goto err; |
699 | } | 699 | } |
700 | } | 700 | } |
@@ -754,8 +754,8 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
754 | * image. | 754 | * image. |
755 | */ | 755 | */ |
756 | if (flags & FLAT_FLAG_GOTPIC) { | 756 | if (flags & FLAT_FLAG_GOTPIC) { |
757 | for (rp = (unsigned long __user *)datapos; ; rp++) { | 757 | for (rp = (u32 __user *)datapos; ; rp++) { |
758 | unsigned long addr, rp_val; | 758 | u32 addr, rp_val; |
759 | if (get_user(rp_val, rp)) | 759 | if (get_user(rp_val, rp)) |
760 | return -EFAULT; | 760 | return -EFAULT; |
761 | if (rp_val == 0xffffffff) | 761 | if (rp_val == 0xffffffff) |
@@ -784,9 +784,9 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
784 | * __start to address 4 so that is okay). | 784 | * __start to address 4 so that is okay). |
785 | */ | 785 | */ |
786 | if (rev > OLD_FLAT_VERSION) { | 786 | if (rev > OLD_FLAT_VERSION) { |
787 | unsigned long __maybe_unused persistent = 0; | 787 | u32 __maybe_unused persistent = 0; |
788 | for (i = 0; i < relocs; i++) { | 788 | for (i = 0; i < relocs; i++) { |
789 | unsigned long addr, relval; | 789 | u32 addr, relval; |
790 | 790 | ||
791 | /* | 791 | /* |
792 | * Get the address of the pointer to be | 792 | * Get the address of the pointer to be |
@@ -799,15 +799,18 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
799 | if (flat_set_persistent(relval, &persistent)) | 799 | if (flat_set_persistent(relval, &persistent)) |
800 | continue; | 800 | continue; |
801 | addr = flat_get_relocate_addr(relval); | 801 | addr = flat_get_relocate_addr(relval); |
802 | rp = (unsigned long __user *)calc_reloc(addr, libinfo, id, 1); | 802 | rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1); |
803 | if (rp == (unsigned long __user *)RELOC_FAILED) { | 803 | if (rp == (u32 __user *)RELOC_FAILED) { |
804 | ret = -ENOEXEC; | 804 | ret = -ENOEXEC; |
805 | goto err; | 805 | goto err; |
806 | } | 806 | } |
807 | 807 | ||
808 | /* Get the pointer's value. */ | 808 | /* Get the pointer's value. */ |
809 | addr = flat_get_addr_from_rp(rp, relval, flags, | 809 | ret = flat_get_addr_from_rp(rp, relval, flags, |
810 | &persistent); | 810 | &addr, &persistent); |
811 | if (unlikely(ret)) | ||
812 | goto err; | ||
813 | |||
811 | if (addr != 0) { | 814 | if (addr != 0) { |
812 | /* | 815 | /* |
813 | * Do the relocation. PIC relocs in the data section are | 816 | * Do the relocation. PIC relocs in the data section are |
@@ -822,12 +825,14 @@ static int load_flat_file(struct linux_binprm *bprm, | |||
822 | } | 825 | } |
823 | 826 | ||
824 | /* Write back the relocated pointer. */ | 827 | /* Write back the relocated pointer. */ |
825 | flat_put_addr_at_rp(rp, addr, relval); | 828 | ret = flat_put_addr_at_rp(rp, addr, relval); |
829 | if (unlikely(ret)) | ||
830 | goto err; | ||
826 | } | 831 | } |
827 | } | 832 | } |
828 | } else { | 833 | } else { |
829 | for (i = 0; i < relocs; i++) { | 834 | for (i = 0; i < relocs; i++) { |
830 | unsigned long relval; | 835 | u32 relval; |
831 | if (get_user(relval, reloc + i)) | 836 | if (get_user(relval, reloc + i)) |
832 | return -EFAULT; | 837 | return -EFAULT; |
833 | relval = ntohl(relval); | 838 | relval = ntohl(relval); |