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 : static INLINE uintptr_t NaClUserToSysAddrNullOkay(struct NaClApp *nap,
53 0 : uintptr_t uaddr) {
54 0 : if (((uintptr_t) 1U << nap->addr_bits <= uaddr)) {
55 0 : return kNaClBadAddress;
56 : }
57 0 : return uaddr + nap->mem_start;
58 : }
59 :
60 : static INLINE uintptr_t NaClUserToSysAddr(struct NaClApp *nap,
61 42 : uintptr_t uaddr) {
62 42 : if (0 == uaddr || ((uintptr_t) 1U << nap->addr_bits) <= uaddr) {
63 3 : return kNaClBadAddress;
64 : }
65 39 : return uaddr + nap->mem_start;
66 : }
67 :
68 : static INLINE int NaClIsUserAddr(struct NaClApp *nap,
69 0 : uintptr_t sysaddr) {
70 0 : return nap->mem_start <= sysaddr &&
71 : sysaddr < nap->mem_start + ((uintptr_t) 1U << nap->addr_bits);
72 : }
73 :
74 : static INLINE uintptr_t NaClUserToSysAddrRange(struct NaClApp *nap,
75 : uintptr_t uaddr,
76 198 : size_t count) {
77 : uintptr_t end_addr;
78 :
79 198 : if (0 == uaddr) {
80 0 : return kNaClBadAddress;
81 : }
82 198 : end_addr = uaddr + count;
83 198 : if (end_addr < uaddr) {
84 : /* unsigned wraparound */
85 3 : return kNaClBadAddress;
86 : }
87 195 : if (((uintptr_t) 1U << nap->addr_bits) < end_addr) {
88 3 : return kNaClBadAddress;
89 : }
90 192 : return uaddr + nap->mem_start;
91 : }
92 :
93 : static INLINE uintptr_t NaClUserToSys(struct NaClApp *nap,
94 1153 : uintptr_t uaddr) {
95 1153 : if (0 == uaddr || ((uintptr_t) 1U << nap->addr_bits) <= uaddr) {
96 0 : NaClLog(LOG_FATAL,
97 : "NaClUserToSys: uaddr 0x%08"NACL_PRIxPTR", "
98 : "addr space %"NACL_PRId8" bits\n",
99 : uaddr, nap->addr_bits);
100 : }
101 1153 : return uaddr + nap->mem_start;
102 : }
103 :
104 : static INLINE uintptr_t NaClSysToUser(struct NaClApp *nap,
105 358 : uintptr_t sysaddr) {
106 358 : if (sysaddr < nap->mem_start ||
107 : nap->mem_start + ((uintptr_t) 1U << nap->addr_bits) <= sysaddr) {
108 0 : NaClLog(LOG_FATAL,
109 : ("NaclSysToUser: sysaddr 0x%08"NACL_PRIxPTR","
110 : " mem_start 0x%08"NACL_PRIxPTR","
111 : " addr space %"NACL_PRId8" bits\n"),
112 : sysaddr, nap->mem_start, nap->addr_bits);
113 : }
114 358 : return sysaddr - nap->mem_start;
115 : }
116 :
117 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
118 : /*
119 : * For x86-64 sandboxing, %rsp and %rbp are system addresses already.
120 : */
121 : static INLINE uintptr_t NaClUserToSysStackAddr(struct NaClApp *nap,
122 : uintptr_t stackaddr) {
123 : UNREFERENCED_PARAMETER(nap);
124 : return stackaddr;
125 : }
126 :
127 : static INLINE uintptr_t NaClSysToUserStackAddr(struct NaClApp *nap,
128 : uintptr_t stackaddr) {
129 : UNREFERENCED_PARAMETER(nap);
130 : return stackaddr;
131 : }
132 :
133 : #else
134 :
135 : static INLINE uintptr_t NaClUserToSysStackAddr(struct NaClApp *nap,
136 1124 : uintptr_t stackaddr) {
137 1124 : return NaClUserToSys(nap, stackaddr);
138 : }
139 :
140 : static INLINE uintptr_t NaClSysToUserStackAddr(struct NaClApp *nap,
141 6 : uintptr_t stackaddr) {
142 6 : return NaClSysToUser(nap, stackaddr);
143 : }
144 :
145 : #endif
146 :
147 9 : static INLINE uintptr_t NaClEndOfStaticText(struct NaClApp *nap) {
148 9 : return nap->static_text_end;
149 : }
150 :
151 : static INLINE uintptr_t NaClSandboxCodeAddr(struct NaClApp *nap,
152 559 : uintptr_t addr) {
153 : #if NACL_DANGEROUS_DEBUG_ONLY_NO_SANDBOX_RETURNS
154 : UNREFERENCED_PARAMETER(nap);
155 : return addr;
156 : #else
157 : # if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
158 : # if NACL_BUILD_SUBARCH == 32
159 559 : return addr & ~(((uintptr_t) nap->bundle_size) - 1);
160 : # elif NACL_BUILD_SUBARCH == 64
161 : return (((addr & ~(((uintptr_t) nap->bundle_size) - 1))
162 : & ((((uintptr_t) 1) << 32) - 1))
163 : + nap->mem_start);
164 : # else
165 : # error "What kind of x86 are we on anyway?!?"
166 : # endif
167 : # elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
168 : # if defined(NACL_TARGET_ARM_THUMB2_MODE)
169 : return ((addr & ~(((uintptr_t) nap->bundle_size) - 1)) & ~0xF0000000) | 0xF;
170 : # else
171 : /*
172 : * TODO(cbiffle): this hardcodes the size of code memory, and needs to become
173 : * a parameter in NaClApp. The simplest way to do this is with the change
174 : * suggested in issue 244. Then we could fold ARM and x86 impls together.
175 : */
176 :
177 : return (addr & ~(((uintptr_t) nap->bundle_size) - 1)) & ~0xF0000000;
178 : # endif /* defined(NACL_TARGET_ARM_THUMB2_MODE) */
179 : # else
180 : # error "What architecture are we on?!?"
181 : # endif
182 : #endif
183 : }
184 :
185 : static INLINE int NaClIsValidJumpTarget(struct NaClApp *nap,
186 0 : uintptr_t addr) {
187 0 : if (0 != (addr & (((uintptr_t) nap->bundle_size) - 1))) {
188 0 : return 0;
189 : }
190 0 : return addr < nap->dynamic_text_end;
191 : }
|