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_
10 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
11 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
15 class ScopedCopyLock
{
17 explicit ScopedCopyLock(struct NaClApp
* nap
) : nap_(nap
) {
18 NaClCopyTakeLock(nap_
);
20 ~ScopedCopyLock() { NaClCopyDropLock(nap_
); }
26 static inline uintptr_t NaClUserToSysAddrArray(struct NaClApp
* nap
,
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
,
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
++) {
56 bool ConvertPointerInput(struct NaClApp
* nap
, uint32_t user_ptr
, T
** value
) {
58 uintptr_t temp
= NaClUserToSysAddr(nap
, user_ptr
);
59 if (temp
!= kNaClBadAddress
) {
60 *value
= reinterpret_cast<T
*>(temp
);
67 *value
= nullptr; // Paranoia.
72 bool ConvertPointerInOut(struct NaClApp
* nap
,
76 uint32_t volatile** sys_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
;
84 *sys_ptr
= converted_ptr
;
88 uintptr_t temp
= NaClUserToSysAddr(nap
, raw_value
);
89 if (temp
!= kNaClBadAddress
) {
90 *sys_ptr
= converted_ptr
;
91 *value
= reinterpret_cast<T
*>(temp
);
95 } else if (optional
) {
97 *value
= nullptr; // Paranoia.
100 *sys_ptr
= nullptr; // Paranoia.
101 *value
= nullptr; // Paranoia.
105 template <typename T
>
106 void CopyOutPointer(struct NaClApp
* nap
, T
* value
, uint32_t volatile* sys_ptr
) {
108 // Will kill the process if value if the pointer does not lie in the
110 uintptr_t temp
= NaClSysToUser(nap
, reinterpret_cast<uintptr_t>(value
));
111 *sys_ptr
= static_cast<uint32_t>(temp
);
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");
121 uintptr_t temp
= NaClUserToSysAddrRange(nap
, user_ptr
, sizeof(T
));
122 if (temp
!= kNaClBadAddress
) {
123 *value
= *reinterpret_cast<T
volatile*>(temp
);
130 template <typename T
>
131 bool ConvertScalarOutput(struct NaClApp
* nap
,
134 T
volatile** sys_ptr
) {
135 static_assert(!std::is_pointer
<T
>::value
, "do not use for pointer types");
137 uintptr_t temp
= NaClUserToSysAddrRange(nap
, user_ptr
, sizeof(T
));
138 if (temp
!= kNaClBadAddress
) {
139 *sys_ptr
= reinterpret_cast<T
volatile*>(temp
);
142 } else if (optional
) {
146 *sys_ptr
= 0; // Paranoia.
150 template <typename T
>
151 bool ConvertScalarInOut(struct NaClApp
* nap
,
155 T
volatile** sys_ptr
) {
156 static_assert(!std::is_pointer
<T
>::value
, "do not use for pointer types");
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
;
165 } else if (optional
) {
167 *value
= static_cast<T
>(0); // Paranoia.
170 *sys_ptr
= 0; // Paranoia.
171 *value
= static_cast<T
>(0); // Paranoia.
175 template <typename T
>
176 bool ConvertArray(struct NaClApp
* nap
,
184 NaClUserToSysAddrArray(nap
, user_ptr
, length
, element_size
);
185 if (temp
!= kNaClBadAddress
) {
186 *sys_ptr
= reinterpret_cast<T
*>(temp
);
189 } else if (optional
) {
196 template <typename T
>
197 bool ConvertBytes(struct NaClApp
* nap
,
203 uintptr_t temp
= NaClUserToSysAddrRange(nap
, user_ptr
, length
);
204 if (temp
!= kNaClBadAddress
) {
205 *sys_ptr
= reinterpret_cast<T
*>(temp
);
208 } else if (optional
) {
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
,
222 static_assert(!std::is_pointer
<T
>::value
, "do not use for pointer types");
224 uintptr_t temp
= NaClUserToSysAddrRange(nap
, user_ptr
, sizeof(T
));
225 if (temp
!= kNaClBadAddress
) {
226 *sys_ptr
= reinterpret_cast<T
*>(temp
);
229 } else if (optional
) {
238 #endif // MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_