| OLD | NEW |
| 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 #include <memory> | 8 #include <memory> |
| 9 | 9 |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 MojoHandle* handles, | 168 MojoHandle* handles, |
| 169 uint32_t* num_handles, | 169 uint32_t* num_handles, |
| 170 MojoReadMessageFlags flags, | 170 MojoReadMessageFlags flags, |
| 171 bool read_any_size) { | 171 bool read_any_size) { |
| 172 // We can't read from a port that's closed or in transit! | 172 // We can't read from a port that's closed or in transit! |
| 173 if (port_closed_ || in_transit_) | 173 if (port_closed_ || in_transit_) |
| 174 return MOJO_RESULT_INVALID_ARGUMENT; | 174 return MOJO_RESULT_INVALID_ARGUMENT; |
| 175 | 175 |
| 176 bool no_space = false; | 176 bool no_space = false; |
| 177 bool may_discard = flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD; | 177 bool may_discard = flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD; |
| 178 bool invalid_message = false; |
| 178 | 179 |
| 179 // Grab a message if the provided handles buffer is large enough. If the input | 180 // Grab a message if the provided handles buffer is large enough. If the input |
| 180 // |num_bytes| is provided and |read_any_size| is false, we also ensure | 181 // |num_bytes| is provided and |read_any_size| is false, we also ensure |
| 181 // that it specifies a size at least as large as the next available payload. | 182 // that it specifies a size at least as large as the next available payload. |
| 182 // | 183 // |
| 183 // If |read_any_size| is true, the input value of |*num_bytes| is ignored. | 184 // If |read_any_size| is true, the input value of |*num_bytes| is ignored. |
| 184 // This flag exists to support both new and old API behavior. | 185 // This flag exists to support both new and old API behavior. |
| 185 | 186 |
| 186 ports::ScopedMessage ports_message; | 187 ports::ScopedMessage ports_message; |
| 187 int rv = node_controller_->node()->GetMessageIf( | 188 int rv = node_controller_->node()->GetMessageIf( |
| 188 port_, | 189 port_, |
| 189 [read_any_size, num_bytes, num_handles, &no_space, &may_discard]( | 190 [read_any_size, num_bytes, num_handles, &no_space, &may_discard, |
| 191 &invalid_message]( |
| 190 const ports::Message& next_message) { | 192 const ports::Message& next_message) { |
| 191 const PortsMessage& message = | 193 const PortsMessage& message = |
| 192 static_cast<const PortsMessage&>(next_message); | 194 static_cast<const PortsMessage&>(next_message); |
| 193 DCHECK_GE(message.num_payload_bytes(), sizeof(MessageHeader)); | 195 if (message.num_payload_bytes() < sizeof(MessageHeader)) { |
| 196 invalid_message = true; |
| 197 return true; |
| 198 } |
| 194 | 199 |
| 195 const MessageHeader* header = | 200 const MessageHeader* header = |
| 196 static_cast<const MessageHeader*>(message.payload_bytes()); | 201 static_cast<const MessageHeader*>(message.payload_bytes()); |
| 197 DCHECK_LE(header->header_size, message.num_payload_bytes()); | 202 if (header->header_size > message.num_payload_bytes()) { |
| 203 invalid_message = true; |
| 204 return true; |
| 205 } |
| 198 | 206 |
| 199 uint32_t bytes_to_read = 0; | 207 uint32_t bytes_to_read = 0; |
| 200 uint32_t bytes_available = | 208 uint32_t bytes_available = |
| 201 static_cast<uint32_t>(message.num_payload_bytes()) - | 209 static_cast<uint32_t>(message.num_payload_bytes()) - |
| 202 header->header_size; | 210 header->header_size; |
| 203 if (num_bytes) { | 211 if (num_bytes) { |
| 204 bytes_to_read = std::min(*num_bytes, bytes_available); | 212 bytes_to_read = std::min(*num_bytes, bytes_available); |
| 205 *num_bytes = bytes_available; | 213 *num_bytes = bytes_available; |
| 206 } | 214 } |
| 207 | 215 |
| 208 uint32_t handles_to_read = 0; | 216 uint32_t handles_to_read = 0; |
| 209 uint32_t handles_available = header->num_dispatchers; | 217 uint32_t handles_available = header->num_dispatchers; |
| 210 if (num_handles) { | 218 if (num_handles) { |
| 211 handles_to_read = std::min(*num_handles, handles_available); | 219 handles_to_read = std::min(*num_handles, handles_available); |
| 212 *num_handles = handles_available; | 220 *num_handles = handles_available; |
| 213 } | 221 } |
| 214 | 222 |
| 215 if (handles_to_read < handles_available || | 223 if (handles_to_read < handles_available || |
| 216 (!read_any_size && bytes_to_read < bytes_available)) { | 224 (!read_any_size && bytes_to_read < bytes_available)) { |
| 217 no_space = true; | 225 no_space = true; |
| 218 return may_discard; | 226 return may_discard; |
| 219 } | 227 } |
| 220 | 228 |
| 221 return true; | 229 return true; |
| 222 }, | 230 }, |
| 223 &ports_message); | 231 &ports_message); |
| 224 | 232 |
| 233 if (invalid_message) |
| 234 return MOJO_RESULT_UNKNOWN; |
| 235 |
| 225 if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) { | 236 if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) { |
| 226 if (rv == ports::ERROR_PORT_UNKNOWN || | 237 if (rv == ports::ERROR_PORT_UNKNOWN || |
| 227 rv == ports::ERROR_PORT_STATE_UNEXPECTED) | 238 rv == ports::ERROR_PORT_STATE_UNEXPECTED) |
| 228 return MOJO_RESULT_INVALID_ARGUMENT; | 239 return MOJO_RESULT_INVALID_ARGUMENT; |
| 229 | 240 |
| 230 NOTREACHED(); | 241 NOTREACHED(); |
| 231 return MOJO_RESULT_UNKNOWN; // TODO: Add a better error code here? | 242 return MOJO_RESULT_UNKNOWN; // TODO: Add a better error code here? |
| 232 } | 243 } |
| 233 | 244 |
| 234 if (no_space) { | 245 if (no_space) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 251 return MOJO_RESULT_FAILED_PRECONDITION; | 262 return MOJO_RESULT_FAILED_PRECONDITION; |
| 252 } | 263 } |
| 253 | 264 |
| 254 // Alright! We have a message and the caller has provided sufficient storage | 265 // Alright! We have a message and the caller has provided sufficient storage |
| 255 // in which to receive it. | 266 // in which to receive it. |
| 256 | 267 |
| 257 std::unique_ptr<PortsMessage> msg( | 268 std::unique_ptr<PortsMessage> msg( |
| 258 static_cast<PortsMessage*>(ports_message.release())); | 269 static_cast<PortsMessage*>(ports_message.release())); |
| 259 | 270 |
| 260 const MessageHeader* header = | 271 const MessageHeader* header = |
| 261 static_cast<const MessageHeader*>( msg->payload_bytes()); | 272 static_cast<const MessageHeader*>(msg->payload_bytes()); |
| 262 const DispatcherHeader* dispatcher_headers = | 273 const DispatcherHeader* dispatcher_headers = |
| 263 reinterpret_cast<const DispatcherHeader*>(header + 1); | 274 reinterpret_cast<const DispatcherHeader*>(header + 1); |
| 264 | 275 |
| 265 const char* dispatcher_data = reinterpret_cast<const char*>( | 276 if (header->num_dispatchers > std::numeric_limits<uint16_t>::max()) |
| 266 dispatcher_headers + header->num_dispatchers); | 277 return MOJO_RESULT_UNKNOWN; |
| 267 | 278 |
| 268 // Deserialize dispatchers. | 279 // Deserialize dispatchers. |
| 269 if (header->num_dispatchers > 0) { | 280 if (header->num_dispatchers > 0) { |
| 270 CHECK(handles); | 281 CHECK(handles); |
| 271 std::vector<DispatcherInTransit> dispatchers(header->num_dispatchers); | 282 std::vector<DispatcherInTransit> dispatchers(header->num_dispatchers); |
| 272 size_t data_payload_index = sizeof(MessageHeader) + | 283 size_t data_payload_index = sizeof(MessageHeader) + |
| 273 header->num_dispatchers * sizeof(DispatcherHeader); | 284 header->num_dispatchers * sizeof(DispatcherHeader); |
| 285 if (data_payload_index > header->header_size) |
| 286 return MOJO_RESULT_UNKNOWN; |
| 287 const char* dispatcher_data = reinterpret_cast<const char*>( |
| 288 dispatcher_headers + header->num_dispatchers); |
| 274 size_t port_index = 0; | 289 size_t port_index = 0; |
| 275 size_t platform_handle_index = 0; | 290 size_t platform_handle_index = 0; |
| 276 for (size_t i = 0; i < header->num_dispatchers; ++i) { | 291 for (size_t i = 0; i < header->num_dispatchers; ++i) { |
| 277 const DispatcherHeader& dh = dispatcher_headers[i]; | 292 const DispatcherHeader& dh = dispatcher_headers[i]; |
| 278 Type type = static_cast<Type>(dh.type); | 293 Type type = static_cast<Type>(dh.type); |
| 279 | 294 |
| 280 DCHECK_GE(msg->num_payload_bytes(), | 295 size_t next_payload_index = data_payload_index + dh.num_bytes; |
| 281 data_payload_index + dh.num_bytes); | 296 if (msg->num_payload_bytes() < next_payload_index || |
| 282 DCHECK_GE(msg->num_ports(), | 297 next_payload_index < data_payload_index) { |
| 283 port_index + dh.num_ports); | 298 return MOJO_RESULT_UNKNOWN; |
| 284 DCHECK_GE(msg->num_handles(), | 299 } |
| 285 platform_handle_index + dh.num_platform_handles); | 300 |
| 301 size_t next_port_index = port_index + dh.num_ports; |
| 302 if (msg->num_ports() < next_port_index || next_port_index < port_index) |
| 303 return MOJO_RESULT_UNKNOWN; |
| 304 |
| 305 size_t next_platform_handle_index = |
| 306 platform_handle_index + dh.num_platform_handles; |
| 307 if (msg->num_handles() < next_platform_handle_index || |
| 308 next_platform_handle_index < platform_handle_index) { |
| 309 return MOJO_RESULT_UNKNOWN; |
| 310 } |
| 286 | 311 |
| 287 PlatformHandle* out_handles = | 312 PlatformHandle* out_handles = |
| 288 msg->num_handles() ? msg->handles() + platform_handle_index : nullptr; | 313 msg->num_handles() ? msg->handles() + platform_handle_index : nullptr; |
| 289 dispatchers[i].dispatcher = Dispatcher::Deserialize( | 314 dispatchers[i].dispatcher = Dispatcher::Deserialize( |
| 290 type, dispatcher_data, dh.num_bytes, msg->ports() + port_index, | 315 type, dispatcher_data, dh.num_bytes, msg->ports() + port_index, |
| 291 dh.num_ports, out_handles, dh.num_platform_handles); | 316 dh.num_ports, out_handles, dh.num_platform_handles); |
| 292 if (!dispatchers[i].dispatcher) | 317 if (!dispatchers[i].dispatcher) |
| 293 return MOJO_RESULT_UNKNOWN; | 318 return MOJO_RESULT_UNKNOWN; |
| 294 | 319 |
| 295 dispatcher_data += dh.num_bytes; | 320 dispatcher_data += dh.num_bytes; |
| 296 data_payload_index += dh.num_bytes; | 321 data_payload_index = next_payload_index; |
| 297 port_index += dh.num_ports; | 322 port_index = next_port_index; |
| 298 platform_handle_index += dh.num_platform_handles; | 323 platform_handle_index = next_platform_handle_index; |
| 299 } | 324 } |
| 300 | 325 |
| 301 if (!node_controller_->core()->AddDispatchersFromTransit(dispatchers, | 326 if (!node_controller_->core()->AddDispatchersFromTransit(dispatchers, |
| 302 handles)) | 327 handles)) |
| 303 return MOJO_RESULT_UNKNOWN; | 328 return MOJO_RESULT_UNKNOWN; |
| 304 } | 329 } |
| 305 | 330 |
| 306 CHECK(msg); | 331 CHECK(msg); |
| 307 *message = MessageForTransit::WrapPortsMessage(std::move(msg)); | 332 *message = MessageForTransit::WrapPortsMessage(std::move(msg)); |
| 308 return MOJO_RESULT_OK; | 333 return MOJO_RESULT_OK; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 << " endpoint " << endpoint_ << " [port=" << port_.name() << "]"; | 541 << " endpoint " << endpoint_ << " [port=" << port_.name() << "]"; |
| 517 } | 542 } |
| 518 } | 543 } |
| 519 #endif | 544 #endif |
| 520 | 545 |
| 521 awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock()); | 546 awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock()); |
| 522 } | 547 } |
| 523 | 548 |
| 524 } // namespace edk | 549 } // namespace edk |
| 525 } // namespace mojo | 550 } // namespace mojo |
| OLD | NEW |