channel_mac.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. // Copyright 2019 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. #include "mojo/core/channel.h"
  5. #include <mach/mach.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <algorithm>
  9. #include <memory>
  10. #include <tuple>
  11. #include <utility>
  12. #include <vector>
  13. #include "base/bind.h"
  14. #include "base/containers/buffer_iterator.h"
  15. #include "base/containers/circular_deque.h"
  16. #include "base/containers/span.h"
  17. #include "base/logging.h"
  18. #include "base/mac/mach_logging.h"
  19. #include "base/mac/scoped_mach_msg_destroy.h"
  20. #include "base/mac/scoped_mach_port.h"
  21. #include "base/mac/scoped_mach_vm.h"
  22. #include "base/message_loop/message_pump_for_io.h"
  23. #include "base/task/current_thread.h"
  24. #include "base/trace_event/typed_macros.h"
  25. extern "C" {
  26. kern_return_t fileport_makeport(int fd, mach_port_t*);
  27. int fileport_makefd(mach_port_t);
  28. } // extern "C"
  29. namespace mojo {
  30. namespace core {
  31. namespace {
  32. constexpr mach_msg_id_t kChannelMacHandshakeMsgId = 'mjhs';
  33. constexpr mach_msg_id_t kChannelMacInlineMsgId = 'MOJO';
  34. constexpr mach_msg_id_t kChannelMacOOLMsgId = 'MOJ+';
  35. class ChannelMac : public Channel,
  36. public base::CurrentThread::DestructionObserver,
  37. public base::MessagePumpKqueue::MachPortWatcher {
  38. public:
  39. ChannelMac(Delegate* delegate,
  40. ConnectionParams connection_params,
  41. HandlePolicy handle_policy,
  42. scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
  43. : Channel(delegate, handle_policy, DispatchBufferPolicy::kUnmanaged),
  44. self_(this),
  45. io_task_runner_(io_task_runner),
  46. watch_controller_(FROM_HERE) {
  47. PlatformHandle channel_handle;
  48. if (connection_params.server_endpoint().is_valid()) {
  49. channel_handle =
  50. connection_params.TakeServerEndpoint().TakePlatformHandle();
  51. } else {
  52. channel_handle = connection_params.TakeEndpoint().TakePlatformHandle();
  53. }
  54. if (channel_handle.is_mach_send()) {
  55. send_port_ = channel_handle.TakeMachSendRight();
  56. } else if (channel_handle.is_mach_receive()) {
  57. receive_port_ = channel_handle.TakeMachReceiveRight();
  58. } else {
  59. NOTREACHED();
  60. }
  61. }
  62. ChannelMac(const ChannelMac&) = delete;
  63. ChannelMac& operator=(const ChannelMac&) = delete;
  64. void Start() override {
  65. io_task_runner_->PostTask(
  66. FROM_HERE, base::BindOnce(&ChannelMac::StartOnIOThread, this));
  67. }
  68. void ShutDownImpl() override {
  69. io_task_runner_->PostTask(
  70. FROM_HERE, base::BindOnce(&ChannelMac::ShutDownOnIOThread, this));
  71. }
  72. void Write(MessagePtr message) override {
  73. base::AutoLock lock(write_lock_);
  74. if (reject_writes_) {
  75. return;
  76. }
  77. // If the channel is not fully established, queue pending messages.
  78. if (!handshake_done_) {
  79. pending_messages_.push_back(std::move(message));
  80. return;
  81. }
  82. // If messages are being queued, enqueue |message| and try to flush
  83. // the queue.
  84. if (send_buffer_contains_message_ || !pending_messages_.empty()) {
  85. pending_messages_.push_back(std::move(message));
  86. SendPendingMessagesLocked();
  87. return;
  88. }
  89. SendMessageLocked(std::move(message));
  90. }
  91. void LeakHandle() override {
  92. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  93. leak_handles_ = true;
  94. }
  95. bool GetReadPlatformHandles(const void* payload,
  96. size_t payload_size,
  97. size_t num_handles,
  98. const void* extra_header,
  99. size_t extra_header_size,
  100. std::vector<PlatformHandle>* handles,
  101. bool* deferred) override {
  102. // Validate the incoming handles. If validation fails, ensure they are
  103. // destroyed.
  104. std::vector<PlatformHandle> incoming_handles;
  105. std::swap(incoming_handles, incoming_handles_);
  106. if (extra_header_size <
  107. sizeof(Message::MachPortsExtraHeader) +
  108. (incoming_handles.size() * sizeof(Message::MachPortsEntry))) {
  109. return false;
  110. }
  111. const auto* mach_ports_header =
  112. reinterpret_cast<const Message::MachPortsExtraHeader*>(extra_header);
  113. if (mach_ports_header->num_ports != incoming_handles.size()) {
  114. return false;
  115. }
  116. for (uint16_t i = 0; i < mach_ports_header->num_ports; ++i) {
  117. auto type =
  118. static_cast<PlatformHandle::Type>(mach_ports_header->entries[i].type);
  119. if (type == PlatformHandle::Type::kNone) {
  120. return false;
  121. } else if (type == PlatformHandle::Type::kFd &&
  122. incoming_handles[i].is_mach_send()) {
  123. int fd = fileport_makefd(incoming_handles[i].GetMachSendRight().get());
  124. if (fd < 0) {
  125. return false;
  126. }
  127. incoming_handles[i] = PlatformHandle(base::ScopedFD(fd));
  128. } else if (type != incoming_handles[i].type()) {
  129. return false;
  130. }
  131. }
  132. *handles = std::move(incoming_handles);
  133. return true;
  134. }
  135. bool GetReadPlatformHandlesForIpcz(
  136. size_t num_handles,
  137. std::vector<PlatformHandle>& handles) override {
  138. if (incoming_handles_.size() != num_handles) {
  139. // ChannelMac messages are transmitted all at once or not at all, so this
  140. // method should always be invoked with the exact, correct number of
  141. // handles already in `incoming_handles_`.
  142. return false;
  143. }
  144. DCHECK(handles.empty());
  145. incoming_handles_.swap(handles);
  146. return true;
  147. }
  148. private:
  149. ~ChannelMac() override = default;
  150. void StartOnIOThread() {
  151. vm_address_t address = 0;
  152. const vm_size_t size = getpagesize();
  153. kern_return_t kr =
  154. vm_allocate(mach_task_self(), &address, size,
  155. VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE);
  156. MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_allocate";
  157. send_buffer_.reset(address, size);
  158. kr = vm_allocate(mach_task_self(), &address, size,
  159. VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE);
  160. MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_allocate";
  161. receive_buffer_.reset(address, size);
  162. // When a channel is created, it only has one end of communication (either
  163. // send or receive). If it was created with a receive port, the first thing
  164. // a channel does is receive a special channel-internal message containing
  165. // its peer's send right. If the channel was created with a send right, it
  166. // creates a new receive right and sends to its peer (using the send right
  167. // it was created with) a new send right to the receive right. This
  168. // establishes the bidirectional communication channel.
  169. if (send_port_ != MACH_PORT_NULL) {
  170. DCHECK(receive_port_ == MACH_PORT_NULL);
  171. CHECK(base::mac::CreateMachPort(&receive_port_, nullptr,
  172. MACH_PORT_QLIMIT_LARGE));
  173. if (!RequestSendDeadNameNotification()) {
  174. OnError(Error::kConnectionFailed);
  175. return;
  176. }
  177. SendHandshake();
  178. } else if (receive_port_ != MACH_PORT_NULL) {
  179. DCHECK(send_port_ == MACH_PORT_NULL);
  180. // Wait for the received message via the MessageLoop.
  181. } else {
  182. NOTREACHED();
  183. }
  184. base::CurrentThread::Get()->AddDestructionObserver(this);
  185. base::CurrentIOThread::Get()->WatchMachReceivePort(
  186. receive_port_.get(), &watch_controller_, this);
  187. }
  188. void ShutDownOnIOThread() {
  189. base::CurrentThread::Get()->RemoveDestructionObserver(this);
  190. watch_controller_.StopWatchingMachPort();
  191. send_buffer_.reset();
  192. receive_buffer_.reset();
  193. incoming_handles_.clear();
  194. if (leak_handles_) {
  195. std::ignore = receive_port_.release();
  196. std::ignore = send_port_.release();
  197. } else {
  198. receive_port_.reset();
  199. send_port_.reset();
  200. }
  201. // May destroy the |this| if it was the last reference.
  202. self_ = nullptr;
  203. }
  204. // Requests that the kernel notify the |receive_port_| when the receive right
  205. // connected to |send_port_| becomes a dead name. This should be called as
  206. // soon as the Channel establishes both the send and receive ports.
  207. bool RequestSendDeadNameNotification() {
  208. base::mac::ScopedMachSendRight previous;
  209. kern_return_t kr = mach_port_request_notification(
  210. mach_task_self(), send_port_.get(), MACH_NOTIFY_DEAD_NAME, 0,
  211. receive_port_.get(), MACH_MSG_TYPE_MAKE_SEND_ONCE,
  212. base::mac::ScopedMachSendRight::Receiver(previous).get());
  213. if (kr != KERN_SUCCESS) {
  214. // If port is already a dead name (i.e. the receiver is already gone),
  215. // then the channel should be shut down by the caller.
  216. MACH_LOG_IF(ERROR, kr != KERN_INVALID_ARGUMENT, kr)
  217. << "mach_port_request_notification";
  218. return false;
  219. }
  220. return true;
  221. }
  222. // SendHandshake() sends to the |receive_port_| a right to |send_port_|,
  223. // establishing bi-directional communication with the peer. After the
  224. // handshake message has been sent, this Channel can queue any pending
  225. // messages for its peer.
  226. void SendHandshake() {
  227. mach_msg_header_t message{};
  228. message.msgh_bits =
  229. MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND);
  230. message.msgh_size = sizeof(message);
  231. message.msgh_remote_port = send_port_.get();
  232. message.msgh_local_port = receive_port_.get();
  233. message.msgh_id = kChannelMacHandshakeMsgId;
  234. kern_return_t kr =
  235. mach_msg(&message, MACH_SEND_MSG, sizeof(message), 0, MACH_PORT_NULL,
  236. MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  237. if (kr != KERN_SUCCESS) {
  238. MACH_LOG(ERROR, kr) << "mach_msg send handshake";
  239. base::AutoLock lock(write_lock_);
  240. OnWriteErrorLocked(Error::kConnectionFailed);
  241. return;
  242. }
  243. base::AutoLock lock(write_lock_);
  244. handshake_done_ = true;
  245. SendPendingMessagesLocked();
  246. }
  247. // Acquires the peer's send right from the handshake message sent via
  248. // SendHandshake(). After this, bi-directional communication is established
  249. // and this Channel can send to its peer any pending messages.
  250. bool ReceiveHandshake(base::BufferIterator<const char> buffer) {
  251. if (handshake_done_) {
  252. OnError(Error::kReceivedMalformedData);
  253. return false;
  254. }
  255. DCHECK(send_port_ == MACH_PORT_NULL);
  256. auto* message = buffer.Object<mach_msg_header_t>();
  257. if (message->msgh_id != kChannelMacHandshakeMsgId ||
  258. message->msgh_local_port == MACH_PORT_NULL) {
  259. OnError(Error::kConnectionFailed);
  260. return false;
  261. }
  262. send_port_ = base::mac::ScopedMachSendRight(message->msgh_remote_port);
  263. if (!RequestSendDeadNameNotification()) {
  264. send_port_.reset();
  265. OnError(Error::kConnectionFailed);
  266. return false;
  267. }
  268. // Record the audit token of the sender. All messages received by the
  269. // channel must be from this same sender.
  270. auto* trailer = buffer.Object<mach_msg_audit_trailer_t>();
  271. peer_audit_token_ = std::make_unique<audit_token_t>();
  272. memcpy(peer_audit_token_.get(), &trailer->msgh_audit,
  273. sizeof(audit_token_t));
  274. base::AutoLock lock(write_lock_);
  275. handshake_done_ = true;
  276. SendPendingMessagesLocked();
  277. return true;
  278. }
  279. void SendPendingMessages() {
  280. base::AutoLock lock(write_lock_);
  281. SendPendingMessagesLocked();
  282. }
  283. void SendPendingMessagesLocked() {
  284. // If a previous send failed due to the receiver's kernel message queue
  285. // being full, attempt to send that failed message first.
  286. if (send_buffer_contains_message_ && !reject_writes_) {
  287. auto* header =
  288. reinterpret_cast<mach_msg_header_t*>(send_buffer_.address());
  289. if (!MachMessageSendLocked(header)) {
  290. // The send failed again. If the peer is still unable to receive,
  291. // MachMessageSendLocked() will have arranged another attempt. If an
  292. // error occurred, the channel will be shut down.
  293. return;
  294. }
  295. }
  296. // Try and send any other pending messages that were queued.
  297. while (!pending_messages_.empty() && !reject_writes_) {
  298. bool did_send = SendMessageLocked(std::move(pending_messages_.front()));
  299. // If the message failed to send because the kernel message queue is
  300. // full, the message will have been fully serialized and
  301. // |send_buffer_contains_message_| will be set to true. The Mojo message
  302. // object can be destroyed at this point.
  303. pending_messages_.pop_front();
  304. if (!did_send)
  305. break;
  306. }
  307. }
  308. bool SendMessageLocked(MessagePtr message) {
  309. DCHECK(!send_buffer_contains_message_);
  310. base::BufferIterator<char> buffer(
  311. reinterpret_cast<char*>(send_buffer_.address()), send_buffer_.size());
  312. auto* header = buffer.MutableObject<mach_msg_header_t>();
  313. *header = mach_msg_header_t{};
  314. std::vector<PlatformHandleInTransit> handles = message->TakeHandles();
  315. // Compute the total size of the message. If the message data are larger
  316. // than the allocated receive buffer, the data will be transferred out-of-
  317. // line. The receive buffer is the same size as the send buffer, but there
  318. // also needs to be room to receive the trailer.
  319. const size_t mach_header_size =
  320. sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) +
  321. (handles.size() * sizeof(mach_msg_port_descriptor_t));
  322. const size_t expected_message_size =
  323. round_msg(mach_header_size + sizeof(uint64_t) +
  324. message->data_num_bytes() + sizeof(mach_msg_audit_trailer_t));
  325. const bool transfer_message_ool =
  326. expected_message_size >= send_buffer_.size();
  327. const bool is_complex = !handles.empty() || transfer_message_ool;
  328. header->msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) |
  329. (is_complex ? MACH_MSGH_BITS_COMPLEX : 0);
  330. header->msgh_remote_port = send_port_.get();
  331. header->msgh_id =
  332. transfer_message_ool ? kChannelMacOOLMsgId : kChannelMacInlineMsgId;
  333. auto* body = buffer.MutableObject<mach_msg_body_t>();
  334. body->msgh_descriptor_count = handles.size();
  335. auto descriptors =
  336. buffer.MutableSpan<mach_msg_port_descriptor_t>(handles.size());
  337. for (size_t i = 0; i < handles.size(); ++i) {
  338. auto* descriptor = &descriptors[i];
  339. descriptor->pad1 = 0;
  340. descriptor->pad2 = 0;
  341. descriptor->type = MACH_MSG_PORT_DESCRIPTOR;
  342. PlatformHandle handle = handles[i].TakeHandle();
  343. switch (handle.type()) {
  344. case PlatformHandle::Type::kMachSend:
  345. descriptor->name = handle.ReleaseMachSendRight();
  346. descriptor->disposition = MACH_MSG_TYPE_MOVE_SEND;
  347. break;
  348. case PlatformHandle::Type::kMachReceive:
  349. descriptor->name = handle.ReleaseMachReceiveRight();
  350. descriptor->disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
  351. break;
  352. case PlatformHandle::Type::kFd: {
  353. // After putting the FD in a fileport, the kernel will keep a
  354. // reference to the opened file, and the local descriptor can be
  355. // closed.
  356. kern_return_t kr =
  357. fileport_makeport(handle.GetFD().get(), &descriptor->name);
  358. if (kr != KERN_SUCCESS) {
  359. MACH_LOG(ERROR, kr) << "fileport_makeport";
  360. OnWriteErrorLocked(Error::kDisconnected);
  361. return false;
  362. }
  363. descriptor->disposition = MACH_MSG_TYPE_MOVE_SEND;
  364. break;
  365. }
  366. default:
  367. NOTREACHED() << "Unsupported handle type "
  368. << static_cast<int>(handle.type());
  369. OnWriteErrorLocked(Error::kDisconnected);
  370. }
  371. }
  372. if (transfer_message_ool) {
  373. auto* descriptor = buffer.MutableObject<mach_msg_ool_descriptor_t>();
  374. descriptor->address = const_cast<void*>(message->data());
  375. descriptor->size = message->data_num_bytes();
  376. descriptor->copy = MACH_MSG_VIRTUAL_COPY;
  377. descriptor->deallocate = false;
  378. descriptor->pad1 = 0;
  379. descriptor->type = MACH_MSG_OOL_DESCRIPTOR;
  380. ++body->msgh_descriptor_count;
  381. } else {
  382. auto* data_size = buffer.MutableObject<uint64_t>();
  383. *data_size = message->data_num_bytes();
  384. auto data = buffer.MutableSpan<char>(message->data_num_bytes());
  385. memcpy(data.data(), message->data(), message->data_num_bytes());
  386. }
  387. header->msgh_size = round_msg(buffer.position());
  388. return MachMessageSendLocked(header);
  389. }
  390. bool MachMessageSendLocked(mach_msg_header_t* header) {
  391. kern_return_t kr = mach_msg(header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
  392. header->msgh_size, 0, MACH_PORT_NULL,
  393. /*timeout=*/0, MACH_PORT_NULL);
  394. if (kr != KERN_SUCCESS) {
  395. if (kr == MACH_SEND_TIMED_OUT) {
  396. // The kernel message queue for the peer's receive port is full, so the
  397. // send timed out. Since the send buffer contains a fully serialized
  398. // message, set a flag to indicate this condition and arrange to try
  399. // sending it again.
  400. send_buffer_contains_message_ = true;
  401. io_task_runner_->PostTask(
  402. FROM_HERE, base::BindOnce(&ChannelMac::SendPendingMessages, this));
  403. } else {
  404. // If the message failed to send for other reasons, destroy it.
  405. send_buffer_contains_message_ = false;
  406. mach_msg_destroy(header);
  407. if (kr != MACH_SEND_INVALID_DEST) {
  408. // If the message failed to send because the receiver is a dead-name,
  409. // wait for the Channel to process the dead-name notification.
  410. // Otherwise, the notification message will never be received and the
  411. // dead-name right contained within it will be leaked
  412. // (https://crbug.com/1041682). If the message failed to send for any
  413. // other reason, report an error and shut down.
  414. MACH_LOG(ERROR, kr) << "mach_msg send";
  415. OnWriteErrorLocked(Error::kDisconnected);
  416. }
  417. }
  418. return false;
  419. }
  420. send_buffer_contains_message_ = false;
  421. return true;
  422. }
  423. // base::CurrentThread::DestructionObserver:
  424. void WillDestroyCurrentMessageLoop() override {
  425. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  426. if (self_)
  427. ShutDownOnIOThread();
  428. }
  429. // base::MessagePumpKqueue::MachPortWatcher:
  430. void OnMachMessageReceived(mach_port_t port) override {
  431. TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("toplevel.ipc"), "Mojo read message");
  432. DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
  433. base::BufferIterator<const char> buffer(
  434. reinterpret_cast<const char*>(receive_buffer_.address()),
  435. receive_buffer_.size());
  436. auto* header = buffer.MutableObject<mach_msg_header_t>();
  437. *header = mach_msg_header_t{};
  438. header->msgh_size = buffer.total_size();
  439. header->msgh_local_port = receive_port_.get();
  440. const mach_msg_option_t rcv_options =
  441. MACH_RCV_MSG | MACH_RCV_TIMEOUT |
  442. MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
  443. MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
  444. kern_return_t kr =
  445. mach_msg(header, rcv_options, 0, header->msgh_size, receive_port_.get(),
  446. /*timeout=*/0, MACH_PORT_NULL);
  447. if (kr != KERN_SUCCESS) {
  448. if (kr == MACH_RCV_TIMED_OUT)
  449. return;
  450. MACH_LOG(ERROR, kr) << "mach_msg receive";
  451. OnError(Error::kDisconnected);
  452. return;
  453. }
  454. base::ScopedMachMsgDestroy scoped_message(header);
  455. if (header->msgh_id == kChannelMacHandshakeMsgId) {
  456. buffer.Seek(0);
  457. if (ReceiveHandshake(buffer))
  458. scoped_message.Disarm();
  459. return;
  460. }
  461. if (header->msgh_id == MACH_NOTIFY_DEAD_NAME) {
  462. // The DEAD_NAME notification contains a port right that must be
  463. // explicitly destroyed, as it is not carried in a descriptor.
  464. buffer.Seek(0);
  465. auto* notification = buffer.Object<mach_dead_name_notification_t>();
  466. // Verify that the kernel sent the notification.
  467. buffer.Seek(notification->not_header.msgh_size);
  468. auto* trailer = buffer.Object<mach_msg_audit_trailer_t>();
  469. static const audit_token_t kernel_audit_token = KERNEL_AUDIT_TOKEN_VALUE;
  470. if (memcmp(&trailer->msgh_audit, &kernel_audit_token,
  471. sizeof(audit_token_t)) == 0) {
  472. DCHECK(notification->not_port == send_port_);
  473. // Release the notification's send right using this scoper.
  474. base::mac::ScopedMachSendRight notify_port(notification->not_port);
  475. }
  476. OnError(Error::kDisconnected);
  477. return;
  478. } else if (header->msgh_id == MACH_NOTIFY_SEND_ONCE) {
  479. // Notification of an extant send-once right being destroyed. This is
  480. // sent for the right allocated in RequestSendDeadNameNotification(),
  481. // and no action needs to be taken. Since it is ignored, the kernel
  482. // audit token need not be checked.
  483. return;
  484. }
  485. if (header->msgh_size < sizeof(mach_msg_base_t)) {
  486. OnError(Error::kReceivedMalformedData);
  487. return;
  488. }
  489. if (peer_audit_token_) {
  490. buffer.Seek(header->msgh_size);
  491. auto* trailer = buffer.Object<mach_msg_audit_trailer_t>();
  492. if (memcmp(&trailer->msgh_audit, peer_audit_token_.get(),
  493. sizeof(audit_token_t)) != 0) {
  494. // Do not shut down the channel because this endpoint could be
  495. // accessible via the bootstrap server, which means anyone could send
  496. // messages to it.
  497. LOG(ERROR) << "Rejecting message from unauthorized peer";
  498. return;
  499. }
  500. buffer.Seek(sizeof(*header));
  501. }
  502. auto* body = buffer.Object<mach_msg_body_t>();
  503. if (((header->msgh_bits & MACH_MSGH_BITS_COMPLEX) != 0) !=
  504. (body->msgh_descriptor_count > 0)) {
  505. LOG(ERROR) << "Message complex bit does not match descriptor count";
  506. OnError(Error::kReceivedMalformedData);
  507. return;
  508. }
  509. bool transfer_message_ool = false;
  510. mach_msg_size_t mojo_handle_count = body->msgh_descriptor_count;
  511. if (header->msgh_id == kChannelMacOOLMsgId) {
  512. transfer_message_ool = true;
  513. // The number of Mojo handles to process will be one fewer, since the
  514. // message itself was transferred using OOL memory.
  515. if (body->msgh_descriptor_count < 1) {
  516. LOG(ERROR) << "OOL message does not have descriptor";
  517. OnError(Error::kReceivedMalformedData);
  518. return;
  519. }
  520. --mojo_handle_count;
  521. } else if (header->msgh_id != kChannelMacInlineMsgId) {
  522. OnError(Error::kReceivedMalformedData);
  523. return;
  524. }
  525. incoming_handles_.clear();
  526. incoming_handles_.reserve(mojo_handle_count);
  527. // Accept the descriptors into |incoming_handles_|. They will be validated
  528. // in GetReadPlatformHandles(). If the handle is accepted, the name in the
  529. // descriptor is cleared, so that it is not double-unrefed if the
  530. // |scoped_message| destroys the message on error.
  531. auto descriptors =
  532. buffer.MutableSpan<mach_msg_port_descriptor_t>(mojo_handle_count);
  533. for (auto& descriptor : descriptors) {
  534. if (descriptor.type != MACH_MSG_PORT_DESCRIPTOR) {
  535. LOG(ERROR) << "Incorrect descriptor type " << descriptor.type;
  536. OnError(Error::kReceivedMalformedData);
  537. return;
  538. }
  539. switch (descriptor.disposition) {
  540. case MACH_MSG_TYPE_MOVE_SEND:
  541. incoming_handles_.emplace_back(
  542. base::mac::ScopedMachSendRight(descriptor.name));
  543. descriptor.name = MACH_PORT_NULL;
  544. break;
  545. case MACH_MSG_TYPE_MOVE_RECEIVE:
  546. incoming_handles_.emplace_back(
  547. base::mac::ScopedMachReceiveRight(descriptor.name));
  548. descriptor.name = MACH_PORT_NULL;
  549. break;
  550. default:
  551. DLOG(ERROR) << "Unhandled descriptor disposition "
  552. << descriptor.disposition;
  553. OnError(Error::kReceivedMalformedData);
  554. return;
  555. }
  556. }
  557. base::span<const char> payload;
  558. base::mac::ScopedMachVM ool_memory;
  559. if (transfer_message_ool) {
  560. auto* descriptor = buffer.Object<mach_msg_ool_descriptor_t>();
  561. if (descriptor->type != MACH_MSG_OOL_DESCRIPTOR) {
  562. LOG(ERROR) << "Incorrect descriptor type " << descriptor->type;
  563. OnError(Error::kReceivedMalformedData);
  564. return;
  565. }
  566. payload = base::span<const char>(
  567. reinterpret_cast<const char*>(descriptor->address), descriptor->size);
  568. // The kernel page-aligns the OOL memory when performing the mach_msg on
  569. // the send side, but it preserves the original size in the descriptor.
  570. ool_memory.reset_unaligned(
  571. reinterpret_cast<vm_address_t>(descriptor->address),
  572. descriptor->size);
  573. } else {
  574. auto* data_size_ptr = buffer.Object<uint64_t>();
  575. payload = buffer.Span<const char>(*data_size_ptr);
  576. }
  577. if (payload.empty()) {
  578. OnError(Error::kReceivedMalformedData);
  579. return;
  580. }
  581. scoped_message.Disarm();
  582. size_t ignored;
  583. DispatchResult result = TryDispatchMessage(payload, &ignored);
  584. if (result != DispatchResult::kOK) {
  585. OnError(Error::kReceivedMalformedData);
  586. return;
  587. }
  588. }
  589. // Marks the channel as unaccepting of new messages and shuts it down.
  590. void OnWriteErrorLocked(Error error) {
  591. reject_writes_ = true;
  592. io_task_runner_->PostTask(
  593. FROM_HERE, base::BindOnce(&ChannelMac::OnError, this, error));
  594. }
  595. // Keeps the Channel alive at least until explicit shutdown on the IO thread.
  596. scoped_refptr<ChannelMac> self_;
  597. scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
  598. base::mac::ScopedMachReceiveRight receive_port_;
  599. base::mac::ScopedMachSendRight send_port_;
  600. // Whether to leak the above Mach ports when the channel is shut down.
  601. bool leak_handles_ = false;
  602. // Whether or not the channel-internal handshake, which establishes bi-
  603. // directional communication, is complete. If false, calls to Write() will
  604. // enqueue messages on |pending_messages_|.
  605. bool handshake_done_ = false;
  606. // If the channel was created with a receive right, the first message it
  607. // receives is the internal handshake. The audit token of the sender of the
  608. // handshake is recorded here, and all future messages are required to be
  609. // from that sender.
  610. std::unique_ptr<audit_token_t> peer_audit_token_;
  611. // IO buffer for receiving Mach messages. Only accessed on |io_task_runner_|.
  612. base::mac::ScopedMachVM receive_buffer_;
  613. // Handles that were received with a message that are validated and returned
  614. // in GetReadPlatformHandles(). Only accessed on |io_task_runner_|.
  615. std::vector<PlatformHandle> incoming_handles_;
  616. // Watch controller for |receive_port_|, calls OnMachMessageReceived() when
  617. // new messages are available.
  618. base::MessagePumpForIO::MachPortWatchController watch_controller_;
  619. // Lock that protects the following members.
  620. base::Lock write_lock_;
  621. // Whether writes should be rejected due to an internal error.
  622. bool reject_writes_ = false;
  623. // IO buffer for sending Mach messages.
  624. base::mac::ScopedMachVM send_buffer_;
  625. // If a message timed out during send in MachMessageSendLocked(), this will
  626. // be true to indicate that |send_buffer_| contains a message that must
  627. // be sent. If this is true, then other calls to Write() queue messages onto
  628. // |pending_messages_|.
  629. bool send_buffer_contains_message_ = false;
  630. // When |handshake_done_| is false or |send_buffer_contains_message_| is true,
  631. // calls to Write() will enqueue messages here.
  632. base::circular_deque<MessagePtr> pending_messages_;
  633. };
  634. } // namespace
  635. MOJO_SYSTEM_IMPL_EXPORT
  636. scoped_refptr<Channel> Channel::Create(
  637. Channel::Delegate* delegate,
  638. ConnectionParams connection_params,
  639. Channel::HandlePolicy handle_policy,
  640. scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
  641. return new ChannelMac(delegate, std::move(connection_params), handle_policy,
  642. io_task_runner);
  643. }
  644. } // namespace core
  645. } // namespace mojo