Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: mojo/edk/system/message_pipe_dispatcher.cc

Issue 2034183002: [mojo-edk] Add some buffer checks and fix UAF on NodeChannel (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2704
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/edk/system/data_pipe_producer_dispatcher.cc ('k') | mojo/edk/system/node_channel.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/edk/system/message_pipe_dispatcher.h" 5 #include "mojo/edk/system/message_pipe_dispatcher.h"
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "base/memory/ref_counted.h" 10 #include "base/memory/ref_counted.h"
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 MojoReadMessageFlags flags) { 318 MojoReadMessageFlags flags) {
319 { 319 {
320 base::AutoLock lock(signal_lock_); 320 base::AutoLock lock(signal_lock_);
321 // We can't read from a port that's closed or in transit! 321 // We can't read from a port that's closed or in transit!
322 if (port_closed_ || in_transit_) 322 if (port_closed_ || in_transit_)
323 return MOJO_RESULT_INVALID_ARGUMENT; 323 return MOJO_RESULT_INVALID_ARGUMENT;
324 } 324 }
325 325
326 bool no_space = false; 326 bool no_space = false;
327 bool may_discard = flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD; 327 bool may_discard = flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD;
328 bool invalid_message = false;
328 329
329 // Ensure the provided buffers are large enough to hold the next message. 330 // Ensure the provided buffers are large enough to hold the next message.
330 // GetMessageIf provides an atomic way to test the next message without 331 // GetMessageIf provides an atomic way to test the next message without
331 // committing to removing it from the port's underlying message queue until 332 // committing to removing it from the port's underlying message queue until
332 // we are sure we can consume it. 333 // we are sure we can consume it.
333 334
334 ports::ScopedMessage ports_message; 335 ports::ScopedMessage ports_message;
335 int rv = node_controller_->node()->GetMessageIf( 336 int rv = node_controller_->node()->GetMessageIf(
336 port_, 337 port_,
337 [num_bytes, num_handles, &no_space, &may_discard]( 338 [num_bytes, num_handles, &no_space, &may_discard, &invalid_message](
338 const ports::Message& next_message) { 339 const ports::Message& next_message) {
339 const PortsMessage& message = 340 const PortsMessage& message =
340 static_cast<const PortsMessage&>(next_message); 341 static_cast<const PortsMessage&>(next_message);
341 DCHECK_GE(message.num_payload_bytes(), sizeof(MessageHeader)); 342 if (message.num_payload_bytes() < sizeof(MessageHeader)) {
343 invalid_message = true;
344 return true;
345 }
342 346
343 const MessageHeader* header = 347 const MessageHeader* header =
344 static_cast<const MessageHeader*>(message.payload_bytes()); 348 static_cast<const MessageHeader*>(message.payload_bytes());
345 DCHECK_LE(header->header_size, message.num_payload_bytes()); 349 if (header->header_size > message.num_payload_bytes()) {
350 invalid_message = true;
351 return true;
352 }
346 353
347 uint32_t bytes_to_read = 0; 354 uint32_t bytes_to_read = 0;
348 uint32_t bytes_available = 355 uint32_t bytes_available =
349 static_cast<uint32_t>(message.num_payload_bytes()) - 356 static_cast<uint32_t>(message.num_payload_bytes()) -
350 header->header_size; 357 header->header_size;
351 if (num_bytes) { 358 if (num_bytes) {
352 bytes_to_read = std::min(*num_bytes, bytes_available); 359 bytes_to_read = std::min(*num_bytes, bytes_available);
353 *num_bytes = bytes_available; 360 *num_bytes = bytes_available;
354 } 361 }
355 362
356 uint32_t handles_to_read = 0; 363 uint32_t handles_to_read = 0;
357 uint32_t handles_available = header->num_dispatchers; 364 uint32_t handles_available = header->num_dispatchers;
358 if (num_handles) { 365 if (num_handles) {
359 handles_to_read = std::min(*num_handles, handles_available); 366 handles_to_read = std::min(*num_handles, handles_available);
360 *num_handles = handles_available; 367 *num_handles = handles_available;
361 } 368 }
362 369
363 if (bytes_to_read < bytes_available || 370 if (bytes_to_read < bytes_available ||
364 handles_to_read < handles_available) { 371 handles_to_read < handles_available) {
365 no_space = true; 372 no_space = true;
366 return may_discard; 373 return may_discard;
367 } 374 }
368 375
369 return true; 376 return true;
370 }, 377 },
371 &ports_message); 378 &ports_message);
372 379
380 if (invalid_message)
381 return MOJO_RESULT_UNKNOWN;
382
373 if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) { 383 if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) {
374 if (rv == ports::ERROR_PORT_UNKNOWN || 384 if (rv == ports::ERROR_PORT_UNKNOWN ||
375 rv == ports::ERROR_PORT_STATE_UNEXPECTED) 385 rv == ports::ERROR_PORT_STATE_UNEXPECTED)
376 return MOJO_RESULT_INVALID_ARGUMENT; 386 return MOJO_RESULT_INVALID_ARGUMENT;
377 387
378 NOTREACHED(); 388 NOTREACHED();
379 return MOJO_RESULT_UNKNOWN; // TODO: Add a better error code here? 389 return MOJO_RESULT_UNKNOWN; // TODO: Add a better error code here?
380 } 390 }
381 391
382 if (no_space) { 392 if (no_space) {
(...skipping 20 matching lines...) Expand all
403 // in which to receive it. 413 // in which to receive it.
404 414
405 scoped_ptr<PortsMessage> message( 415 scoped_ptr<PortsMessage> message(
406 static_cast<PortsMessage*>(ports_message.release())); 416 static_cast<PortsMessage*>(ports_message.release()));
407 417
408 const MessageHeader* header = 418 const MessageHeader* header =
409 static_cast<const MessageHeader*>(message->payload_bytes()); 419 static_cast<const MessageHeader*>(message->payload_bytes());
410 const DispatcherHeader* dispatcher_headers = 420 const DispatcherHeader* dispatcher_headers =
411 reinterpret_cast<const DispatcherHeader*>(header + 1); 421 reinterpret_cast<const DispatcherHeader*>(header + 1);
412 422
413 const char* dispatcher_data = reinterpret_cast<const char*>( 423 if (header->num_dispatchers > std::numeric_limits<uint16_t>::max())
414 dispatcher_headers + header->num_dispatchers); 424 return MOJO_RESULT_UNKNOWN;
415 425
416 // Deserialize dispatchers. 426 // Deserialize dispatchers.
417 if (header->num_dispatchers > 0) { 427 if (header->num_dispatchers > 0) {
418 CHECK(handles); 428 CHECK(handles);
419 std::vector<DispatcherInTransit> dispatchers(header->num_dispatchers); 429 std::vector<DispatcherInTransit> dispatchers(header->num_dispatchers);
420 size_t data_payload_index = sizeof(MessageHeader) + 430 size_t data_payload_index = sizeof(MessageHeader) +
421 header->num_dispatchers * sizeof(DispatcherHeader); 431 header->num_dispatchers * sizeof(DispatcherHeader);
432 if (data_payload_index > header->header_size)
433 return MOJO_RESULT_UNKNOWN;
434 const char* dispatcher_data = reinterpret_cast<const char*>(
435 dispatcher_headers + header->num_dispatchers);
422 size_t port_index = 0; 436 size_t port_index = 0;
423 size_t platform_handle_index = 0; 437 size_t platform_handle_index = 0;
424 for (size_t i = 0; i < header->num_dispatchers; ++i) { 438 for (size_t i = 0; i < header->num_dispatchers; ++i) {
425 const DispatcherHeader& dh = dispatcher_headers[i]; 439 const DispatcherHeader& dh = dispatcher_headers[i];
426 Type type = static_cast<Type>(dh.type); 440 Type type = static_cast<Type>(dh.type);
427 441
428 DCHECK_GE(message->num_payload_bytes(), 442 size_t next_payload_index = data_payload_index + dh.num_bytes;
429 data_payload_index + dh.num_bytes); 443 if (message->num_payload_bytes() < next_payload_index ||
430 DCHECK_GE(message->num_ports(), 444 next_payload_index < data_payload_index) {
431 port_index + dh.num_ports); 445 return MOJO_RESULT_UNKNOWN;
432 DCHECK_GE(message->num_handles(), 446 }
433 platform_handle_index + dh.num_platform_handles); 447
448 size_t next_port_index = port_index + dh.num_ports;
449 if (message->num_ports() < next_port_index ||
450 next_port_index < port_index)
451 return MOJO_RESULT_UNKNOWN;
452
453 size_t next_platform_handle_index =
454 platform_handle_index + dh.num_platform_handles;
455 if (message->num_handles() < next_platform_handle_index ||
456 next_platform_handle_index < platform_handle_index) {
457 return MOJO_RESULT_UNKNOWN;
458 }
434 459
435 PlatformHandle* out_handles = 460 PlatformHandle* out_handles =
436 message->num_handles() ? message->handles() + platform_handle_index 461 message->num_handles() ? message->handles() + platform_handle_index
437 : nullptr; 462 : nullptr;
438 dispatchers[i].dispatcher = Dispatcher::Deserialize( 463 dispatchers[i].dispatcher = Dispatcher::Deserialize(
439 type, dispatcher_data, dh.num_bytes, message->ports() + port_index, 464 type, dispatcher_data, dh.num_bytes, message->ports() + port_index,
440 dh.num_ports, out_handles, dh.num_platform_handles); 465 dh.num_ports, out_handles, dh.num_platform_handles);
441 if (!dispatchers[i].dispatcher) 466 if (!dispatchers[i].dispatcher)
442 return MOJO_RESULT_UNKNOWN; 467 return MOJO_RESULT_UNKNOWN;
443 468
444 dispatcher_data += dh.num_bytes; 469 dispatcher_data += dh.num_bytes;
445 data_payload_index += dh.num_bytes; 470 data_payload_index = next_payload_index;
446 port_index += dh.num_ports; 471 port_index = next_port_index;
447 platform_handle_index += dh.num_platform_handles; 472 platform_handle_index = next_platform_handle_index;
448 } 473 }
449 474
450 if (!node_controller_->core()->AddDispatchersFromTransit(dispatchers, 475 if (!node_controller_->core()->AddDispatchersFromTransit(dispatchers,
451 handles)) 476 handles))
452 return MOJO_RESULT_UNKNOWN; 477 return MOJO_RESULT_UNKNOWN;
453 } 478 }
454 479
455 // Copy message bytes. 480 // Copy message bytes.
456 DCHECK_GE(message->num_payload_bytes(), header->header_size); 481 DCHECK_GE(message->num_payload_bytes(), header->header_size);
457 const char* payload = reinterpret_cast<const char*>(message->payload_bytes()); 482 const char* payload = reinterpret_cast<const char*>(message->payload_bytes());
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 DVLOG(1) << "Peer closure detected on message pipe " << pipe_id_ 693 DVLOG(1) << "Peer closure detected on message pipe " << pipe_id_
669 << " endpoint " << endpoint_ << " [port=" << port_.name() << "]"; 694 << " endpoint " << endpoint_ << " [port=" << port_.name() << "]";
670 } 695 }
671 #endif 696 #endif
672 697
673 awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock()); 698 awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock());
674 } 699 }
675 700
676 } // namespace edk 701 } // namespace edk
677 } // namespace mojo 702 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/edk/system/data_pipe_producer_dispatcher.cc ('k') | mojo/edk/system/node_channel.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698