wrapped_platform_handle.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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/wrapped_platform_handle.h"
  5. #include <cstdint>
  6. #include <utility>
  7. #include "base/check.h"
  8. #include "base/files/scoped_file.h"
  9. #include "base/notreached.h"
  10. #include "build/build_config.h"
  11. #include "mojo/public/cpp/platform/platform_handle.h"
  12. #include "third_party/ipcz/include/ipcz/ipcz.h"
  13. #if BUILDFLAG(IS_FUCHSIA)
  14. #include <lib/fdio/fd.h>
  15. #include <lib/zx/handle.h>
  16. #include "base/fuchsia/fuchsia_logging.h"
  17. #endif
  18. #if BUILDFLAG(IS_APPLE)
  19. #include <mach/mach.h>
  20. #include "base/mac/mach_logging.h"
  21. #include "base/mac/scoped_mach_port.h"
  22. #endif
  23. namespace mojo::core::ipcz_driver {
  24. namespace {
  25. // Enumeration for different possible types of PlatformHandles that may be
  26. // wrapped by a WrappedPlatformHandle.
  27. enum class WrapperType : uint32_t {
  28. // The wrapped PlatformHandle is transmissible as-is and can pass through a
  29. // Transport unmodified.
  30. kTransmissible,
  31. #if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE)
  32. // The wrapped PlatformHandle is a file descriptor on Fuchsia or macOS/iOS,
  33. // where the Transport can only transmit Fuchsia handles or Mach port rights,
  34. // respectively.
  35. //
  36. // On Fuchsia we serialize this type of handle by replacing it with a handle
  37. // to a corresponding fdio object. On macOS/iOS we replace it with a handle to
  38. // a corresponding fileport send right. On the receiving end this deserializes
  39. // back to a file descriptor.
  40. kIndirectFileDescriptor,
  41. #endif
  42. };
  43. // Header for a serialized WrappedPlatformHandle object.
  44. struct IPCZ_ALIGN(8) WrappedPlatformHandleHeader {
  45. // The size of this structure in bytes.
  46. uint32_t size;
  47. // Indicates what specific type of handle is wrapped.
  48. WrapperType type;
  49. };
  50. #if BUILDFLAG(IS_FUCHSIA)
  51. PlatformHandle MakeFDTransmissible(base::ScopedFD fd) {
  52. zx::handle result;
  53. const zx_status_t status =
  54. fdio_fd_transfer_or_clone(fd.release(), result.reset_and_get_address());
  55. if (status != ZX_OK) {
  56. ZX_DLOG(ERROR, status) << "fdio_fd_transfer_or_clone";
  57. return {};
  58. }
  59. return PlatformHandle(std::move(result));
  60. }
  61. base::ScopedFD RecoverFDFromTransmissible(PlatformHandle handle) {
  62. base::ScopedFD fd;
  63. zx_status_t status = fdio_fd_create(handle.ReleaseHandle(),
  64. base::ScopedFD::Receiver(fd).get());
  65. if (status != ZX_OK) {
  66. ZX_DLOG(ERROR, status) << "fdio_fd_create";
  67. return {};
  68. }
  69. return fd;
  70. }
  71. #elif BUILDFLAG(IS_APPLE)
  72. extern "C" {
  73. kern_return_t fileport_makeport(int fd, mach_port_t*);
  74. int fileport_makefd(mach_port_t);
  75. } // extern "C"
  76. PlatformHandle MakeFDTransmissible(base::ScopedFD fd) {
  77. base::mac::ScopedMachSendRight port;
  78. kern_return_t kr = fileport_makeport(
  79. fd.get(), base::mac::ScopedMachSendRight::Receiver(port).get());
  80. if (kr != KERN_SUCCESS) {
  81. MACH_LOG(ERROR, kr) << "fileport_makeport";
  82. return {};
  83. }
  84. return PlatformHandle(std::move(port));
  85. }
  86. base::ScopedFD RecoverFDFromTransmissible(PlatformHandle handle) {
  87. if (!handle.is_mach_send()) {
  88. return {};
  89. }
  90. return base::ScopedFD(fileport_makefd(handle.GetMachSendRight().get()));
  91. }
  92. #endif
  93. } // namespace
  94. WrappedPlatformHandle::WrappedPlatformHandle() = default;
  95. WrappedPlatformHandle::WrappedPlatformHandle(PlatformHandle handle)
  96. : handle_(std::move(handle)) {}
  97. WrappedPlatformHandle::~WrappedPlatformHandle() = default;
  98. void WrappedPlatformHandle::Close() {
  99. handle_.reset();
  100. }
  101. bool WrappedPlatformHandle::IsSerializable() const {
  102. return true;
  103. }
  104. bool WrappedPlatformHandle::GetSerializedDimensions(Transport& transmitter,
  105. size_t& num_bytes,
  106. size_t& num_handles) {
  107. DCHECK(handle_.is_valid());
  108. num_bytes = sizeof(WrappedPlatformHandleHeader);
  109. num_handles = 1;
  110. return true;
  111. }
  112. bool WrappedPlatformHandle::Serialize(Transport& transmitter,
  113. base::span<uint8_t> data,
  114. base::span<PlatformHandle> handles) {
  115. DCHECK(handle_.is_valid());
  116. DCHECK_EQ(sizeof(WrappedPlatformHandleHeader), data.size());
  117. DCHECK_EQ(1u, handles.size());
  118. PlatformHandle handle = std::move(handle_);
  119. WrapperType type = WrapperType::kTransmissible;
  120. #if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE)
  121. if (handle.is_fd()) {
  122. type = WrapperType::kIndirectFileDescriptor;
  123. handle = MakeFDTransmissible(handle.TakeFD());
  124. }
  125. #endif
  126. auto& header = *reinterpret_cast<WrappedPlatformHandleHeader*>(data.data());
  127. header.size = sizeof(header);
  128. header.type = type;
  129. handles[0] = std::move(handle);
  130. return true;
  131. }
  132. // static
  133. scoped_refptr<WrappedPlatformHandle> WrappedPlatformHandle::Deserialize(
  134. base::span<const uint8_t> data,
  135. base::span<PlatformHandle> handles) {
  136. if (data.size() < sizeof(WrappedPlatformHandleHeader) ||
  137. handles.size() != 1) {
  138. return nullptr;
  139. }
  140. const auto& header =
  141. *reinterpret_cast<const WrappedPlatformHandleHeader*>(data.data());
  142. if (header.size < sizeof(header)) {
  143. return nullptr;
  144. }
  145. PlatformHandle handle = std::move(handles[0]);
  146. switch (header.type) {
  147. case WrapperType::kTransmissible:
  148. break;
  149. #if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE)
  150. case WrapperType::kIndirectFileDescriptor:
  151. handle = PlatformHandle(RecoverFDFromTransmissible(std::move(handle)));
  152. break;
  153. #endif
  154. default:
  155. return nullptr;
  156. }
  157. if (!handle.is_valid()) {
  158. return nullptr;
  159. }
  160. return base::MakeRefCounted<WrappedPlatformHandle>(std::move(handle));
  161. }
  162. } // namespace mojo::core::ipcz_driver