Index: mojo/nacl/mojo_syscall_internal.h |
diff --git a/mojo/nacl/mojo_syscall_internal.h b/mojo/nacl/mojo_syscall_internal.h |
index f0795e63ba72c92dc7ec3629b93c3ca7c72440a0..84de656d20434d0fc9975d3bab50337a4c5cdc79 100644 |
--- a/mojo/nacl/mojo_syscall_internal.h |
+++ b/mojo/nacl/mojo_syscall_internal.h |
@@ -32,6 +32,27 @@ static inline uintptr_t NaClUserToSysAddrArray( |
return NaClUserToSysAddrRange(nap, uaddr, range); |
} |
+// We don't use plain-old memcpy because reads and writes to the untrusted |
+// address space from trusted code must be volatile. Non-volatile memory |
+// operations are dangerous because a compiler would be free to materialize a |
+// second load from the same memory address or materialize a load from a memory |
+// address that was stored, and assume the materialized load would return the |
+// same value as the previous load or store. Data races could cause the |
+// materialized load to return a different value, however, which could lead to |
+// time of check vs. time of use problems, or worse. For this binding code in |
+// particular, where memcpy is being called with a constant size, it is entirely |
+// conceivable the function will be inlined, unrolled, and optimized. |
+static inline void memcpy_volatile_out( |
+ void volatile* dst, |
+ const void* src, |
+ size_t n) { |
+ char volatile* c_dst = static_cast<char volatile*>(dst); |
+ const char* c_src = static_cast<const char*>(src); |
+ for (size_t i = 0; i < n; i++) { |
+ c_dst[i] = c_src[i]; |
+ } |
+} |
+ |
template <typename T> bool ConvertScalarInput( |
struct NaClApp* nap, |
uint32_t user_ptr, |
@@ -49,12 +70,16 @@ template <typename T> bool ConvertScalarInput( |
template <typename T> bool ConvertScalarOutput( |
struct NaClApp* nap, |
uint32_t user_ptr, |
+ bool optional, |
T volatile** sys_ptr) { |
if (user_ptr) { |
uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); |
if (temp != kNaClBadAddress) { |
*sys_ptr = reinterpret_cast<T volatile*>(temp); |
return true; |
+ } else if (optional) { |
+ *sys_ptr = 0; |
+ return true; |
} |
} |
*sys_ptr = 0; // Paranoia. |
@@ -127,7 +152,7 @@ template <typename T> bool ConvertBytes( |
// TODO(ncbray): size validation and complete copy. |
// TODO(ncbray): ensure non-null / missized structs are covered by a test case. |
-template <typename T> bool ConvertStruct( |
+template <typename T> bool ConvertExtensibleStructInput( |
struct NaClApp* nap, |
uint32_t user_ptr, |
bool optional, |