| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/system/message_in_transit.h" | 5 #include "mojo/system/message_in_transit.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include <new> | 9 #include <new> |
| 10 | 10 |
| 11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/memory/aligned_memory.h" | 13 #include "base/memory/aligned_memory.h" |
| 14 #include "mojo/system/constants.h" | 14 #include "mojo/system/constants.h" |
| 15 | 15 |
| 16 namespace mojo { | 16 namespace mojo { |
| 17 namespace system { | 17 namespace system { |
| 18 | 18 |
| 19 namespace { | |
| 20 | |
| 21 | |
| 22 } // namespace | |
| 23 | |
| 24 struct MessageInTransit::PrivateStructForCompileAsserts { | 19 struct MessageInTransit::PrivateStructForCompileAsserts { |
| 25 // The size of |Header| must be appropriate to maintain alignment of the | 20 // The size of |Header| must be a multiple of the alignment. |
| 26 // following data. | |
| 27 COMPILE_ASSERT(sizeof(Header) % kMessageAlignment == 0, | 21 COMPILE_ASSERT(sizeof(Header) % kMessageAlignment == 0, |
| 28 sizeof_MessageInTransit_Header_invalid); | 22 sizeof_MessageInTransit_Header_invalid); |
| 29 // Avoid dangerous situations, but making sure that the size of the "header" + | 23 // Avoid dangerous situations, but making sure that the size of the "header" + |
| 30 // the size of the data fits into a 31-bit number. | 24 // the size of the data fits into a 31-bit number. |
| 31 COMPILE_ASSERT(static_cast<uint64_t>(sizeof(Header)) + kMaxMessageNumBytes <= | 25 COMPILE_ASSERT(static_cast<uint64_t>(sizeof(Header)) + kMaxMessageNumBytes <= |
| 32 0x7fffffffULL, | 26 0x7fffffffULL, |
| 33 kMaxMessageNumBytes_too_big); | 27 kMaxMessageNumBytes_too_big); |
| 34 | 28 |
| 35 // We assume (to avoid extra rounding code) that the maximum message (data) | 29 // We assume (to avoid extra rounding code) that the maximum message (data) |
| 36 // size is a multiple of the alignment. | 30 // size is a multiple of the alignment. |
| 37 COMPILE_ASSERT(kMaxMessageNumBytes % kMessageAlignment == 0, | 31 COMPILE_ASSERT(kMaxMessageNumBytes % kMessageAlignment == 0, |
| 38 kMessageAlignment_not_a_multiple_of_alignment); | 32 kMessageAlignment_not_a_multiple_of_alignment); |
| 39 | 33 |
| 34 // The maximum serialized dispatcher size must be a multiple of the alignment. |
| 40 COMPILE_ASSERT(kMaxSerializedDispatcherSize % kMessageAlignment == 0, | 35 COMPILE_ASSERT(kMaxSerializedDispatcherSize % kMessageAlignment == 0, |
| 41 kMaxSerializedDispatcherSize_not_a_multiple_of_alignment); | 36 kMaxSerializedDispatcherSize_not_a_multiple_of_alignment); |
| 42 | 37 |
| 43 // The size of |HandleTableEntry| must be appropriate to maintain alignment. | 38 // The size of |HandleTableEntry| must be a multiple of the alignment. |
| 44 COMPILE_ASSERT(sizeof(HandleTableEntry) % kMessageAlignment == 0, | 39 COMPILE_ASSERT(sizeof(HandleTableEntry) % kMessageAlignment == 0, |
| 45 sizeof_MessageInTransit_HandleTableEntry_invalid); | 40 sizeof_MessageInTransit_HandleTableEntry_invalid); |
| 46 }; | 41 }; |
| 47 | 42 |
| 48 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type | 43 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type |
| 49 MessageInTransit::kTypeMessagePipeEndpoint; | 44 MessageInTransit::kTypeMessagePipeEndpoint; |
| 50 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type | 45 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type |
| 51 MessageInTransit::kTypeMessagePipe; | 46 MessageInTransit::kTypeMessagePipe; |
| 52 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type | 47 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type |
| 53 MessageInTransit::kTypeChannel; | 48 MessageInTransit::kTypeChannel; |
| 54 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype | 49 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype |
| 55 MessageInTransit::kSubtypeMessagePipeEndpointData; | 50 MessageInTransit::kSubtypeMessagePipeEndpointData; |
| 56 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype | 51 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype |
| 57 MessageInTransit::kSubtypeMessagePipePeerClosed; | 52 MessageInTransit::kSubtypeMessagePipePeerClosed; |
| 58 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId | 53 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId |
| 59 MessageInTransit::kInvalidEndpointId; | 54 MessageInTransit::kInvalidEndpointId; |
| 60 STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment; | 55 STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment; |
| 61 STATIC_CONST_MEMBER_DEFINITION const size_t | 56 STATIC_CONST_MEMBER_DEFINITION const size_t |
| 62 MessageInTransit::kMaxSerializedDispatcherSize; | 57 MessageInTransit::kMaxSerializedDispatcherSize; |
| 63 | 58 |
| 59 // For each attached (Mojo) handle, there'll be a handle table entry and |
| 60 // serialized dispatcher data. |
| 64 // static | 61 // static |
| 65 const size_t MessageInTransit::kMaxSecondaryBufferSize = kMaxMessageNumHandles * | 62 const size_t MessageInTransit::kMaxSecondaryBufferSize = kMaxMessageNumHandles * |
| 66 (sizeof(HandleTableEntry) + kMaxSerializedDispatcherSize); | 63 (sizeof(HandleTableEntry) + kMaxSerializedDispatcherSize); |
| 67 | 64 |
| 68 MessageInTransit::View::View(size_t message_size, const void* buffer) | 65 MessageInTransit::View::View(size_t message_size, const void* buffer) |
| 69 : buffer_(buffer) { | 66 : buffer_(buffer) { |
| 70 size_t next_message_size = 0; | 67 size_t next_message_size = 0; |
| 71 DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size, | 68 DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size, |
| 72 &next_message_size)); | 69 &next_message_size)); |
| 73 DCHECK_EQ(message_size, next_message_size); | 70 DCHECK_EQ(message_size, next_message_size); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 } | 246 } |
| 250 | 247 |
| 251 void* destination = static_cast<char*>(secondary_buffer_) + current_offset; | 248 void* destination = static_cast<char*>(secondary_buffer_) + current_offset; |
| 252 size_t actual_size = 0; | 249 size_t actual_size = 0; |
| 253 if (Dispatcher::MessageInTransitAccess::SerializeAndClose( | 250 if (Dispatcher::MessageInTransitAccess::SerializeAndClose( |
| 254 dispatcher, channel, destination, &actual_size)) { | 251 dispatcher, channel, destination, &actual_size)) { |
| 255 handle_table[i].type = static_cast<int32_t>(dispatcher->GetType()); | 252 handle_table[i].type = static_cast<int32_t>(dispatcher->GetType()); |
| 256 handle_table[i].offset = static_cast<uint32_t>(current_offset); | 253 handle_table[i].offset = static_cast<uint32_t>(current_offset); |
| 257 handle_table[i].size = static_cast<uint32_t>(actual_size); | 254 handle_table[i].size = static_cast<uint32_t>(actual_size); |
| 258 } else { | 255 } else { |
| 259 // (Nothing to do on failure, since |secondary_buffer_| was cleared, and | 256 // Nothing to do on failure, since |secondary_buffer_| was cleared, and |
| 260 // |kTypeUnknown| is zero.) | 257 // |kTypeUnknown| is zero. The handle was simply closed. |
| 261 // The handle will simply be closed. | |
| 262 LOG(ERROR) << "Failed to serialize handle to remote message pipe"; | 258 LOG(ERROR) << "Failed to serialize handle to remote message pipe"; |
| 263 } | 259 } |
| 264 | 260 |
| 265 current_offset += RoundUpMessageAlignment(actual_size); | 261 current_offset += RoundUpMessageAlignment(actual_size); |
| 266 DCHECK_LE(current_offset, size); | 262 DCHECK_LE(current_offset, size); |
| 267 } | 263 } |
| 268 | 264 |
| 269 UpdateTotalSize(); | 265 UpdateTotalSize(); |
| 270 } | 266 } |
| 271 | 267 |
| 268 // Note: The message's secondary buffer should have been checked by calling |
| 269 // |View::IsValid()| (on the |View|) first. |
| 272 void MessageInTransit::DeserializeDispatchers(Channel* channel) { | 270 void MessageInTransit::DeserializeDispatchers(Channel* channel) { |
| 273 DCHECK(!dispatchers_); | 271 DCHECK(!dispatchers_); |
| 274 | 272 |
| 275 // This should have been checked by calling |IsValid()| on the |View| first. | 273 // Already checked by |View::IsValid()|: |
| 276 DCHECK_LE(num_handles(), kMaxMessageNumHandles); | 274 DCHECK_LE(num_handles(), kMaxMessageNumHandles); |
| 277 | 275 |
| 278 if (!num_handles()) | 276 if (!num_handles()) |
| 279 return; | 277 return; |
| 280 | 278 |
| 281 dispatchers_.reset( | 279 dispatchers_.reset( |
| 282 new std::vector<scoped_refptr<Dispatcher> >(num_handles())); | 280 new std::vector<scoped_refptr<Dispatcher> >(num_handles())); |
| 283 | 281 |
| 284 size_t handle_table_size = num_handles() * sizeof(HandleTableEntry); | 282 size_t handle_table_size = num_handles() * sizeof(HandleTableEntry); |
| 285 if (secondary_buffer_size_ < handle_table_size) { | 283 // Already checked by |View::IsValid()|: |
| 286 LOG(ERROR) << "Serialized handle table too small"; | 284 DCHECK_LE(handle_table_size, secondary_buffer_size_); |
| 287 return; | |
| 288 } | |
| 289 | 285 |
| 290 const HandleTableEntry* handle_table = | 286 const HandleTableEntry* handle_table = |
| 291 static_cast<const HandleTableEntry*>(secondary_buffer_); | 287 static_cast<const HandleTableEntry*>(secondary_buffer_); |
| 292 for (size_t i = 0; i < num_handles(); i++) { | 288 for (size_t i = 0; i < num_handles(); i++) { |
| 293 size_t offset = handle_table[i].offset; | 289 size_t offset = handle_table[i].offset; |
| 294 size_t size = handle_table[i].size; | 290 size_t size = handle_table[i].size; |
| 295 // TODO(vtl): Sanity-check the size. | 291 // Already checked by |View::IsValid()|: |
| 296 if (offset % kMessageAlignment != 0 || offset > secondary_buffer_size_ || | 292 DCHECK_EQ(offset % kMessageAlignment, 0u); |
| 297 offset + size > secondary_buffer_size_) { | 293 DCHECK_LE(offset, secondary_buffer_size_); |
| 298 // TODO(vtl): Maybe should report error (and make it possible to kill the | 294 DCHECK_LE(offset + size, secondary_buffer_size_); |
| 299 // connection with extreme prejudice). | |
| 300 LOG(ERROR) << "Invalid serialized handle table entry"; | |
| 301 continue; | |
| 302 } | |
| 303 | 295 |
| 304 const void* source = static_cast<const char*>(secondary_buffer_) + offset; | 296 const void* source = static_cast<const char*>(secondary_buffer_) + offset; |
| 305 (*dispatchers_)[i] = Dispatcher::MessageInTransitAccess::Deserialize( | 297 (*dispatchers_)[i] = Dispatcher::MessageInTransitAccess::Deserialize( |
| 306 channel, handle_table[i].type, source, size); | 298 channel, handle_table[i].type, source, size); |
| 307 } | 299 } |
| 308 } | 300 } |
| 309 | 301 |
| 310 // Validates the secondary buffer. Returns null on success, or a human-readable | 302 // Validates the secondary buffer. Returns null on success, or a human-readable |
| 311 // error message on error. | 303 // error message on error. |
| 312 // static | 304 // static |
| 313 const char* MessageInTransit::ValidateSecondaryBuffer( | 305 const char* MessageInTransit::ValidateSecondaryBuffer( |
| 314 size_t num_handles, | 306 size_t num_handles, |
| 315 const void* secondary_buffer, | 307 const void* secondary_buffer, |
| 316 size_t secondary_buffer_size) { | 308 size_t secondary_buffer_size) { |
| 317 if (!num_handles) | 309 // Always make sure that the secondary buffer size is sane (even if we have no |
| 310 // handles); if it's not, someone's messing with us. |
| 311 if (secondary_buffer_size > kMaxSecondaryBufferSize) |
| 312 return "Message secondary buffer too large"; |
| 313 |
| 314 // Fast-path for the common case (no handles => no secondary buffer). |
| 315 if (num_handles == 0) { |
| 316 // We shouldn't have a secondary buffer in this case. |
| 317 if (secondary_buffer_size > 0) |
| 318 return "Message has no handles attached, but secondary buffer present"; |
| 318 return NULL; | 319 return NULL; |
| 320 } |
| 319 | 321 |
| 322 // Sanity-check |num_handles| (before multiplying it against anything). |
| 320 if (num_handles > kMaxMessageNumHandles) | 323 if (num_handles > kMaxMessageNumHandles) |
| 321 return "Message handle payload too large"; | 324 return "Message handle payload too large"; |
| 322 | 325 |
| 323 if (secondary_buffer_size > kMaxSecondaryBufferSize) | |
| 324 return "Message secondary buffer too large"; | |
| 325 | |
| 326 if (secondary_buffer_size < num_handles * sizeof(HandleTableEntry)) | 326 if (secondary_buffer_size < num_handles * sizeof(HandleTableEntry)) |
| 327 return "Message secondary buffer too small"; | 327 return "Message secondary buffer too small"; |
| 328 | 328 |
| 329 DCHECK(secondary_buffer); | 329 DCHECK(secondary_buffer); |
| 330 const HandleTableEntry* handle_table = | 330 const HandleTableEntry* handle_table = |
| 331 static_cast<const HandleTableEntry*>(secondary_buffer); | 331 static_cast<const HandleTableEntry*>(secondary_buffer); |
| 332 | 332 |
| 333 static const char kInvalidSerializedDispatcher[] = | 333 static const char kInvalidSerializedDispatcher[] = |
| 334 "Message contains invalid serialized dispatcher"; | 334 "Message contains invalid serialized dispatcher"; |
| 335 for (size_t i = 0; i < num_handles; i++) { | 335 for (size_t i = 0; i < num_handles; i++) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 353 | 353 |
| 354 void MessageInTransit::UpdateTotalSize() { | 354 void MessageInTransit::UpdateTotalSize() { |
| 355 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); | 355 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); |
| 356 DCHECK_EQ(secondary_buffer_size_ % kMessageAlignment, 0u); | 356 DCHECK_EQ(secondary_buffer_size_ % kMessageAlignment, 0u); |
| 357 header()->total_size = | 357 header()->total_size = |
| 358 static_cast<uint32_t>(main_buffer_size_ + secondary_buffer_size_); | 358 static_cast<uint32_t>(main_buffer_size_ + secondary_buffer_size_); |
| 359 } | 359 } |
| 360 | 360 |
| 361 } // namespace system | 361 } // namespace system |
| 362 } // namespace mojo | 362 } // namespace mojo |
| OLD | NEW |