1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*******************************************************************************
8 : *
9 : * DO NOT INCLUDE EXCEPT FROM sel_ldr.h
10 : *
11 : ******************************************************************************/
12 :
13 : /*
14 : * Routines to translate addresses between user and "system" or
15 : * service runtime addresses. the *Addr* versions will return
16 : * kNaClBadAddress if the user address is outside of the user address
17 : * space, e.g., if the input addresses for *UserToSys* is outside of
18 : * (1<<nap->addr_bits), and correspondingly for *SysToUser* if the
19 : * input system address does not correspond to a user address.
20 : * Generally, the *Addr* versions are used when the addresses come
21 : * from untrusted usre code, and kNaClBadAddress would translate to an
22 : * EINVAL return from a syscall. The *Range code ensures that the
23 : * entire address range is in the user address space.
24 : *
25 : * Note that just because an address is within the address space, it
26 : * doesn't mean that it is safe to acceess the memory: the page may be
27 : * protected against access.
28 : *
29 : * The non-*Addr* versions abort the program rather than return an
30 : * error indication.
31 : */
32 :
33 : /*
34 : * address translation routines. after a NaClApp is started, the
35 : * member variables accessed by these routines are read-only, so no
36 : * locking is needed to use these functions, as long as the NaClApp
37 : * structure doesn't get destructed/deallocated.
38 : *
39 : * the first is used internally when a NULL pointer is okay, typically
40 : * for address manipulation.
41 : *
42 : * the next two are for syscalls to do address translation, e.g., for
43 : * system calls; -1 indicates an error, so the syscall can return
44 : * EINVAL or EFAULT or whatever is appropriate.
45 : *
46 : * the latter two interfaces are for use everywhere else in the loader
47 : * / service runtime and will log a fatal error and abort the process
48 : * when an error is detected. (0 is not a good error indicator, since
49 : * 0 is a valid user address.)
50 : */
51 :
52 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
53 :
54 38 : static INLINE uintptr_t NaClUserToSysAddrNullOkay(struct NaClApp *nap,
55 38 : uintptr_t uaddr) {
56 38 : if (((uintptr_t) 1U << nap->addr_bits <= uaddr)) {
57 0 : return kNaClBadAddress;
58 : }
59 38 : return uaddr + nap->mem_start;
60 38 : }
61 :
62 21648 : static INLINE uintptr_t NaClUserToSysAddr(struct NaClApp *nap,
63 21648 : uintptr_t uaddr) {
64 43282 : if (0 == uaddr || ((uintptr_t) 1U << nap->addr_bits) <= uaddr) {
65 14 : return kNaClBadAddress;
66 : }
67 21634 : return uaddr + nap->mem_start;
68 21648 : }
69 :
70 57006 : static INLINE int NaClIsUserAddr(struct NaClApp *nap,
71 57006 : uintptr_t sysaddr) {
72 : /*
73 : * Note that NaClIsUserAddr() is used in the Windows debug exception
74 : * handler so must remain safe to use on a copy of NaClApp.
75 : */
76 110602 : return nap->mem_start <= sysaddr &&
77 : sysaddr < nap->mem_start + ((uintptr_t) 1U << nap->addr_bits);
78 57006 : }
79 :
80 3072626 : static INLINE uintptr_t NaClUserToSysAddrRange(struct NaClApp *nap,
81 3072626 : uintptr_t uaddr,
82 3072626 : size_t count) {
83 3072626 : uintptr_t end_addr;
84 :
85 3072626 : if (0 == uaddr) {
86 3 : return kNaClBadAddress;
87 : }
88 3072623 : end_addr = uaddr + count;
89 3072623 : if (end_addr < uaddr) {
90 : /* unsigned wraparound */
91 1 : return kNaClBadAddress;
92 : }
93 3072622 : if (((uintptr_t) 1U << nap->addr_bits) < end_addr) {
94 7 : return kNaClBadAddress;
95 : }
96 3072614 : return uaddr + nap->mem_start;
97 3072625 : }
98 :
99 118825 : static INLINE uintptr_t NaClUserToSys(struct NaClApp *nap,
100 118825 : uintptr_t uaddr) {
101 237650 : if (0 == uaddr || ((uintptr_t) 1U << nap->addr_bits) <= uaddr) {
102 0 : NaClLog(LOG_FATAL,
103 : "NaClUserToSys: uaddr 0x%08" NACL_PRIxPTR ", "
104 : "addr space %" NACL_PRId8 " bits\n",
105 : uaddr, nap->addr_bits);
106 0 : }
107 118825 : return uaddr + nap->mem_start;
108 : }
109 :
110 142086 : static INLINE uintptr_t NaClSysToUser(struct NaClApp *nap,
111 142086 : uintptr_t sysaddr) {
112 284172 : if (sysaddr < nap->mem_start ||
113 : nap->mem_start + ((uintptr_t) 1U << nap->addr_bits) <= sysaddr) {
114 0 : NaClLog(LOG_FATAL,
115 : ("NaClSysToUser: sysaddr 0x%08" NACL_PRIxPTR ","
116 : " mem_start 0x%08" NACL_PRIxPTR ","
117 : " addr space %" NACL_PRId8 " bits\n"),
118 : sysaddr, nap->mem_start, nap->addr_bits);
119 0 : }
120 142086 : return sysaddr - nap->mem_start;
121 : }
122 :
123 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
124 : /*
125 : * For x86-64 sandboxing, %rsp and %rbp are system addresses already.
126 : */
127 3538671 : static INLINE uintptr_t NaClUserToSysStackAddr(struct NaClApp *nap,
128 3538671 : uintptr_t stackaddr) {
129 7077342 : UNREFERENCED_PARAMETER(nap);
130 3538671 : return stackaddr;
131 : }
132 :
133 21151 : static INLINE uintptr_t NaClSysToUserStackAddr(struct NaClApp *nap,
134 21151 : uintptr_t stackaddr) {
135 42302 : UNREFERENCED_PARAMETER(nap);
136 21151 : return stackaddr;
137 : }
138 :
139 : #else
140 :
141 : static INLINE uintptr_t NaClUserToSysStackAddr(struct NaClApp *nap,
142 : uintptr_t stackaddr) {
143 : return NaClUserToSys(nap, stackaddr);
144 : }
145 :
146 : static INLINE uintptr_t NaClSysToUserStackAddr(struct NaClApp *nap,
147 : uintptr_t stackaddr) {
148 : return NaClSysToUser(nap, stackaddr);
149 : }
150 :
151 : #endif
152 :
153 : /*
154 : * Normalize a user address space address. This function is really a
155 : * no-op for 32-bit sandboxes, but for x86-64 where rsp contains a
156 : * true 64-bit address, we must discard the high 32 bits to make the
157 : * stack address a proper user-space address. After normalization,
158 : * the address can be used with NaClUserToSys etc.
159 : */
160 3538673 : static INLINE uint32_t NaClRawUserStackAddrNormalize(uintptr_t stack_addr) {
161 3538673 : return (uint32_t) stack_addr;
162 : }
163 :
164 553 : static INLINE uintptr_t NaClEndOfStaticText(struct NaClApp *nap) {
165 553 : return nap->static_text_end;
166 : }
167 :
168 3544424 : static INLINE uintptr_t NaClSandboxCodeAddr(struct NaClApp *nap,
169 3544424 : uintptr_t addr) {
170 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
171 : /*
172 : * If misaligned, round up to the following bundle boundary.
173 : * With the original nacl-gcc toolchain, a return address is
174 : * always on a bundle boundary, so this is always a no-op and
175 : * the ABI specification was that a misaligned return address
176 : * has undefined results. With the next-generation gcc
177 : * toolchain, a return address on the stack may be mid-bundle
178 : * and the ABI specification is that the real address to use is
179 : * found by rounding up to the following bundle.
180 : */
181 3544424 : addr += (uintptr_t) nap->bundle_size - 1;
182 3544424 : addr &= ~((uintptr_t) nap->bundle_size - 1);
183 : # if NACL_BUILD_SUBARCH == 32
184 : return addr;
185 : # elif NACL_BUILD_SUBARCH == 64
186 3544424 : return nap->mem_start + (uint32_t) addr;
187 : # else
188 : # error "What kind of x86 are we on anyway?!?"
189 : # endif
190 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
191 : UNREFERENCED_PARAMETER(nap);
192 : addr &= ~NACL_CONTROL_FLOW_MASK;
193 : return addr;
194 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
195 : UNREFERENCED_PARAMETER(nap);
196 : return addr & NACL_CONTROL_FLOW_MASK;
197 : #else
198 : # error "What architecture are we on?!?"
199 : #endif
200 : }
201 :
202 20774 : static INLINE int NaClIsValidJumpTarget(struct NaClApp *nap,
203 20774 : uintptr_t addr) {
204 20774 : if (0 != (addr & (((uintptr_t) nap->bundle_size) - 1))) {
205 3 : return 0;
206 : }
207 20771 : return addr < nap->dynamic_text_end;
208 20774 : }
|