transport.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // Copyright 2022 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/ipcz_driver/transport.h"
  5. #include <utility>
  6. #include <vector>
  7. #include "base/check_op.h"
  8. #include "base/containers/stack_container.h"
  9. #include "base/memory/scoped_refptr.h"
  10. #include "base/process/process.h"
  11. #include "build/build_config.h"
  12. #include "mojo/core/core.h"
  13. #include "mojo/core/ipcz_driver/object.h"
  14. #include "mojo/core/ipcz_driver/transmissible_platform_handle.h"
  15. #include "mojo/core/ipcz_driver/wrapped_platform_handle.h"
  16. #include "mojo/public/cpp/platform/platform_channel.h"
  17. #include "mojo/public/cpp/platform/platform_channel_endpoint.h"
  18. #include "mojo/public/cpp/platform/platform_handle.h"
  19. #include "third_party/ipcz/include/ipcz/ipcz.h"
  20. namespace mojo::core::ipcz_driver {
  21. namespace {
  22. // Header serialized at the beginning of all mojo-ipcz driver objects.
  23. struct IPCZ_ALIGN(8) ObjectHeader {
  24. // The size of this header in bytes. Used for versioning.
  25. uint32_t size;
  26. // Identifies the type of object serialized.
  27. ObjectBase::Type type;
  28. #if BUILDFLAG(IS_WIN)
  29. // On Windows only, platform handles are serialized as part of object data.
  30. // This identifies how many packed HANDLE values immediately follow this
  31. // header and precede the actual object data.
  32. uint32_t num_handles;
  33. // Padding for 8-byte size alignment.
  34. uint32_t reserved;
  35. #endif
  36. };
  37. // Header for a serialized Transport object.
  38. struct IPCZ_ALIGN(8) TransportHeader {
  39. // Indicates what type of destination the other end of this serialized
  40. // transport is connected to.
  41. Transport::Destination destination;
  42. };
  43. #if BUILDFLAG(IS_WIN)
  44. void EncodeHandle(PlatformHandle& handle,
  45. const base::Process& remote_process,
  46. Transport::Destination destination,
  47. HANDLE& out_handle) {
  48. DCHECK(handle.is_valid());
  49. if (!remote_process.IsValid()) {
  50. // When sending to a broker, HANDLE values are encoded as-is. Handles are
  51. // never sent from a non-broker to another non-broker, by virtue of
  52. // Transport's Serialize() behavior forcing ipcz to relay through a broker.
  53. DCHECK_EQ(destination, Transport::kToBroker);
  54. out_handle = handle.ReleaseHandle();
  55. return;
  56. }
  57. // When sending from a broker to a non-broker, duplicate the handle to the
  58. // remote process first, then encode that duplicated value.
  59. BOOL result = ::DuplicateHandle(
  60. ::GetCurrentProcess(), handle.ReleaseHandle(), remote_process.Handle(),
  61. &out_handle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  62. DCHECK(result);
  63. }
  64. PlatformHandle DecodeHandle(HANDLE handle,
  65. const base::Process& remote_process,
  66. Transport::Destination destination) {
  67. if (!remote_process.IsValid()) {
  68. // Handles coming from a broker are already ours.
  69. DCHECK(destination == Transport::kToBroker);
  70. return PlatformHandle(base::win::ScopedHandle(handle));
  71. }
  72. // Handles coming from a non-broker to a broker must be duplicated from the
  73. // source process first.
  74. HANDLE local_dupe = INVALID_HANDLE_VALUE;
  75. ::DuplicateHandle(remote_process.Handle(), handle, ::GetCurrentProcess(),
  76. &local_dupe, 0, FALSE,
  77. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  78. return PlatformHandle(base::win::ScopedHandle(local_dupe));
  79. }
  80. #endif // BUILDFLAG(IS_WIN)
  81. } // namespace
  82. Transport::Transport(Destination destination,
  83. PlatformChannelEndpoint endpoint,
  84. base::Process remote_process)
  85. : destination_(destination),
  86. remote_process_(std::move(remote_process)),
  87. inactive_endpoint_(std::move(endpoint)) {}
  88. // static
  89. std::pair<scoped_refptr<Transport>, scoped_refptr<Transport>>
  90. Transport::CreatePair(Destination first_destination,
  91. Destination second_destination) {
  92. PlatformChannel channel;
  93. auto one = base::MakeRefCounted<Transport>(first_destination,
  94. channel.TakeLocalEndpoint());
  95. auto two = base::MakeRefCounted<Transport>(second_destination,
  96. channel.TakeRemoteEndpoint());
  97. return {one, two};
  98. }
  99. Transport::~Transport() = default;
  100. bool Transport::Activate(IpczHandle transport,
  101. IpczTransportActivityHandler activity_handler) {
  102. scoped_refptr<Channel> channel;
  103. std::vector<PendingTransmission> pending_transmissions;
  104. {
  105. base::AutoLock lock(lock_);
  106. if (channel_ || !inactive_endpoint_.is_valid()) {
  107. return false;
  108. }
  109. ipcz_transport_ = transport;
  110. activity_handler_ = activity_handler;
  111. self_reference_for_channel_ = base::WrapRefCounted(this);
  112. channel_ = Channel::CreateForIpczDriver(
  113. this, std::move(inactive_endpoint_),
  114. Core::Get()->GetNodeController()->io_task_runner());
  115. channel_->Start();
  116. if (!pending_transmissions_.empty()) {
  117. pending_transmissions_.swap(pending_transmissions);
  118. channel = channel_;
  119. }
  120. }
  121. for (auto& transmission : pending_transmissions) {
  122. channel->Write(Channel::Message::CreateIpczMessage(
  123. base::make_span(transmission.bytes), std::move(transmission.handles)));
  124. }
  125. return true;
  126. }
  127. bool Transport::Deactivate() {
  128. scoped_refptr<Channel> channel;
  129. {
  130. base::AutoLock lock(lock_);
  131. if (!channel_) {
  132. return false;
  133. }
  134. channel = std::move(channel_);
  135. }
  136. // This will post a task to the Channel's IO thread to complete shutdown. Once
  137. // the last Channel reference is dropped, it will invoke OnChannelDestroyed()
  138. // on this Transport. The Transport is kept alive in the meantime by its own
  139. // retained `self_reference_for_channel_`.
  140. channel->ShutDown();
  141. return true;
  142. }
  143. bool Transport::Transmit(base::span<const uint8_t> data,
  144. base::span<const IpczDriverHandle> handles) {
  145. #if BUILDFLAG(IS_WIN)
  146. // All Windows handles must be inlined as message data as part of object
  147. // serialization, so the driver should never attempt to transmit handles
  148. // out-of-band there.
  149. DCHECK(handles.empty());
  150. #endif
  151. std::vector<PlatformHandle> platform_handles;
  152. platform_handles.reserve(handles.size());
  153. for (IpczDriverHandle handle : handles) {
  154. auto transmissible_handle =
  155. TransmissiblePlatformHandle::TakeFromHandle(handle);
  156. DCHECK(transmissible_handle);
  157. platform_handles.push_back(transmissible_handle->TakeHandle());
  158. }
  159. scoped_refptr<Channel> channel;
  160. {
  161. base::AutoLock lock(lock_);
  162. if (inactive_endpoint_.is_valid()) {
  163. PendingTransmission transmission;
  164. transmission.bytes = std::vector<uint8_t>(data.begin(), data.end());
  165. transmission.handles = std::move(platform_handles);
  166. pending_transmissions_.push_back(std::move(transmission));
  167. return true;
  168. }
  169. if (!channel_) {
  170. return false;
  171. }
  172. channel = channel_;
  173. }
  174. channel->Write(
  175. Channel::Message::CreateIpczMessage(data, std::move(platform_handles)));
  176. return true;
  177. }
  178. IpczResult Transport::SerializeObject(ObjectBase& object,
  179. void* data,
  180. size_t* num_bytes,
  181. IpczDriverHandle* handles,
  182. size_t* num_handles) {
  183. size_t object_num_bytes;
  184. size_t object_num_handles;
  185. if (!object.GetSerializedDimensions(*this, object_num_bytes,
  186. object_num_handles)) {
  187. return IPCZ_RESULT_INVALID_ARGUMENT;
  188. }
  189. if (object_num_handles > 0 && !CanTransmitHandles()) {
  190. // Let ipcz know that it must relay this object through a broker instead of
  191. // transmitting it over this transport.
  192. return IPCZ_RESULT_PERMISSION_DENIED;
  193. }
  194. #if BUILDFLAG(IS_WIN)
  195. const size_t required_num_bytes = sizeof(ObjectHeader) + object_num_bytes +
  196. sizeof(HANDLE) * object_num_handles;
  197. const size_t required_num_handles = 0;
  198. #else
  199. const size_t required_num_bytes = sizeof(ObjectHeader) + object_num_bytes;
  200. const size_t required_num_handles = object_num_handles;
  201. #endif
  202. const size_t data_capacity = num_bytes ? *num_bytes : 0;
  203. const size_t handle_capacity = num_handles ? *num_handles : 0;
  204. if (num_bytes) {
  205. *num_bytes = required_num_bytes;
  206. }
  207. if (num_handles) {
  208. *num_handles = required_num_handles;
  209. }
  210. if (data_capacity < required_num_bytes ||
  211. handle_capacity < required_num_handles) {
  212. return IPCZ_RESULT_RESOURCE_EXHAUSTED;
  213. }
  214. auto& header = *static_cast<ObjectHeader*>(data);
  215. header.size = sizeof(header);
  216. header.type = object.type();
  217. #if BUILDFLAG(IS_WIN)
  218. header.num_handles = object_num_handles;
  219. header.reserved = 0;
  220. auto handle_data = base::make_span(reinterpret_cast<HANDLE*>(&header + 1),
  221. object_num_handles);
  222. auto object_data = base::make_span(reinterpret_cast<uint8_t*>(&header + 1) +
  223. object_num_handles * sizeof(HANDLE),
  224. object_num_bytes);
  225. #else
  226. auto object_data = base::make_span(reinterpret_cast<uint8_t*>(&header + 1),
  227. object_num_bytes);
  228. #endif
  229. // A small amount of stack storage is reserved to avoid heap allocation in the
  230. // most common cases.
  231. base::StackVector<PlatformHandle, 2> platform_handles;
  232. platform_handles->resize(object_num_handles);
  233. if (!object.Serialize(*this, object_data,
  234. base::make_span(platform_handles.container()))) {
  235. return IPCZ_RESULT_INVALID_ARGUMENT;
  236. }
  237. for (size_t i = 0; i < object_num_handles; ++i) {
  238. #if BUILDFLAG(IS_WIN)
  239. EncodeHandle(platform_handles[i], remote_process_, destination_,
  240. handle_data[i]);
  241. #else
  242. handles[i] = TransmissiblePlatformHandle::ReleaseAsHandle(
  243. base::MakeRefCounted<TransmissiblePlatformHandle>(
  244. std::move(platform_handles[i])));
  245. #endif
  246. }
  247. return IPCZ_RESULT_OK;
  248. }
  249. IpczResult Transport::DeserializeObject(
  250. base::span<const uint8_t> bytes,
  251. base::span<const IpczDriverHandle> handles,
  252. scoped_refptr<ObjectBase>& object) {
  253. if (bytes.size() < sizeof(ObjectHeader)) {
  254. return IPCZ_RESULT_INVALID_ARGUMENT;
  255. }
  256. const auto& header = *reinterpret_cast<const ObjectHeader*>(bytes.data());
  257. const uint32_t header_size = header.size;
  258. if (header_size < sizeof(ObjectHeader) || header_size > bytes.size()) {
  259. return IPCZ_RESULT_INVALID_ARGUMENT;
  260. }
  261. #if BUILDFLAG(IS_WIN)
  262. DCHECK(handles.empty());
  263. size_t num_handles = header.num_handles;
  264. size_t available_bytes = bytes.size() - header_size;
  265. const size_t max_handles = available_bytes / sizeof(HANDLE);
  266. if (num_handles > max_handles) {
  267. return IPCZ_RESULT_INVALID_ARGUMENT;
  268. }
  269. const size_t handle_data_size = num_handles * sizeof(HANDLE);
  270. auto handle_data = base::make_span(
  271. reinterpret_cast<const HANDLE*>(bytes.data() + header_size), num_handles);
  272. auto object_data = bytes.subspan(header_size + handle_data_size);
  273. #else
  274. auto object_data = bytes.subspan(header_size);
  275. size_t num_handles = handles.size();
  276. #endif
  277. // A small amount of stack storage is reserved to avoid heap allocation in the
  278. // most common cases.
  279. base::StackVector<PlatformHandle, 2> platform_handles;
  280. platform_handles->resize(num_handles);
  281. for (size_t i = 0; i < num_handles; ++i) {
  282. #if BUILDFLAG(IS_WIN)
  283. platform_handles[i] =
  284. DecodeHandle(handle_data[i], remote_process_, destination_);
  285. #else
  286. platform_handles[i] =
  287. TransmissiblePlatformHandle::TakeFromHandle(handles[i])->TakeHandle();
  288. #endif
  289. if (!platform_handles[i].is_valid()) {
  290. return IPCZ_RESULT_INVALID_ARGUMENT;
  291. }
  292. }
  293. auto object_handles = base::make_span(platform_handles.container());
  294. switch (header.type) {
  295. case ObjectBase::kTransport:
  296. object = Transport::Deserialize(object_data, object_handles);
  297. break;
  298. case ObjectBase::kSharedBuffer:
  299. // TODO: Implement this.
  300. NOTIMPLEMENTED();
  301. return IPCZ_RESULT_UNIMPLEMENTED;
  302. case ObjectBase::kTransmissiblePlatformHandle:
  303. object =
  304. TransmissiblePlatformHandle::Deserialize(object_data, object_handles);
  305. break;
  306. case ObjectBase::kWrappedPlatformHandle:
  307. object = WrappedPlatformHandle::Deserialize(object_data, object_handles);
  308. break;
  309. default:
  310. return IPCZ_RESULT_UNIMPLEMENTED;
  311. }
  312. if (!object) {
  313. return IPCZ_RESULT_INVALID_ARGUMENT;
  314. }
  315. return IPCZ_RESULT_OK;
  316. }
  317. void Transport::Close() {
  318. Deactivate();
  319. }
  320. bool Transport::IsSerializable() const {
  321. return true;
  322. }
  323. bool Transport::GetSerializedDimensions(Transport& transmitter,
  324. size_t& num_bytes,
  325. size_t& num_handles) {
  326. num_bytes = sizeof(TransportHeader);
  327. num_handles = 1;
  328. return true;
  329. }
  330. bool Transport::Serialize(Transport& transmitter,
  331. base::span<uint8_t> data,
  332. base::span<PlatformHandle> handles) {
  333. DCHECK_EQ(sizeof(TransportHeader), data.size());
  334. auto& header = *reinterpret_cast<TransportHeader*>(data.data());
  335. header.destination = destination_;
  336. DCHECK_EQ(1u, handles.size());
  337. DCHECK(inactive_endpoint_.is_valid());
  338. handles[0] = inactive_endpoint_.TakePlatformHandle();
  339. return true;
  340. }
  341. // static
  342. scoped_refptr<Transport> Transport::Deserialize(
  343. base::span<const uint8_t> data,
  344. base::span<PlatformHandle> handles) {
  345. if (data.size() < sizeof(TransportHeader) || handles.size() < 1) {
  346. return nullptr;
  347. }
  348. const auto& header = *reinterpret_cast<const TransportHeader*>(data.data());
  349. return base::MakeRefCounted<Transport>(
  350. header.destination, PlatformChannelEndpoint(std::move(handles[0])));
  351. }
  352. bool Transport::IsIpczTransport() const {
  353. return true;
  354. }
  355. void Transport::OnChannelMessage(const void* payload,
  356. size_t payload_size,
  357. std::vector<PlatformHandle> handles) {
  358. std::vector<IpczDriverHandle> driver_handles(handles.size());
  359. for (size_t i = 0; i < handles.size(); ++i) {
  360. driver_handles[i] = TransmissiblePlatformHandle::ReleaseAsHandle(
  361. base::MakeRefCounted<TransmissiblePlatformHandle>(
  362. std::move(handles[i])));
  363. }
  364. const IpczResult result = activity_handler_(
  365. ipcz_transport_, static_cast<const uint8_t*>(payload), payload_size,
  366. driver_handles.data(), driver_handles.size(), IPCZ_NO_FLAGS, nullptr);
  367. if (result != IPCZ_RESULT_OK && result != IPCZ_RESULT_UNIMPLEMENTED) {
  368. OnChannelError(Channel::Error::kReceivedMalformedData);
  369. }
  370. }
  371. void Transport::OnChannelError(Channel::Error error) {
  372. activity_handler_(ipcz_transport_, nullptr, 0, nullptr, 0,
  373. IPCZ_TRANSPORT_ACTIVITY_ERROR, nullptr);
  374. }
  375. void Transport::OnChannelDestroyed() {
  376. activity_handler_(ipcz_transport_, nullptr, 0, nullptr, 0,
  377. IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED, nullptr);
  378. // Drop our self-reference now that the Channel is definitely done calling us.
  379. // May delete `this` as the stack unwinds.
  380. scoped_refptr<Transport> self;
  381. base::AutoLock lock(lock_);
  382. self = std::move(self_reference_for_channel_);
  383. }
  384. bool Transport::CanTransmitHandles() const {
  385. #if BUILDFLAG(IS_WIN)
  386. // On Windows, only transports with a broker on one end may transmit handles.
  387. return remote_process_.IsValid() || destination_ == kToBroker;
  388. #else
  389. return true;
  390. #endif
  391. }
  392. Transport::PendingTransmission::PendingTransmission() = default;
  393. Transport::PendingTransmission::PendingTransmission(PendingTransmission&&) =
  394. default;
  395. Transport::PendingTransmission& Transport::PendingTransmission::operator=(
  396. PendingTransmission&&) = default;
  397. Transport::PendingTransmission::~PendingTransmission() = default;
  398. } // namespace mojo::core::ipcz_driver