Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / mojo / src / nacl_bindings / mojo_syscall_internal.h
blob2f67e3a669bc3a7d73239c74f80df41679fcc6cb
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.
5 #ifndef MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
6 #define MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
8 #include <type_traits>
10 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
11 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
13 namespace {
15 class ScopedCopyLock {
16 public:
17 explicit ScopedCopyLock(struct NaClApp* nap) : nap_(nap) {
18 NaClCopyTakeLock(nap_);
20 ~ScopedCopyLock() { NaClCopyDropLock(nap_); }
22 private:
23 struct NaClApp* nap_;
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);
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];
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;
63 } else {
64 *value = nullptr;
65 return true;
67 *value = nullptr; // Paranoia.
68 return false;
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;
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;
95 } else if (optional) {
96 *sys_ptr = nullptr;
97 *value = nullptr; // Paranoia.
98 return true;
100 *sys_ptr = nullptr; // Paranoia.
101 *value = nullptr; // Paranoia.
102 return false;
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;
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;
127 return false;
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;
142 } else if (optional) {
143 *sys_ptr = 0;
144 return true;
146 *sys_ptr = 0; // Paranoia.
147 return false;
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;
165 } else if (optional) {
166 *sys_ptr = 0;
167 *value = static_cast<T>(0); // Paranoia.
168 return true;
170 *sys_ptr = 0; // Paranoia.
171 *value = static_cast<T>(0); // Paranoia.
172 return false;
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;
189 } else if (optional) {
190 *sys_ptr = 0;
191 return true;
193 return false;
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;
208 } else if (optional) {
209 *sys_ptr = 0;
210 return true;
212 return false;
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;
229 } else if (optional) {
230 *sys_ptr = 0;
231 return true;
233 return false;
236 } // namespace
238 #endif // MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_