1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/edk/system/channel.h"
6
7 #include <string.h>
8
9 #include <algorithm>
10 #include <limits>
11 #include <utility>
12
13 #include "base/macros.h"
14 #include "base/memory/aligned_memory.h"
15 #include "base/process/process_handle.h"
16 #include "mojo/edk/embedder/platform_handle.h"
17
18 #if defined(OS_MACOSX) && !defined(OS_IOS)
19 #include "base/mac/mach_logging.h"
20 #elif defined(OS_WIN)
21 #include "base/win/win_util.h"
22 #endif
23
24 namespace mojo {
25 namespace edk {
26
27 namespace {
28
29 static_assert(sizeof(Channel::Message::Header) % kChannelMessageAlignment == 0,
30 "Invalid Header size.");
31
32 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
33 static_assert(sizeof(Channel::Message::Header) == 8,
34 "Header must be 8 bytes on ChromeOS and Android");
35 #endif
36
37 } // namespace
38
39 const size_t kReadBufferSize = 4096;
40 const size_t kMaxUnusedReadBufferCapacity = 64 * 1024;
41 const size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
42 const size_t kMaxAttachedHandles = 128;
43
Message(size_t payload_size,size_t max_handles,Header::MessageType message_type)44 Channel::Message::Message(size_t payload_size,
45 size_t max_handles,
46 Header::MessageType message_type)
47 : max_handles_(max_handles) {
48 DCHECK_LE(max_handles_, kMaxAttachedHandles);
49
50 size_t extra_header_size = 0;
51 #if defined(OS_WIN)
52 // On Windows we serialize HANDLEs into the extra header space.
53 extra_header_size = max_handles_ * sizeof(HandleEntry);
54 #elif defined(OS_MACOSX) && !defined(OS_IOS)
55 // On OSX, some of the platform handles may be mach ports, which are
56 // serialised into the message buffer. Since there could be a mix of fds and
57 // mach ports, we store the mach ports as an <index, port> pair (of uint32_t),
58 // so that the original ordering of handles can be re-created.
59 if (max_handles) {
60 extra_header_size =
61 sizeof(MachPortsExtraHeader) + (max_handles * sizeof(MachPortsEntry));
62 }
63 #endif
64 // Pad extra header data to be aliged to |kChannelMessageAlignment| bytes.
65 if (extra_header_size % kChannelMessageAlignment) {
66 extra_header_size += kChannelMessageAlignment -
67 (extra_header_size % kChannelMessageAlignment);
68 }
69 DCHECK_EQ(0u, extra_header_size % kChannelMessageAlignment);
70 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
71 DCHECK_EQ(0u, extra_header_size);
72 #endif
73
74 size_ = sizeof(Header) + extra_header_size + payload_size;
75 data_ = static_cast<char*>(base::AlignedAlloc(size_,
76 kChannelMessageAlignment));
77 // Only zero out the header and not the payload. Since the payload is going to
78 // be memcpy'd, zeroing the payload is unnecessary work and a significant
79 // performance issue when dealing with large messages. Any sanitizer errors
80 // complaining about an uninitialized read in the payload area should be
81 // treated as an error and fixed.
82 memset(data_, 0, sizeof(Header) + extra_header_size);
83 header_ = reinterpret_cast<Header*>(data_);
84
85 DCHECK_LE(size_, std::numeric_limits<uint32_t>::max());
86 header_->num_bytes = static_cast<uint32_t>(size_);
87
88 DCHECK_LE(sizeof(Header) + extra_header_size,
89 std::numeric_limits<uint16_t>::max());
90 header_->message_type = message_type;
91 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
92 header_->num_handles = static_cast<uint16_t>(max_handles);
93 #else
94 header_->num_header_bytes =
95 static_cast<uint16_t>(sizeof(Header) + extra_header_size);
96 #endif
97
98 if (max_handles_ > 0) {
99 #if defined(OS_WIN)
100 handles_ = reinterpret_cast<HandleEntry*>(mutable_extra_header());
101 // Initialize all handles to invalid values.
102 for (size_t i = 0; i < max_handles_; ++i)
103 handles_[i].handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE);
104 #elif defined(OS_MACOSX) && !defined(OS_IOS)
105 mach_ports_header_ =
106 reinterpret_cast<MachPortsExtraHeader*>(mutable_extra_header());
107 mach_ports_header_->num_ports = 0;
108 // Initialize all handles to invalid values.
109 for (size_t i = 0; i < max_handles_; ++i) {
110 mach_ports_header_->entries[i] =
111 {0, static_cast<uint32_t>(MACH_PORT_NULL)};
112 }
113 #endif
114 }
115 }
116
~Message()117 Channel::Message::~Message() {
118 base::AlignedFree(data_);
119 }
120
121 // static
Deserialize(const void * data,size_t data_num_bytes)122 Channel::MessagePtr Channel::Message::Deserialize(const void* data,
123 size_t data_num_bytes) {
124 if (data_num_bytes < sizeof(Header))
125 return nullptr;
126
127 const Header* header = reinterpret_cast<const Header*>(data);
128 if (header->num_bytes != data_num_bytes) {
129 DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes
130 << " != " << data_num_bytes;
131 return nullptr;
132 }
133
134 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
135 size_t payload_size = data_num_bytes - sizeof(Header);
136 const char* payload = static_cast<const char*>(data) + sizeof(Header);
137 #else
138 if (header->num_bytes < header->num_header_bytes ||
139 header->num_header_bytes < sizeof(Header)) {
140 DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < "
141 << header->num_header_bytes;
142 return nullptr;
143 }
144
145 uint32_t extra_header_size = header->num_header_bytes - sizeof(Header);
146 size_t payload_size = data_num_bytes - header->num_header_bytes;
147 const char* payload =
148 static_cast<const char*>(data) + header->num_header_bytes;
149 #endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
150
151 #if defined(OS_WIN)
152 uint32_t max_handles = extra_header_size / sizeof(HandleEntry);
153 #elif defined(OS_MACOSX) && !defined(OS_IOS)
154 if (extra_header_size < sizeof(MachPortsExtraHeader)) {
155 DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < "
156 << sizeof(MachPortsExtraHeader);
157 return nullptr;
158 }
159 uint32_t max_handles = (extra_header_size - sizeof(MachPortsExtraHeader)) /
160 sizeof(MachPortsEntry);
161 #else
162 const uint32_t max_handles = 0;
163 #endif // defined(OS_WIN)
164
165 if (header->num_handles > max_handles || max_handles > kMaxAttachedHandles) {
166 DLOG(ERROR) << "Decoding invalid message:" << header->num_handles
167 << " > " << max_handles;
168 return nullptr;
169 }
170
171 MessagePtr message(new Message(payload_size, max_handles));
172 DCHECK_EQ(message->data_num_bytes(), data_num_bytes);
173
174 // Copy all payload bytes.
175 if (payload_size)
176 memcpy(message->mutable_payload(), payload, payload_size);
177
178 #if !defined(MOJO_EDK_LEGACY_PROTOCOL)
179 DCHECK_EQ(message->extra_header_size(), extra_header_size);
180 DCHECK_EQ(message->header_->num_header_bytes, header->num_header_bytes);
181
182 if (message->extra_header_size()) {
183 // Copy extra header bytes.
184 memcpy(message->mutable_extra_header(),
185 static_cast<const char*>(data) + sizeof(Header),
186 message->extra_header_size());
187 }
188 #endif
189
190 message->header_->num_handles = header->num_handles;
191 #if defined(OS_WIN)
192 ScopedPlatformHandleVectorPtr handles(
193 new PlatformHandleVector(header->num_handles));
194 for (size_t i = 0; i < header->num_handles; i++) {
195 (*handles)[i].handle = reinterpret_cast<HANDLE>(
196 static_cast<uintptr_t>(message->handles_[i].handle));
197 }
198 message->SetHandles(std::move(handles));
199 #endif
200
201 return message;
202 }
203
payload_size() const204 size_t Channel::Message::payload_size() const {
205 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
206 return header_->num_bytes - sizeof(Header);
207 #else
208 return size_ - header_->num_header_bytes;
209 #endif
210 }
211
212 #if defined(OS_MACOSX) && !defined(OS_IOS)
has_mach_ports() const213 bool Channel::Message::has_mach_ports() const {
214 if (!has_handles())
215 return false;
216
217 for (const auto& handle : (*handle_vector_)) {
218 if (handle.type == PlatformHandle::Type::MACH ||
219 handle.type == PlatformHandle::Type::MACH_NAME) {
220 return true;
221 }
222 }
223 return false;
224 }
225 #endif
226
SetHandles(ScopedPlatformHandleVectorPtr new_handles)227 void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) {
228 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
229 // Old semantics for ChromeOS and Android
230 if (header_->num_handles == 0) {
231 CHECK(!new_handles || new_handles->size() == 0);
232 return;
233 }
234 CHECK(new_handles && new_handles->size() == header_->num_handles);
235 std::swap(handle_vector_, new_handles);
236
237 #else
238 if (max_handles_ == 0) {
239 CHECK(!new_handles || new_handles->size() == 0);
240 return;
241 }
242
243 CHECK(new_handles && new_handles->size() <= max_handles_);
244 header_->num_handles = static_cast<uint16_t>(new_handles->size());
245 std::swap(handle_vector_, new_handles);
246 #if defined(OS_WIN)
247 memset(handles_, 0, extra_header_size());
248 for (size_t i = 0; i < handle_vector_->size(); i++)
249 handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle);
250 #endif // defined(OS_WIN)
251 #endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
252
253 #if defined(OS_MACOSX) && !defined(OS_IOS)
254 size_t mach_port_index = 0;
255 if (mach_ports_header_) {
256 for (size_t i = 0; i < max_handles_; ++i) {
257 mach_ports_header_->entries[i] =
258 {0, static_cast<uint32_t>(MACH_PORT_NULL)};
259 }
260 for (size_t i = 0; i < handle_vector_->size(); i++) {
261 if ((*handle_vector_)[i].type == PlatformHandle::Type::MACH ||
262 (*handle_vector_)[i].type == PlatformHandle::Type::MACH_NAME) {
263 mach_port_t port = (*handle_vector_)[i].port;
264 mach_ports_header_->entries[mach_port_index].index = i;
265 mach_ports_header_->entries[mach_port_index].mach_port = port;
266 mach_port_index++;
267 }
268 }
269 mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index);
270 }
271 #endif
272 }
273
TakeHandles()274 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() {
275 #if defined(OS_MACOSX) && !defined(OS_IOS)
276 if (mach_ports_header_) {
277 for (size_t i = 0; i < max_handles_; ++i) {
278 mach_ports_header_->entries[i] =
279 {0, static_cast<uint32_t>(MACH_PORT_NULL)};
280 }
281 mach_ports_header_->num_ports = 0;
282 }
283 header_->num_handles = 0;
284 return std::move(handle_vector_);
285 #else
286 header_->num_handles = 0;
287 return std::move(handle_vector_);
288 #endif
289 }
290
TakeHandlesForTransport()291 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() {
292 #if defined(OS_WIN)
293 // Not necessary on Windows.
294 NOTREACHED();
295 return nullptr;
296 #elif defined(OS_MACOSX) && !defined(OS_IOS)
297 if (handle_vector_) {
298 for (auto it = handle_vector_->begin(); it != handle_vector_->end(); ) {
299 if (it->type == PlatformHandle::Type::MACH ||
300 it->type == PlatformHandle::Type::MACH_NAME) {
301 // For Mach port names, we can can just leak them. They're not real
302 // ports anyways. For real ports, they're leaked because this is a child
303 // process and the remote process will take ownership.
304 it = handle_vector_->erase(it);
305 } else {
306 ++it;
307 }
308 }
309 }
310 return std::move(handle_vector_);
311 #else
312 return std::move(handle_vector_);
313 #endif
314 }
315
316 #if defined(OS_WIN)
317 // static
RewriteHandles(base::ProcessHandle from_process,base::ProcessHandle to_process,PlatformHandleVector * handles)318 bool Channel::Message::RewriteHandles(base::ProcessHandle from_process,
319 base::ProcessHandle to_process,
320 PlatformHandleVector* handles) {
321 bool success = true;
322 for (size_t i = 0; i < handles->size(); ++i) {
323 if (!(*handles)[i].is_valid()) {
324 DLOG(ERROR) << "Refusing to duplicate invalid handle.";
325 continue;
326 }
327 DCHECK_EQ((*handles)[i].owning_process, from_process);
328 BOOL result = DuplicateHandle(
329 from_process, (*handles)[i].handle, to_process,
330 &(*handles)[i].handle, 0, FALSE,
331 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
332 if (result) {
333 (*handles)[i].owning_process = to_process;
334 } else {
335 success = false;
336
337 // If handle duplication fails, the source handle will already be closed
338 // due to DUPLICATE_CLOSE_SOURCE. Replace the handle in the message with
339 // an invalid handle.
340 (*handles)[i].handle = INVALID_HANDLE_VALUE;
341 (*handles)[i].owning_process = base::GetCurrentProcessHandle();
342 }
343 }
344 return success;
345 }
346 #endif
347
348 // Helper class for managing a Channel's read buffer allocations. This maintains
349 // a single contiguous buffer with the layout:
350 //
351 // [discarded bytes][occupied bytes][unoccupied bytes]
352 //
353 // The Reserve() method ensures that a certain capacity of unoccupied bytes are
354 // available. It does not claim that capacity and only allocates new capacity
355 // when strictly necessary.
356 //
357 // Claim() marks unoccupied bytes as occupied.
358 //
359 // Discard() marks occupied bytes as discarded, signifying that their contents
360 // can be forgotten or overwritten.
361 //
362 // Realign() moves occupied bytes to the front of the buffer so that those
363 // occupied bytes are properly aligned.
364 //
365 // The most common Channel behavior in practice should result in very few
366 // allocations and copies, as memory is claimed and discarded shortly after
367 // being reserved, and future reservations will immediately reuse discarded
368 // memory.
369 class Channel::ReadBuffer {
370 public:
ReadBuffer()371 ReadBuffer() {
372 size_ = kReadBufferSize;
373 data_ = static_cast<char*>(base::AlignedAlloc(size_,
374 kChannelMessageAlignment));
375 }
376
~ReadBuffer()377 ~ReadBuffer() {
378 DCHECK(data_);
379 base::AlignedFree(data_);
380 }
381
occupied_bytes() const382 const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
383
num_occupied_bytes() const384 size_t num_occupied_bytes() const {
385 return num_occupied_bytes_ - num_discarded_bytes_;
386 }
387
388 // Ensures the ReadBuffer has enough contiguous space allocated to hold
389 // |num_bytes| more bytes; returns the address of the first available byte.
Reserve(size_t num_bytes)390 char* Reserve(size_t num_bytes) {
391 if (num_occupied_bytes_ + num_bytes > size_) {
392 size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes);
393 void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment);
394 memcpy(new_data, data_, num_occupied_bytes_);
395 base::AlignedFree(data_);
396 data_ = static_cast<char*>(new_data);
397 }
398
399 return data_ + num_occupied_bytes_;
400 }
401
402 // Marks the first |num_bytes| unoccupied bytes as occupied.
Claim(size_t num_bytes)403 void Claim(size_t num_bytes) {
404 DCHECK_LE(num_occupied_bytes_ + num_bytes, size_);
405 num_occupied_bytes_ += num_bytes;
406 }
407
408 // Marks the first |num_bytes| occupied bytes as discarded. This may result in
409 // shrinkage of the internal buffer, and it is not safe to assume the result
410 // of a previous Reserve() call is still valid after this.
Discard(size_t num_bytes)411 void Discard(size_t num_bytes) {
412 DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_);
413 num_discarded_bytes_ += num_bytes;
414
415 if (num_discarded_bytes_ == num_occupied_bytes_) {
416 // We can just reuse the buffer from the beginning in this common case.
417 num_discarded_bytes_ = 0;
418 num_occupied_bytes_ = 0;
419 }
420
421 if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) {
422 // In the uncommon case that we have a lot of discarded data at the
423 // front of the buffer, simply move remaining data to a smaller buffer.
424 size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_;
425 size_ = std::max(num_preserved_bytes, kReadBufferSize);
426 char* new_data = static_cast<char*>(
427 base::AlignedAlloc(size_, kChannelMessageAlignment));
428 memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes);
429 base::AlignedFree(data_);
430 data_ = new_data;
431 num_discarded_bytes_ = 0;
432 num_occupied_bytes_ = num_preserved_bytes;
433 }
434
435 if (num_occupied_bytes_ == 0 && size_ > kMaxUnusedReadBufferCapacity) {
436 // Opportunistically shrink the read buffer back down to a small size if
437 // it's grown very large. We only do this if there are no remaining
438 // unconsumed bytes in the buffer to avoid copies in most the common
439 // cases.
440 size_ = kMaxUnusedReadBufferCapacity;
441 base::AlignedFree(data_);
442 data_ = static_cast<char*>(
443 base::AlignedAlloc(size_, kChannelMessageAlignment));
444 }
445 }
446
Realign()447 void Realign() {
448 size_t num_bytes = num_occupied_bytes();
449 memmove(data_, occupied_bytes(), num_bytes);
450 num_discarded_bytes_ = 0;
451 num_occupied_bytes_ = num_bytes;
452 }
453
454 private:
455 char* data_ = nullptr;
456
457 // The total size of the allocated buffer.
458 size_t size_ = 0;
459
460 // The number of discarded bytes at the beginning of the allocated buffer.
461 size_t num_discarded_bytes_ = 0;
462
463 // The total number of occupied bytes, including discarded bytes.
464 size_t num_occupied_bytes_ = 0;
465
466 DISALLOW_COPY_AND_ASSIGN(ReadBuffer);
467 };
468
Channel(Delegate * delegate)469 Channel::Channel(Delegate* delegate)
470 : delegate_(delegate), read_buffer_(new ReadBuffer) {
471 }
472
~Channel()473 Channel::~Channel() {
474 }
475
ShutDown()476 void Channel::ShutDown() {
477 delegate_ = nullptr;
478 ShutDownImpl();
479 }
480
GetReadBuffer(size_t * buffer_capacity)481 char* Channel::GetReadBuffer(size_t *buffer_capacity) {
482 DCHECK(read_buffer_);
483 size_t required_capacity = *buffer_capacity;
484 if (!required_capacity)
485 required_capacity = kReadBufferSize;
486
487 *buffer_capacity = required_capacity;
488 return read_buffer_->Reserve(required_capacity);
489 }
490
OnReadComplete(size_t bytes_read,size_t * next_read_size_hint)491 bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
492 bool did_dispatch_message = false;
493 read_buffer_->Claim(bytes_read);
494 while (read_buffer_->num_occupied_bytes() >= sizeof(Message::Header)) {
495 // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could
496 // happen on architectures that don't allow misaligned words access (i.e.
497 // anything other than x86). Only re-align when necessary to avoid copies.
498 if (reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()) %
499 kChannelMessageAlignment != 0)
500 read_buffer_->Realign();
501
502 // We have at least enough data available for a MessageHeader.
503 const Message::Header* header = reinterpret_cast<const Message::Header*>(
504 read_buffer_->occupied_bytes());
505 if (header->num_bytes < sizeof(Message::Header) ||
506 header->num_bytes > kMaxChannelMessageSize) {
507 LOG(ERROR) << "Invalid message size: " << header->num_bytes;
508 return false;
509 }
510
511 if (read_buffer_->num_occupied_bytes() < header->num_bytes) {
512 // Not enough data available to read the full message. Hint to the
513 // implementation that it should try reading the full size of the message.
514 *next_read_size_hint =
515 header->num_bytes - read_buffer_->num_occupied_bytes();
516 return true;
517 }
518
519 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
520 size_t extra_header_size = 0;
521 const void* extra_header = nullptr;
522 size_t payload_size = header->num_bytes - sizeof(Message::Header);
523 void* payload = payload_size ? const_cast<Message::Header*>(&header[1])
524 : nullptr;
525 #else
526 if (header->num_header_bytes < sizeof(Message::Header) ||
527 header->num_header_bytes > header->num_bytes) {
528 LOG(ERROR) << "Invalid message header size: " << header->num_header_bytes;
529 return false;
530 }
531 size_t extra_header_size =
532 header->num_header_bytes - sizeof(Message::Header);
533 const void* extra_header = extra_header_size ? header + 1 : nullptr;
534 size_t payload_size = header->num_bytes - header->num_header_bytes;
535 void* payload =
536 payload_size ? reinterpret_cast<Message::Header*>(
537 const_cast<char*>(read_buffer_->occupied_bytes()) +
538 header->num_header_bytes)
539 : nullptr;
540 #endif // defined(MOJO_EDK_LEGACY_PROTOCOL)
541
542 ScopedPlatformHandleVectorPtr handles;
543 if (header->num_handles > 0) {
544 if (!GetReadPlatformHandles(header->num_handles, extra_header,
545 extra_header_size, &handles)) {
546 return false;
547 }
548
549 if (!handles) {
550 // Not enough handles available for this message.
551 break;
552 }
553 }
554
555 // We've got a complete message! Dispatch it and try another.
556 if (header->message_type != Message::Header::MessageType::NORMAL) {
557 if (!OnControlMessage(header->message_type, payload, payload_size,
558 std::move(handles))) {
559 return false;
560 }
561 did_dispatch_message = true;
562 } else if (delegate_) {
563 delegate_->OnChannelMessage(payload, payload_size, std::move(handles));
564 did_dispatch_message = true;
565 }
566
567 read_buffer_->Discard(header->num_bytes);
568 }
569
570 *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize;
571 return true;
572 }
573
OnError()574 void Channel::OnError() {
575 if (delegate_)
576 delegate_->OnChannelError();
577 }
578
OnControlMessage(Message::Header::MessageType message_type,const void * payload,size_t payload_size,ScopedPlatformHandleVectorPtr handles)579 bool Channel::OnControlMessage(Message::Header::MessageType message_type,
580 const void* payload,
581 size_t payload_size,
582 ScopedPlatformHandleVectorPtr handles) {
583 return false;
584 }
585
586 } // namespace edk
587 } // namespace mojo
588