NORETURN void CreateSession(struct NaClApp *nap) { uintptr_t stack_ptr; assert(nap != NULL); /* set up user stack */ stack_ptr = nap->mem_start + ((uintptr_t)1U << nap->addr_bits); stack_ptr -= STACK_USER_DATA_SIZE; memset((void*)stack_ptr, 0, STACK_USER_DATA_SIZE); ((uint32_t*)stack_ptr)[4] = 1; ((uint32_t*)stack_ptr)[5] = 0xfffffff0; /* construct "nacl_user" global */ ThreadContextCtor(nacl_user, nap, nap->initial_entry_pt, stack_ptr, 0); nacl_user->sysret = nap->break_addr; nacl_user->prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt); nacl_user->new_prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt); /* initialize "nacl_sys" global */ nacl_sys->rbp = GetStackPtr(); nacl_sys->rsp = GetStackPtr(); /* pass control to the user side */ ZLOGS(LOG_DEBUG, "SESSION %d STARTED", nap->manifest->node); SwitchToApp(nap, nacl_user->new_prog_ctr); ZLOGFAIL(1, EFAULT, "the unreachable has been reached"); }
/* serve trap invoked from the untrusted code */ NORETURN void SyscallHook() { struct NaClApp *nap; struct ThreadContext *user; uintptr_t tramp_ret; nacl_reg_t user_ret; size_t sysnum; uintptr_t sp_user; uintptr_t sp_sys; /* restore trusted side environment */ nap = gnap; /* restore NaClApp object */ user = nacl_user; sp_user = GetThreadCtxSp(user); sp_sys = sp_user; /* * sp_sys points to the top of user stack where there is a retaddr to * trampoline slot */ tramp_ret = *(uintptr_t *)sp_sys; sysnum = (tramp_ret - (nap->mem_start + NACL_SYSCALL_START_ADDR)) >> NACL_SYSCALL_BLOCK_SHIFT; /* * getting user return address (the address where we need to return after * system call) from the user stack. (see stack layout above) */ user_ret = *(uintptr_t *)(sp_sys + NACL_USERRET_FIX); /* * Fix the user stack, throw away return addresses from the top of the stack. * After this fix, the first argument to a system call must be on the top of * the user stack (see user stack layout above) */ sp_sys += NACL_SYSARGS_FIX; sp_user += NACL_SYSCALLRET_FIX; SetThreadCtxSp(user, sp_user); /* fail if nacl syscall received */ ZLOGFAIL(sysnum != 0, EINVAL, "nacl syscall #%d received", sysnum); /* * syscall_args must point to the first argument of a system call. * System call arguments are placed on the untrusted user stack. */ nap->sysret = TrapHandler(nap, *(uint32_t*)sp_sys); /* * before switching back to user module, we need to make sure that the * user_ret is properly sandboxed. */ user_ret = (nacl_reg_t)NaClSandboxCodeAddr(nap, (uintptr_t)user_ret); /* d'b: give control to the user side */ SwitchToApp(nap, user_ret); ZLOGFAIL(1, EFAULT, "the unreachable has been reached"); }
/* * preconditions: * argc > 0, argc and argv table is consistent * envv may be NULL (this happens on MacOS/Cocoa * if envv is non-NULL it is 'consistent', null terminated etc. */ int NaClCreateMainThread(struct NaClApp *nap, int argc, char **argv, char const *const *envv) { /* * Compute size of string tables for argv and envv */ int retval; int envc; size_t size; int auxv_entries; size_t ptr_tbl_size; int i; uint32_t *p; char *strp; size_t *argv_len; size_t *envv_len; uintptr_t stack_ptr; retval = 0; /* fail */ CHECK(argc > 0); CHECK(NULL != argv); envc = 0; if (NULL != envv) { char const *const *pp; for (pp = envv; NULL != *pp; ++pp) { ++envc; } } envv_len = 0; argv_len = malloc(argc * sizeof argv_len[0]); envv_len = malloc(envc * sizeof envv_len[0]); if (NULL == argv_len) { goto cleanup; } if (NULL == envv_len && 0 != envc) { goto cleanup; } size = 0; /* * The following two loops cannot overflow. The reason for this is * that they are counting the number of bytes used to hold the * NUL-terminated strings that comprise the argv and envv tables. * If the entire address space consisted of just those strings, then * the size variable would overflow; however, since there's the code * space required to hold the code below (and we are not targetting * Harvard architecture machines), at least one page holds code, not * data. We are assuming that the caller is non-adversarial and the * code does not look like string data.... */ for (i = 0; i < argc; ++i) { argv_len[i] = strlen(argv[i]) + 1; size += argv_len[i]; } for (i = 0; i < envc; ++i) { envv_len[i] = strlen(envv[i]) + 1; size += envv_len[i]; } /* * NaCl modules are ILP32, so the argv, envv pointers, as well as * the terminating NULL pointers at the end of the argv/envv tables, * are 32-bit values. We also have the auxv to take into account. * * The argv and envv pointer tables came from trusted code and is * part of memory. Thus, by the same argument above, adding in * "ptr_tbl_size" cannot possibly overflow the "size" variable since * it is a size_t object. However, the extra pointers for auxv and * the space for argv could cause an overflow. The fact that we * used stack to get here etc means that ptr_tbl_size could not have * overflowed. * * NB: the underlying OS would have limited the amount of space used * for argv and envv -- on linux, it is ARG_MAX, or 128KB -- and * hence the overflow check is for obvious auditability rather than * for correctness. */ auxv_entries = 1; if (0 != nap->user_entry_pt) { auxv_entries++; } ptr_tbl_size = (((NACL_STACK_GETS_ARG ? 1 : 0) + (3 + argc + 1 + envc + 1 + auxv_entries * 2)) * sizeof(uint32_t)); if (SIZE_T_MAX - size < ptr_tbl_size) { NaClLog(LOG_WARNING, "NaClCreateMainThread: ptr_tbl_size cause size of" " argv / environment copy to overflow!?!\n"); retval = 0; goto cleanup; } size += ptr_tbl_size; size = (size + NACL_STACK_ALIGN_MASK) & ~NACL_STACK_ALIGN_MASK; if (size > nap->stack_size) { retval = 0; goto cleanup; } /* write strings and char * arrays to stack */ stack_ptr = (nap->mem_start + ((uintptr_t) 1U << nap->addr_bits) - size); NaClLog(2, "setting stack to : %016"NACL_PRIxPTR"\n", stack_ptr); VCHECK(0 == (stack_ptr & NACL_STACK_ALIGN_MASK), ("stack_ptr not aligned: %016"NACL_PRIxPTR"\n", stack_ptr)); p = (uint32_t *) stack_ptr; strp = (char *) stack_ptr + ptr_tbl_size; /* * For x86-32, we push an initial argument that is the address of * the main argument block. For other machines, this is passed * in a register and that's set in NaClStartThreadInApp. */ if (NACL_STACK_GETS_ARG) { uint32_t *argloc = p++; *argloc = (uint32_t) NaClSysToUser(nap, (uintptr_t) p); } *p++ = 0; /* Cleanup function pointer, always NULL. */ *p++ = envc; *p++ = argc; for (i = 0; i < argc; ++i) { *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp); NaClLog(2, "copying arg %d %p -> %p\n", i, argv[i], strp); strcpy(strp, argv[i]); strp += argv_len[i]; } *p++ = 0; /* argv[argc] is NULL. */ for (i = 0; i < envc; ++i) { *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp); NaClLog(2, "copying env %d %p -> %p\n", i, envv[i], strp); strcpy(strp, envv[i]); strp += envv_len[i]; } *p++ = 0; /* envp[envc] is NULL. */ /* Push an auxv */ if (0 != nap->user_entry_pt) { *p++ = AT_ENTRY; *p++ = (uint32_t) nap->user_entry_pt; } *p++ = AT_NULL; *p++ = 0; CHECK((char *) p == (char *) stack_ptr + ptr_tbl_size); /* * For x86, we adjust the stack pointer down to push a dummy return * address. This happens after the stack pointer alignment. */ stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN; memset((void *) stack_ptr, 0, NACL_STACK_PAD_BELOW_ALIGN); NaClLog(2, "system stack ptr : %016"NACL_PRIxPTR"\n", stack_ptr); NaClLog(2, " user stack ptr : %016"NACL_PRIxPTR"\n", NaClSysToUserStackAddr(nap, stack_ptr)); /* d'b: jump directly to user code instead of using thread launching */ ResumeCpuClock(nap); SwitchToApp(nap, stack_ptr); /* d'b end */ retval = 1; cleanup: free(argv_len); free(envv_len); return retval; }
static bool MainVBlank() { renderTopLines(); updAppList(); word_t kDown = keysDown(); TouchPos pos; // Page moving code do { int disp = 0; if (kDown & KEY_LEFT) disp = -1; else if (kDown & KEY_RIGHT) disp = +1; else if (kDown & KEY_UP) disp = -6; else if (kDown & KEY_DOWN) disp = +6; else if (kDown & KEY_TOUCH) { if (pos.InRegion(0, 48, 8, 64*2+8)) disp = -1; else if (pos.InRegion(256-8, 48, 8, 64*2+8)) disp = +1; } if (!disp) break; int oldPage = page; page += disp; int nPages = bump.GetBumpCount(); while (page < 0) page += nPages; while (page >= nPages) page -= nPages; if (page == oldPage) break; unloadPageIcons(oldPage); bump.SelectBump(page); updCursor(); loadPageIcons(); } while(0); // Selection code if (kDown & KEY_TOUCH) do { bool bFound = false; for (int i = 0; i < 6; i ++) { int xPos = 16 + (i % 3) * (64+16); int yPos = 48 + (i / 3) * (64+8); if (pos.InRegion(xPos, yPos, 64, 64)) { int touchedApp = page*6 + i; if (touchedApp == selectedApp) executeApp(); else if (g_appData[touchedApp].IsLoaded()) { selectedApp = touchedApp; updCursor(); } bFound = true; break; } } if (bFound) break; for (int i = 0; i < g_appList.GetCount(); i ++) { if (!pos.InRegion(64+(i*(16+8)), 16, 16, 16)) continue; SwitchToApp(i); return true; } } while(0); if (kDown & KEY_A) executeApp(); #ifdef ALLOW_EXIT if (g_appList.GetCount() == 0 && (kDown & KEY_START)) return false; #endif return true; }