OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef MOJO_NACL_SFI_NACL_BINDINGS_MOJO_SYSCALL_INTERNAL_H_ | |
6 #define MOJO_NACL_SFI_NACL_BINDINGS_MOJO_SYSCALL_INTERNAL_H_ | |
7 | |
8 #include <type_traits> | |
9 | |
10 #include "native_client/src/trusted/service_runtime/nacl_copy.h" | |
11 #include "native_client/src/trusted/service_runtime/sel_ldr.h" | |
12 | |
13 namespace { | |
14 | |
15 class ScopedCopyLock { | |
16 public: | |
17 explicit ScopedCopyLock(struct NaClApp* nap) : nap_(nap) { | |
18 NaClCopyTakeLock(nap_); | |
19 } | |
20 ~ScopedCopyLock() { NaClCopyDropLock(nap_); } | |
21 | |
22 private: | |
23 struct NaClApp* nap_; | |
24 }; | |
25 | |
26 static inline uintptr_t NaClUserToSysAddrArray(struct NaClApp* nap, | |
27 uint32_t uaddr, | |
28 size_t count, | |
29 size_t size) { | |
30 // TODO(ncbray): overflow checking | |
31 size_t range = count * size; | |
32 return NaClUserToSysAddrRange(nap, uaddr, range); | |
33 } | |
34 | |
35 // We don't use plain-old memcpy because reads and writes to the untrusted | |
36 // address space from trusted code must be volatile. Non-volatile memory | |
37 // operations are dangerous because a compiler would be free to materialize a | |
38 // second load from the same memory address or materialize a load from a memory | |
39 // address that was stored, and assume the materialized load would return the | |
40 // same value as the previous load or store. Data races could cause the | |
41 // materialized load to return a different value, however, which could lead to | |
42 // time of check vs. time of use problems, or worse. For this binding code in | |
43 // particular, where memcpy is being called with a constant size, it is entirely | |
44 // conceivable the function will be inlined, unrolled, and optimized. | |
45 static inline void memcpy_volatile_out(void volatile* dst, | |
46 const void* src, | |
47 size_t n) { | |
48 char volatile* c_dst = static_cast<char volatile*>(dst); | |
49 const char* c_src = static_cast<const char*>(src); | |
50 for (size_t i = 0; i < n; i++) { | |
51 c_dst[i] = c_src[i]; | |
52 } | |
53 } | |
54 | |
55 template <typename T> | |
56 bool ConvertPointerInput(struct NaClApp* nap, uint32_t user_ptr, T** value) { | |
57 if (user_ptr) { | |
58 uintptr_t temp = NaClUserToSysAddr(nap, user_ptr); | |
59 if (temp != kNaClBadAddress) { | |
60 *value = reinterpret_cast<T*>(temp); | |
61 return true; | |
62 } | |
63 } else { | |
64 *value = nullptr; | |
65 return true; | |
66 } | |
67 *value = nullptr; // Paranoia. | |
68 return false; | |
69 } | |
70 | |
71 template <typename T> | |
72 bool ConvertPointerInOut(struct NaClApp* nap, | |
73 uint32_t user_ptr, | |
74 bool optional, | |
75 T** value, | |
76 uint32_t volatile** sys_ptr) { | |
77 if (user_ptr) { | |
78 uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(uint32_t)); | |
79 if (temp != kNaClBadAddress) { | |
80 uint32_t volatile* converted_ptr = | |
81 reinterpret_cast<uint32_t volatile*>(temp); | |
82 uint32_t raw_value = *converted_ptr; | |
83 if (!raw_value) { | |
84 *sys_ptr = converted_ptr; | |
85 *value = nullptr; | |
86 return true; | |
87 } | |
88 uintptr_t temp = NaClUserToSysAddr(nap, raw_value); | |
89 if (temp != kNaClBadAddress) { | |
90 *sys_ptr = converted_ptr; | |
91 *value = reinterpret_cast<T*>(temp); | |
92 return true; | |
93 } | |
94 } | |
95 } else if (optional) { | |
96 *sys_ptr = nullptr; | |
97 *value = nullptr; // Paranoia. | |
98 return true; | |
99 } | |
100 *sys_ptr = nullptr; // Paranoia. | |
101 *value = nullptr; // Paranoia. | |
102 return false; | |
103 } | |
104 | |
105 template <typename T> | |
106 void CopyOutPointer(struct NaClApp* nap, T* value, uint32_t volatile* sys_ptr) { | |
107 if (value) { | |
108 // Will kill the process if value if the pointer does not lie in the | |
109 // sandbox. | |
110 uintptr_t temp = NaClSysToUser(nap, reinterpret_cast<uintptr_t>(value)); | |
111 *sys_ptr = static_cast<uint32_t>(temp); | |
112 } else { | |
113 *sys_ptr = 0; | |
114 } | |
115 } | |
116 | |
117 template <typename T> | |
118 bool ConvertScalarInput(struct NaClApp* nap, uint32_t user_ptr, T* value) { | |
119 static_assert(!std::is_pointer<T>::value, "do not use for pointer types"); | |
120 if (user_ptr) { | |
121 uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); | |
122 if (temp != kNaClBadAddress) { | |
123 *value = *reinterpret_cast<T volatile*>(temp); | |
124 return true; | |
125 } | |
126 } | |
127 return false; | |
128 } | |
129 | |
130 template <typename T> | |
131 bool ConvertScalarOutput(struct NaClApp* nap, | |
132 uint32_t user_ptr, | |
133 bool optional, | |
134 T volatile** sys_ptr) { | |
135 static_assert(!std::is_pointer<T>::value, "do not use for pointer types"); | |
136 if (user_ptr) { | |
137 uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); | |
138 if (temp != kNaClBadAddress) { | |
139 *sys_ptr = reinterpret_cast<T volatile*>(temp); | |
140 return true; | |
141 } | |
142 } else if (optional) { | |
143 *sys_ptr = 0; | |
144 return true; | |
145 } | |
146 *sys_ptr = 0; // Paranoia. | |
147 return false; | |
148 } | |
149 | |
150 template <typename T> | |
151 bool ConvertScalarInOut(struct NaClApp* nap, | |
152 uint32_t user_ptr, | |
153 bool optional, | |
154 T* value, | |
155 T volatile** sys_ptr) { | |
156 static_assert(!std::is_pointer<T>::value, "do not use for pointer types"); | |
157 if (user_ptr) { | |
158 uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); | |
159 if (temp != kNaClBadAddress) { | |
160 T volatile* converted = reinterpret_cast<T volatile*>(temp); | |
161 *sys_ptr = converted; | |
162 *value = *converted; | |
163 return true; | |
164 } | |
165 } else if (optional) { | |
166 *sys_ptr = 0; | |
167 *value = static_cast<T>(0); // Paranoia. | |
168 return true; | |
169 } | |
170 *sys_ptr = 0; // Paranoia. | |
171 *value = static_cast<T>(0); // Paranoia. | |
172 return false; | |
173 } | |
174 | |
175 template <typename T> | |
176 bool ConvertArray(struct NaClApp* nap, | |
177 uint32_t user_ptr, | |
178 uint32_t length, | |
179 size_t element_size, | |
180 bool optional, | |
181 T** sys_ptr) { | |
182 if (user_ptr) { | |
183 uintptr_t temp = | |
184 NaClUserToSysAddrArray(nap, user_ptr, length, element_size); | |
185 if (temp != kNaClBadAddress) { | |
186 *sys_ptr = reinterpret_cast<T*>(temp); | |
187 return true; | |
188 } | |
189 } else if (optional) { | |
190 *sys_ptr = 0; | |
191 return true; | |
192 } | |
193 return false; | |
194 } | |
195 | |
196 template <typename T> | |
197 bool ConvertBytes(struct NaClApp* nap, | |
198 uint32_t user_ptr, | |
199 uint32_t length, | |
200 bool optional, | |
201 T** sys_ptr) { | |
202 if (user_ptr) { | |
203 uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, length); | |
204 if (temp != kNaClBadAddress) { | |
205 *sys_ptr = reinterpret_cast<T*>(temp); | |
206 return true; | |
207 } | |
208 } else if (optional) { | |
209 *sys_ptr = 0; | |
210 return true; | |
211 } | |
212 return false; | |
213 } | |
214 | |
215 // TODO(ncbray): size validation and complete copy. | |
216 // TODO(ncbray): ensure non-null / missized structs are covered by a test case. | |
217 template <typename T> | |
218 bool ConvertExtensibleStructInput(struct NaClApp* nap, | |
219 uint32_t user_ptr, | |
220 bool optional, | |
221 T** sys_ptr) { | |
222 static_assert(!std::is_pointer<T>::value, "do not use for pointer types"); | |
223 if (user_ptr) { | |
224 uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); | |
225 if (temp != kNaClBadAddress) { | |
226 *sys_ptr = reinterpret_cast<T*>(temp); | |
227 return true; | |
228 } | |
229 } else if (optional) { | |
230 *sys_ptr = 0; | |
231 return true; | |
232 } | |
233 return false; | |
234 } | |
235 | |
236 } // namespace | |
237 | |
238 #endif // MOJO_NACL_SFI_NACL_BINDINGS_MOJO_SYSCALL_INTERNAL_H_ | |
OLD | NEW |