1 // Copyright 2013 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 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h" 6 7 #include "mojo/public/cpp/bindings/lib/bindings_internal.h" 8 #include "mojo/public/cpp/bindings/lib/bounds_checker.h" 9 #include "mojo/public/cpp/bindings/lib/validation_errors.h" 10 #include "mojo/public/cpp/environment/logging.h" 11 12 namespace mojo { 13 namespace internal { 14 15 namespace { 16 17 const size_t kAlignment = 8; 18 19 template<typename T> 20 T AlignImpl(T t) { 21 return t + (kAlignment - (t % kAlignment)) % kAlignment; 22 } 23 24 } // namespace 25 26 size_t Align(size_t size) { 27 return AlignImpl(size); 28 } 29 30 char* AlignPointer(char* ptr) { 31 return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr))); 32 } 33 34 bool IsAligned(const void* ptr) { 35 return !(reinterpret_cast<uintptr_t>(ptr) % kAlignment); 36 } 37 38 void EncodePointer(const void* ptr, uint64_t* offset) { 39 if (!ptr) { 40 *offset = 0; 41 return; 42 } 43 44 const char* p_obj = reinterpret_cast<const char*>(ptr); 45 const char* p_slot = reinterpret_cast<const char*>(offset); 46 MOJO_DCHECK(p_obj > p_slot); 47 48 *offset = static_cast<uint64_t>(p_obj - p_slot); 49 } 50 51 const void* DecodePointerRaw(const uint64_t* offset) { 52 if (!*offset) 53 return NULL; 54 return reinterpret_cast<const char*>(offset) + *offset; 55 } 56 57 bool ValidateEncodedPointer(const uint64_t* offset) { 58 // Cast to uintptr_t so overflow behavior is well defined. 59 return reinterpret_cast<uintptr_t>(offset) + *offset >= 60 reinterpret_cast<uintptr_t>(offset); 61 } 62 63 void EncodeHandle(Handle* handle, std::vector<Handle>* handles) { 64 if (handle->is_valid()) { 65 handles->push_back(*handle); 66 handle->set_value(static_cast<MojoHandle>(handles->size() - 1)); 67 } else { 68 handle->set_value(kEncodedInvalidHandleValue); 69 } 70 } 71 72 void DecodeHandle(Handle* handle, std::vector<Handle>* handles) { 73 if (handle->value() == kEncodedInvalidHandleValue) { 74 *handle = Handle(); 75 return; 76 } 77 MOJO_DCHECK(handle->value() < handles->size()); 78 // Just leave holes in the vector so we don't screw up other indices. 79 *handle = FetchAndReset(&handles->at(handle->value())); 80 } 81 82 bool ValidateStructHeader(const void* data, 83 uint32_t min_num_bytes, 84 uint32_t min_num_fields, 85 BoundsChecker* bounds_checker) { 86 MOJO_DCHECK(min_num_bytes >= sizeof(StructHeader)); 87 88 if (!IsAligned(data)) { 89 ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); 90 return false; 91 } 92 if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) { 93 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); 94 return false; 95 } 96 97 const StructHeader* header = static_cast<const StructHeader*>(data); 98 99 // TODO(yzshen): Currently our binding code cannot handle structs of smaller 100 // size or with fewer fields than the version that it sees. That needs to be 101 // changed in order to provide backward compatibility. 102 if (header->num_bytes < min_num_bytes || 103 header->num_fields < min_num_fields) { 104 ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); 105 return false; 106 } 107 108 if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { 109 ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); 110 return false; 111 } 112 113 return true; 114 } 115 116 } // namespace internal 117 } // namespace mojo 118