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. 4 5 #include "mojo/system/shared_buffer_dispatcher.h" 6 7 #include <limits> 8 9 #include "base/logging.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "mojo/embedder/platform_support.h" 12 #include "mojo/public/c/system/macros.h" 13 #include "mojo/system/channel.h" 14 #include "mojo/system/constants.h" 15 #include "mojo/system/memory.h" 16 #include "mojo/system/options_validation.h" 17 18 namespace mojo { 19 namespace system { 20 21 namespace { 22 23 struct SerializedSharedBufferDispatcher { 24 size_t num_bytes; 25 size_t platform_handle_index; 26 }; 27 28 } // namespace 29 30 // static 31 const MojoCreateSharedBufferOptions 32 SharedBufferDispatcher::kDefaultCreateOptions = { 33 static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)), 34 MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE}; 35 36 // static 37 MojoResult SharedBufferDispatcher::ValidateCreateOptions( 38 UserPointer<const MojoCreateSharedBufferOptions> in_options, 39 MojoCreateSharedBufferOptions* out_options) { 40 const MojoCreateSharedBufferOptionsFlags kKnownFlags = 41 MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; 42 43 *out_options = kDefaultCreateOptions; 44 if (in_options.IsNull()) 45 return MOJO_RESULT_OK; 46 47 UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options); 48 if (!reader.is_valid()) 49 return MOJO_RESULT_INVALID_ARGUMENT; 50 51 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader)) 52 return MOJO_RESULT_OK; 53 if ((reader.options().flags & ~kKnownFlags)) 54 return MOJO_RESULT_UNIMPLEMENTED; 55 out_options->flags = reader.options().flags; 56 57 // Checks for fields beyond |flags|: 58 59 // (Nothing here yet.) 60 61 return MOJO_RESULT_OK; 62 } 63 64 // static 65 MojoResult SharedBufferDispatcher::Create( 66 embedder::PlatformSupport* platform_support, 67 const MojoCreateSharedBufferOptions& /*validated_options*/, 68 uint64_t num_bytes, 69 scoped_refptr<SharedBufferDispatcher>* result) { 70 if (!num_bytes) 71 return MOJO_RESULT_INVALID_ARGUMENT; 72 if (num_bytes > kMaxSharedMemoryNumBytes) 73 return MOJO_RESULT_RESOURCE_EXHAUSTED; 74 75 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer( 76 platform_support->CreateSharedBuffer(static_cast<size_t>(num_bytes))); 77 if (!shared_buffer.get()) 78 return MOJO_RESULT_RESOURCE_EXHAUSTED; 79 80 *result = new SharedBufferDispatcher(shared_buffer); 81 return MOJO_RESULT_OK; 82 } 83 84 Dispatcher::Type SharedBufferDispatcher::GetType() const { 85 return kTypeSharedBuffer; 86 } 87 88 // static 89 scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize( 90 Channel* channel, 91 const void* source, 92 size_t size, 93 embedder::PlatformHandleVector* platform_handles) { 94 DCHECK(channel); 95 96 if (size != sizeof(SerializedSharedBufferDispatcher)) { 97 LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)"; 98 return scoped_refptr<SharedBufferDispatcher>(); 99 } 100 101 const SerializedSharedBufferDispatcher* serialization = 102 static_cast<const SerializedSharedBufferDispatcher*>(source); 103 size_t num_bytes = serialization->num_bytes; 104 size_t platform_handle_index = serialization->platform_handle_index; 105 106 if (!num_bytes) { 107 LOG(ERROR) 108 << "Invalid serialized shared buffer dispatcher (invalid num_bytes)"; 109 return scoped_refptr<SharedBufferDispatcher>(); 110 } 111 112 if (!platform_handles || platform_handle_index >= platform_handles->size()) { 113 LOG(ERROR) 114 << "Invalid serialized shared buffer dispatcher (missing handles)"; 115 return scoped_refptr<SharedBufferDispatcher>(); 116 } 117 118 // Starts off invalid, which is what we want. 119 embedder::PlatformHandle platform_handle; 120 // We take ownership of the handle, so we have to invalidate the one in 121 // |platform_handles|. 122 std::swap(platform_handle, (*platform_handles)[platform_handle_index]); 123 124 // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be 125 // closed even if creation fails. 126 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer( 127 channel->platform_support()->CreateSharedBufferFromHandle( 128 num_bytes, embedder::ScopedPlatformHandle(platform_handle))); 129 if (!shared_buffer.get()) { 130 LOG(ERROR) 131 << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)"; 132 return scoped_refptr<SharedBufferDispatcher>(); 133 } 134 135 return scoped_refptr<SharedBufferDispatcher>( 136 new SharedBufferDispatcher(shared_buffer)); 137 } 138 139 SharedBufferDispatcher::SharedBufferDispatcher( 140 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer) 141 : shared_buffer_(shared_buffer) { 142 DCHECK(shared_buffer_.get()); 143 } 144 145 SharedBufferDispatcher::~SharedBufferDispatcher() { 146 } 147 148 // static 149 MojoResult SharedBufferDispatcher::ValidateDuplicateOptions( 150 UserPointer<const MojoDuplicateBufferHandleOptions> in_options, 151 MojoDuplicateBufferHandleOptions* out_options) { 152 const MojoDuplicateBufferHandleOptionsFlags kKnownFlags = 153 MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE; 154 static const MojoDuplicateBufferHandleOptions kDefaultOptions = { 155 static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)), 156 MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE}; 157 158 *out_options = kDefaultOptions; 159 if (in_options.IsNull()) 160 return MOJO_RESULT_OK; 161 162 UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options); 163 if (!reader.is_valid()) 164 return MOJO_RESULT_INVALID_ARGUMENT; 165 166 if (!OPTIONS_STRUCT_HAS_MEMBER( 167 MojoDuplicateBufferHandleOptions, flags, reader)) 168 return MOJO_RESULT_OK; 169 if ((reader.options().flags & ~kKnownFlags)) 170 return MOJO_RESULT_UNIMPLEMENTED; 171 out_options->flags = reader.options().flags; 172 173 // Checks for fields beyond |flags|: 174 175 // (Nothing here yet.) 176 177 return MOJO_RESULT_OK; 178 } 179 180 void SharedBufferDispatcher::CloseImplNoLock() { 181 lock().AssertAcquired(); 182 DCHECK(shared_buffer_.get()); 183 shared_buffer_ = nullptr; 184 } 185 186 scoped_refptr<Dispatcher> 187 SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() { 188 lock().AssertAcquired(); 189 DCHECK(shared_buffer_.get()); 190 scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer; 191 shared_buffer.swap(shared_buffer_); 192 return scoped_refptr<Dispatcher>(new SharedBufferDispatcher(shared_buffer)); 193 } 194 195 MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock( 196 UserPointer<const MojoDuplicateBufferHandleOptions> options, 197 scoped_refptr<Dispatcher>* new_dispatcher) { 198 lock().AssertAcquired(); 199 200 MojoDuplicateBufferHandleOptions validated_options; 201 MojoResult result = ValidateDuplicateOptions(options, &validated_options); 202 if (result != MOJO_RESULT_OK) 203 return result; 204 205 *new_dispatcher = new SharedBufferDispatcher(shared_buffer_); 206 return MOJO_RESULT_OK; 207 } 208 209 MojoResult SharedBufferDispatcher::MapBufferImplNoLock( 210 uint64_t offset, 211 uint64_t num_bytes, 212 MojoMapBufferFlags flags, 213 scoped_ptr<embedder::PlatformSharedBufferMapping>* mapping) { 214 lock().AssertAcquired(); 215 DCHECK(shared_buffer_.get()); 216 217 if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) 218 return MOJO_RESULT_INVALID_ARGUMENT; 219 if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) 220 return MOJO_RESULT_INVALID_ARGUMENT; 221 222 if (!shared_buffer_->IsValidMap(static_cast<size_t>(offset), 223 static_cast<size_t>(num_bytes))) 224 return MOJO_RESULT_INVALID_ARGUMENT; 225 226 DCHECK(mapping); 227 *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset), 228 static_cast<size_t>(num_bytes)); 229 if (!*mapping) 230 return MOJO_RESULT_RESOURCE_EXHAUSTED; 231 232 return MOJO_RESULT_OK; 233 } 234 235 void SharedBufferDispatcher::StartSerializeImplNoLock( 236 Channel* /*channel*/, 237 size_t* max_size, 238 size_t* max_platform_handles) { 239 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. 240 *max_size = sizeof(SerializedSharedBufferDispatcher); 241 *max_platform_handles = 1; 242 } 243 244 bool SharedBufferDispatcher::EndSerializeAndCloseImplNoLock( 245 Channel* /*channel*/, 246 void* destination, 247 size_t* actual_size, 248 embedder::PlatformHandleVector* platform_handles) { 249 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. 250 DCHECK(shared_buffer_.get()); 251 252 SerializedSharedBufferDispatcher* serialization = 253 static_cast<SerializedSharedBufferDispatcher*>(destination); 254 // If there's only one reference to |shared_buffer_|, then it's ours (and no 255 // one else can make any more references to it), so we can just take its 256 // handle. 257 embedder::ScopedPlatformHandle platform_handle( 258 shared_buffer_->HasOneRef() ? shared_buffer_->PassPlatformHandle() 259 : shared_buffer_->DuplicatePlatformHandle()); 260 if (!platform_handle.is_valid()) { 261 shared_buffer_ = nullptr; 262 return false; 263 } 264 265 serialization->num_bytes = shared_buffer_->GetNumBytes(); 266 serialization->platform_handle_index = platform_handles->size(); 267 platform_handles->push_back(platform_handle.release()); 268 *actual_size = sizeof(SerializedSharedBufferDispatcher); 269 270 shared_buffer_ = nullptr; 271 272 return true; 273 } 274 275 } // namespace system 276 } // namespace mojo 277