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

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

Issue 2007943003: [mojo-edk] Add some buffer checks and fix UAF on NodeChannel (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2743
Patch Set: Created 4 years, 7 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 #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
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
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
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
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