| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 /* | 7 /* |
| 8 * NaCl Simple/secure ELF loader (NaCl SEL). | 8 * NaCl Simple/secure ELF loader (NaCl SEL). |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 char const *const *envv) { | 648 char const *const *envv) { |
| 649 /* | 649 /* |
| 650 * Compute size of string tables for argv and envv | 650 * Compute size of string tables for argv and envv |
| 651 */ | 651 */ |
| 652 int retval; | 652 int retval; |
| 653 int envc; | 653 int envc; |
| 654 size_t size; | 654 size_t size; |
| 655 int auxv_entries; | 655 int auxv_entries; |
| 656 size_t ptr_tbl_size; | 656 size_t ptr_tbl_size; |
| 657 int i; | 657 int i; |
| 658 char *p; | 658 uint32_t *p; |
| 659 char *strp; | 659 char *strp; |
| 660 size_t *argv_len; | 660 size_t *argv_len; |
| 661 size_t *envv_len; | 661 size_t *envv_len; |
| 662 struct NaClAppThread *natp; | 662 struct NaClAppThread *natp; |
| 663 uintptr_t stack_ptr; | 663 uintptr_t stack_ptr; |
| 664 | 664 |
| 665 retval = 0; /* fail */ | 665 retval = 0; /* fail */ |
| 666 CHECK(argc > 0); | 666 CHECK(argc > 0); |
| 667 CHECK(NULL != argv); | 667 CHECK(NULL != argv); |
| 668 | 668 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 713 } | 713 } |
| 714 for (i = 0; i < envc; ++i) { | 714 for (i = 0; i < envc; ++i) { |
| 715 envv_len[i] = strlen(envv[i]) + 1; | 715 envv_len[i] = strlen(envv[i]) + 1; |
| 716 size += envv_len[i]; | 716 size += envv_len[i]; |
| 717 } | 717 } |
| 718 | 718 |
| 719 /* | 719 /* |
| 720 * NaCl modules are ILP32, so the argv, envv pointers, as well as | 720 * NaCl modules are ILP32, so the argv, envv pointers, as well as |
| 721 * the terminating NULL pointers at the end of the argv/envv tables, | 721 * the terminating NULL pointers at the end of the argv/envv tables, |
| 722 * are 32-bit values. We also have the auxv to take into account. | 722 * are 32-bit values. We also have the auxv to take into account. |
| 723 * Note that on nacl64, argc is popped, and is an 8-byte value! | |
| 724 * | 723 * |
| 725 * The argv and envv pointer tables came from trusted code and is | 724 * The argv and envv pointer tables came from trusted code and is |
| 726 * part of memory. Thus, by the same argument above, adding in | 725 * part of memory. Thus, by the same argument above, adding in |
| 727 * "ptr_tbl_size" cannot possibly overflow the "size" variable since | 726 * "ptr_tbl_size" cannot possibly overflow the "size" variable since |
| 728 * it is a size_t object. However, the extra pointers for auxv and | 727 * it is a size_t object. However, the extra pointers for auxv and |
| 729 * the space for argv could cause an overflow. The fact that we | 728 * the space for argv could cause an overflow. The fact that we |
| 730 * used stack to get here etc means that ptr_tbl_size could not have | 729 * used stack to get here etc means that ptr_tbl_size could not have |
| 731 * overflowed. | 730 * overflowed. |
| 732 * | 731 * |
| 733 * NB: the underlying OS would have limited the amount of space used | 732 * NB: the underlying OS would have limited the amount of space used |
| 734 * for argv and envv -- on linux, it is ARG_MAX, or 128KB -- and | 733 * for argv and envv -- on linux, it is ARG_MAX, or 128KB -- and |
| 735 * hence the overflow check is for obvious auditability rather than | 734 * hence the overflow check is for obvious auditability rather than |
| 736 * for correctness. | 735 * for correctness. |
| 737 */ | 736 */ |
| 738 auxv_entries = 1; | 737 auxv_entries = 1; |
| 739 if (0 != nap->user_entry_pt) { | 738 if (0 != nap->user_entry_pt) { |
| 740 auxv_entries++; | 739 auxv_entries++; |
| 741 } | 740 } |
| 742 ptr_tbl_size = (argc + envc + 2 + auxv_entries * 2) * sizeof(uint32_t) | 741 ptr_tbl_size = (((NACL_STACK_GETS_ARG ? 1 : 0) + |
| 743 + sizeof(nacl_reg_t); | 742 (3 + argc + 1 + envc + 1 + auxv_entries * 2)) * |
| 743 sizeof(uint32_t)); |
| 744 | 744 |
| 745 if (SIZE_T_MAX - size < ptr_tbl_size) { | 745 if (SIZE_T_MAX - size < ptr_tbl_size) { |
| 746 NaClLog(LOG_WARNING, | 746 NaClLog(LOG_WARNING, |
| 747 "NaClCreateMainThread: ptr_tbl_size cause size of" | 747 "NaClCreateMainThread: ptr_tbl_size cause size of" |
| 748 " argv / environment copy to overflow!?!\n"); | 748 " argv / environment copy to overflow!?!\n"); |
| 749 retval = 0; | 749 retval = 0; |
| 750 goto cleanup; | 750 goto cleanup; |
| 751 } | 751 } |
| 752 size += ptr_tbl_size; | 752 size += ptr_tbl_size; |
| 753 | 753 |
| 754 size = (size + NACL_STACK_ALIGN_MASK) & ~NACL_STACK_ALIGN_MASK; | 754 size = (size + NACL_STACK_ALIGN_MASK) & ~NACL_STACK_ALIGN_MASK; |
| 755 | 755 |
| 756 if (size > nap->stack_size) { | 756 if (size > nap->stack_size) { |
| 757 retval = 0; | 757 retval = 0; |
| 758 goto cleanup; | 758 goto cleanup; |
| 759 } | 759 } |
| 760 | 760 |
| 761 /* write strings and char * arrays to stack */ | 761 /* write strings and char * arrays to stack */ |
| 762 stack_ptr = (nap->mem_start + ((uintptr_t) 1U << nap->addr_bits) - size); | 762 stack_ptr = (nap->mem_start + ((uintptr_t) 1U << nap->addr_bits) - size); |
| 763 | 763 |
| 764 NaClLog(2, "setting stack to : %016"NACL_PRIxPTR"\n", stack_ptr); | 764 NaClLog(2, "setting stack to : %016"NACL_PRIxPTR"\n", stack_ptr); |
| 765 | 765 |
| 766 VCHECK(0 == (stack_ptr & NACL_STACK_ALIGN_MASK), | 766 VCHECK(0 == (stack_ptr & NACL_STACK_ALIGN_MASK), |
| 767 ("stack_ptr not aligned: %016"NACL_PRIxPTR"\n", stack_ptr)); | 767 ("stack_ptr not aligned: %016"NACL_PRIxPTR"\n", stack_ptr)); |
| 768 | 768 |
| 769 p = (char *) stack_ptr; | 769 p = (uint32_t *) stack_ptr; |
| 770 strp = p + ptr_tbl_size; | 770 strp = (char *) stack_ptr + ptr_tbl_size; |
| 771 | 771 |
| 772 #define BLAT(t, v) do { \ | 772 /* |
| 773 *(t *) p = (t) v; p += sizeof(t); \ | 773 * For x86-32, we push an initial argument that is the address of |
| 774 } while (0); | 774 * the main argument block. For other machines, this is passed |
| 775 * in a register and that's set in NaClStartThreadInApp. |
| 776 */ |
| 777 if (NACL_STACK_GETS_ARG) { |
| 778 uint32_t *argloc = p++; |
| 779 *argloc = (uint32_t) NaClSysToUser(nap, (uintptr_t) p); |
| 780 } |
| 775 | 781 |
| 776 BLAT(nacl_reg_t, argc); | 782 *p++ = 0; /* Cleanup function pointer, always NULL. */ |
| 783 *p++ = envc; |
| 784 *p++ = argc; |
| 777 | 785 |
| 778 for (i = 0; i < argc; ++i) { | 786 for (i = 0; i < argc; ++i) { |
| 779 BLAT(uint32_t, NaClSysToUser(nap, (uintptr_t) strp)); | 787 *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp); |
| 780 NaClLog(2, "copying arg %d %p -> %p\n", | 788 NaClLog(2, "copying arg %d %p -> %p\n", |
| 781 i, argv[i], strp); | 789 i, argv[i], strp); |
| 782 strcpy(strp, argv[i]); | 790 strcpy(strp, argv[i]); |
| 783 strp += argv_len[i]; | 791 strp += argv_len[i]; |
| 784 } | 792 } |
| 785 BLAT(uint32_t, 0); | 793 *p++ = 0; /* argv[argc] is NULL. */ |
| 786 | 794 |
| 787 for (i = 0; i < envc; ++i) { | 795 for (i = 0; i < envc; ++i) { |
| 788 BLAT(uint32_t, NaClSysToUser(nap, (uintptr_t) strp)); | 796 *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp); |
| 789 NaClLog(2, "copying env %d %p -> %p\n", | 797 NaClLog(2, "copying env %d %p -> %p\n", |
| 790 i, envv[i], strp); | 798 i, envv[i], strp); |
| 791 strcpy(strp, envv[i]); | 799 strcpy(strp, envv[i]); |
| 792 strp += envv_len[i]; | 800 strp += envv_len[i]; |
| 793 } | 801 } |
| 794 BLAT(uint32_t, 0); | 802 *p++ = 0; /* envp[envc] is NULL. */ |
| 803 |
| 795 /* Push an auxv */ | 804 /* Push an auxv */ |
| 796 if (0 != nap->user_entry_pt) { | 805 if (0 != nap->user_entry_pt) { |
| 797 BLAT(uint32_t, AT_ENTRY); | 806 *p++ = AT_ENTRY; |
| 798 BLAT(uint32_t, nap->user_entry_pt); | 807 *p++ = (uint32_t) nap->user_entry_pt; |
| 799 } | 808 } |
| 800 BLAT(uint32_t, AT_NULL); | 809 *p++ = AT_NULL; |
| 801 BLAT(uint32_t, 0); | 810 *p++ = 0; |
| 802 #undef BLAT | 811 |
| 803 CHECK(p == (char *) stack_ptr + ptr_tbl_size); | 812 CHECK((char *) p == (char *) stack_ptr + ptr_tbl_size); |
| 804 | 813 |
| 805 /* now actually spawn the thread */ | 814 /* now actually spawn the thread */ |
| 806 natp = malloc(sizeof *natp); | 815 natp = malloc(sizeof *natp); |
| 807 if (!natp) { | 816 if (!natp) { |
| 808 goto cleanup; | 817 goto cleanup; |
| 809 } | 818 } |
| 810 | 819 |
| 811 /* We are ready to distinguish crashes in trusted and untrusted code. */ | 820 /* We are ready to distinguish crashes in trusted and untrusted code. */ |
| 812 NaClSignalRegisterApp(nap); | 821 NaClSignalRegisterApp(nap); |
| 813 | 822 |
| 814 /* NaClApp initialization is completed, call OOP debugger hook. */ | 823 /* NaClApp initialization is completed, call OOP debugger hook. */ |
| 815 NaClOopDebuggerAppCreateHook(nap); | 824 NaClOopDebuggerAppCreateHook(nap); |
| 816 | 825 |
| 817 NaClXMutexLock(&nap->mu); | 826 NaClXMutexLock(&nap->mu); |
| 818 nap->running = 1; | 827 nap->running = 1; |
| 819 NaClXMutexUnlock(&nap->mu); | 828 NaClXMutexUnlock(&nap->mu); |
| 820 | 829 |
| 821 NaClVmHoleWaitToStartThread(nap); | 830 NaClVmHoleWaitToStartThread(nap); |
| 822 | 831 |
| 832 /* |
| 833 * For x86, we adjust the stack pointer down to push a dummy return |
| 834 * address. This happens after the stack pointer alignment. |
| 835 */ |
| 836 stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN; |
| 837 memset((void *) stack_ptr, 0, NACL_STACK_PAD_BELOW_ALIGN); |
| 838 |
| 823 NaClLog(2, "system stack ptr : %016"NACL_PRIxPTR"\n", stack_ptr); | 839 NaClLog(2, "system stack ptr : %016"NACL_PRIxPTR"\n", stack_ptr); |
| 824 NaClLog(2, " user stack ptr : %016"NACL_PRIxPTR"\n", | 840 NaClLog(2, " user stack ptr : %016"NACL_PRIxPTR"\n", |
| 825 NaClSysToUserStackAddr(nap, stack_ptr)); | 841 NaClSysToUserStackAddr(nap, stack_ptr)); |
| 826 | 842 |
| 827 /* e_entry is user addr */ | 843 /* e_entry is user addr */ |
| 828 if (!NaClAppThreadAllocSegCtor(natp, | 844 if (!NaClAppThreadAllocSegCtor(natp, |
| 829 nap, | 845 nap, |
| 830 nap->initial_entry_pt, | 846 nap->initial_entry_pt, |
| 831 NaClSysToUserStackAddr(nap, stack_ptr), | 847 NaClSysToUserStackAddr(nap, stack_ptr), |
| 832 NaClUserToSys(nap, nap->break_addr))) { | 848 NaClUserToSys(nap, nap->break_addr))) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 stack_ptr, | 926 stack_ptr, |
| 911 sys_tls)) { | 927 sys_tls)) { |
| 912 NaClLog(LOG_WARNING, | 928 NaClLog(LOG_WARNING, |
| 913 ("NaClCreateAdditionalThread: could not allocate thread index." | 929 ("NaClCreateAdditionalThread: could not allocate thread index." |
| 914 " Returning EAGAIN per POSIX specs.\n")); | 930 " Returning EAGAIN per POSIX specs.\n")); |
| 915 free(natp); | 931 free(natp); |
| 916 return -NACL_ABI_EAGAIN; | 932 return -NACL_ABI_EAGAIN; |
| 917 } | 933 } |
| 918 return 0; | 934 return 0; |
| 919 } | 935 } |
| OLD | NEW |