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 |