// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_ #define MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_ #include "native_client/src/trusted/service_runtime/nacl_copy.h" #include "native_client/src/trusted/service_runtime/sel_ldr.h" namespace { class ScopedCopyLock { public: explicit ScopedCopyLock(struct NaClApp* nap) : nap_(nap) { NaClCopyTakeLock(nap_); } ~ScopedCopyLock() { NaClCopyDropLock(nap_); } private: struct NaClApp* nap_; }; static inline uintptr_t NaClUserToSysAddrArray( struct NaClApp* nap, uint32_t uaddr, size_t count, size_t size) { // TODO(ncbray): overflow checking size_t range = count * size; 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(dst); const char* c_src = static_cast(src); for (size_t i = 0; i < n; i++) { c_dst[i] = c_src[i]; } } template bool ConvertScalarInput( struct NaClApp* nap, uint32_t user_ptr, T* value) { if (user_ptr) { uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); if (temp != kNaClBadAddress) { *value = *reinterpret_cast(temp); return true; } } return false; } template 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(temp); return true; } } else if (optional) { *sys_ptr = 0; return true; } *sys_ptr = 0; // Paranoia. return false; } template bool ConvertScalarInOut( struct NaClApp* nap, uint32_t user_ptr, bool optional, T* value, T volatile** sys_ptr) { if (user_ptr) { uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); if (temp != kNaClBadAddress) { T volatile* converted = reinterpret_cast(temp); *sys_ptr = converted; *value = *converted; return true; } } else if (optional) { *sys_ptr = 0; *value = static_cast(0); // Paranoia. return true; } *sys_ptr = 0; // Paranoia. *value = static_cast(0); // Paranoia. return false; } template bool ConvertArray( struct NaClApp* nap, uint32_t user_ptr, uint32_t length, size_t element_size, bool optional, T** sys_ptr) { if (user_ptr) { uintptr_t temp = NaClUserToSysAddrArray(nap, user_ptr, length, element_size); if (temp != kNaClBadAddress) { *sys_ptr = reinterpret_cast(temp); return true; } } else if (optional) { *sys_ptr = 0; return true; } return false; } template bool ConvertBytes( struct NaClApp* nap, uint32_t user_ptr, uint32_t length, bool optional, T** sys_ptr) { if (user_ptr) { uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, length); if (temp != kNaClBadAddress) { *sys_ptr = reinterpret_cast(temp); return true; } } else if (optional) { *sys_ptr = 0; return true; } return false; } // TODO(ncbray): size validation and complete copy. // TODO(ncbray): ensure non-null / missized structs are covered by a test case. template bool ConvertExtensibleStructInput( struct NaClApp* nap, uint32_t user_ptr, bool optional, T** sys_ptr) { if (user_ptr) { uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T)); if (temp != kNaClBadAddress) { *sys_ptr = reinterpret_cast(temp); return true; } } else if (optional) { *sys_ptr = 0; return true; } return false; } } // namespace #endif // MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_