shared_buffer_dispatcher.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. // Copyright 2014 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/shared_buffer_dispatcher.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <limits>
  8. #include <memory>
  9. #include <utility>
  10. #include "base/logging.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "build/build_config.h"
  13. #include "mojo/core/configuration.h"
  14. #include "mojo/core/node_controller.h"
  15. #include "mojo/core/options_validation.h"
  16. #include "mojo/core/platform_handle_utils.h"
  17. #include "mojo/core/platform_shared_memory_mapping.h"
  18. #include "mojo/public/c/system/platform_handle.h"
  19. namespace mojo {
  20. namespace core {
  21. namespace {
  22. #pragma pack(push, 1)
  23. struct SerializedState {
  24. uint64_t num_bytes;
  25. uint32_t access_mode;
  26. uint64_t guid_high;
  27. uint64_t guid_low;
  28. uint32_t padding;
  29. };
  30. #pragma pack(pop)
  31. static_assert(sizeof(SerializedState) % 8 == 0,
  32. "Invalid SerializedState size.");
  33. } // namespace
  34. // static
  35. const MojoCreateSharedBufferOptions
  36. SharedBufferDispatcher::kDefaultCreateOptions = {
  37. static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)),
  38. MOJO_CREATE_SHARED_BUFFER_FLAG_NONE};
  39. // static
  40. MojoResult SharedBufferDispatcher::ValidateCreateOptions(
  41. const MojoCreateSharedBufferOptions* in_options,
  42. MojoCreateSharedBufferOptions* out_options) {
  43. const MojoCreateSharedBufferFlags kKnownFlags =
  44. MOJO_CREATE_SHARED_BUFFER_FLAG_NONE;
  45. *out_options = kDefaultCreateOptions;
  46. if (!in_options)
  47. return MOJO_RESULT_OK;
  48. UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options);
  49. if (!reader.is_valid())
  50. return MOJO_RESULT_INVALID_ARGUMENT;
  51. if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader))
  52. return MOJO_RESULT_OK;
  53. if ((reader.options().flags & ~kKnownFlags))
  54. return MOJO_RESULT_UNIMPLEMENTED;
  55. out_options->flags = reader.options().flags;
  56. // Checks for fields beyond |flags|:
  57. // (Nothing here yet.)
  58. return MOJO_RESULT_OK;
  59. }
  60. // static
  61. MojoResult SharedBufferDispatcher::Create(
  62. const MojoCreateSharedBufferOptions& /*validated_options*/,
  63. NodeController* node_controller,
  64. uint64_t num_bytes,
  65. scoped_refptr<SharedBufferDispatcher>* result) {
  66. if (!num_bytes)
  67. return MOJO_RESULT_INVALID_ARGUMENT;
  68. if (num_bytes > GetConfiguration().max_shared_memory_num_bytes)
  69. return MOJO_RESULT_RESOURCE_EXHAUSTED;
  70. base::WritableSharedMemoryRegion writable_region;
  71. if (node_controller) {
  72. writable_region =
  73. node_controller->CreateSharedBuffer(static_cast<size_t>(num_bytes));
  74. } else {
  75. writable_region = base::WritableSharedMemoryRegion::Create(
  76. static_cast<size_t>(num_bytes));
  77. }
  78. if (!writable_region.IsValid())
  79. return MOJO_RESULT_RESOURCE_EXHAUSTED;
  80. *result = CreateInternal(
  81. base::WritableSharedMemoryRegion::TakeHandleForSerialization(
  82. std::move(writable_region)));
  83. return MOJO_RESULT_OK;
  84. }
  85. // static
  86. MojoResult SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion(
  87. base::subtle::PlatformSharedMemoryRegion region,
  88. scoped_refptr<SharedBufferDispatcher>* result) {
  89. if (!region.IsValid())
  90. return MOJO_RESULT_INVALID_ARGUMENT;
  91. *result = CreateInternal(std::move(region));
  92. return MOJO_RESULT_OK;
  93. }
  94. // static
  95. scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize(
  96. const void* bytes,
  97. size_t num_bytes,
  98. const ports::PortName* ports,
  99. size_t num_ports,
  100. PlatformHandle* platform_handles,
  101. size_t num_platform_handles) {
  102. if (num_bytes != sizeof(SerializedState)) {
  103. AssertNotExtractingHandlesFromMessage();
  104. LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)";
  105. return nullptr;
  106. }
  107. const SerializedState* serialized_state =
  108. static_cast<const SerializedState*>(bytes);
  109. if (!serialized_state->num_bytes) {
  110. AssertNotExtractingHandlesFromMessage();
  111. LOG(ERROR)
  112. << "Invalid serialized shared buffer dispatcher (invalid num_bytes)";
  113. return nullptr;
  114. }
  115. if (num_ports) {
  116. AssertNotExtractingHandlesFromMessage();
  117. return nullptr;
  118. }
  119. PlatformHandle handles[2];
  120. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
  121. if (serialized_state->access_mode ==
  122. MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) {
  123. if (num_platform_handles != 2)
  124. return nullptr;
  125. handles[1] = std::move(platform_handles[1]);
  126. } else {
  127. if (num_platform_handles != 1)
  128. return nullptr;
  129. }
  130. #else
  131. if (num_platform_handles != 1) {
  132. AssertNotExtractingHandlesFromMessage();
  133. return nullptr;
  134. }
  135. #endif
  136. handles[0] = std::move(platform_handles[0]);
  137. base::UnguessableToken guid = base::UnguessableToken::Deserialize(
  138. serialized_state->guid_high, serialized_state->guid_low);
  139. base::subtle::PlatformSharedMemoryRegion::Mode mode;
  140. switch (serialized_state->access_mode) {
  141. case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY:
  142. mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly;
  143. break;
  144. case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE:
  145. mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable;
  146. break;
  147. case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE:
  148. mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe;
  149. break;
  150. default:
  151. AssertNotExtractingHandlesFromMessage();
  152. LOG(ERROR) << "Invalid serialized shared buffer access mode.";
  153. return nullptr;
  154. }
  155. auto region = base::subtle::PlatformSharedMemoryRegion::Take(
  156. CreateSharedMemoryRegionHandleFromPlatformHandles(std::move(handles[0]),
  157. std::move(handles[1])),
  158. mode, static_cast<size_t>(serialized_state->num_bytes), guid);
  159. if (!region.IsValid()) {
  160. AssertNotExtractingHandlesFromMessage();
  161. LOG(ERROR)
  162. << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)";
  163. return nullptr;
  164. }
  165. return CreateInternal(std::move(region));
  166. }
  167. base::subtle::PlatformSharedMemoryRegion
  168. SharedBufferDispatcher::PassPlatformSharedMemoryRegion() {
  169. base::AutoLock lock(lock_);
  170. if (!region_.IsValid() || in_transit_)
  171. return base::subtle::PlatformSharedMemoryRegion();
  172. return std::move(region_);
  173. }
  174. Dispatcher::Type SharedBufferDispatcher::GetType() const {
  175. return Type::SHARED_BUFFER;
  176. }
  177. MojoResult SharedBufferDispatcher::Close() {
  178. base::AutoLock lock(lock_);
  179. if (in_transit_)
  180. return MOJO_RESULT_INVALID_ARGUMENT;
  181. region_ = base::subtle::PlatformSharedMemoryRegion();
  182. return MOJO_RESULT_OK;
  183. }
  184. MojoResult SharedBufferDispatcher::DuplicateBufferHandle(
  185. const MojoDuplicateBufferHandleOptions* options,
  186. scoped_refptr<Dispatcher>* new_dispatcher) {
  187. MojoDuplicateBufferHandleOptions validated_options;
  188. MojoResult result = ValidateDuplicateOptions(options, &validated_options);
  189. if (result != MOJO_RESULT_OK)
  190. return result;
  191. base::AutoLock lock(lock_);
  192. if (in_transit_)
  193. return MOJO_RESULT_INVALID_ARGUMENT;
  194. if ((validated_options.flags & MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY)) {
  195. // If a read-only duplicate is requested and this handle is not already
  196. // read-only, we need to make it read-only before duplicating. If it's
  197. // unsafe it can't be made read-only, and we must fail instead.
  198. if (region_.GetMode() ==
  199. base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe) {
  200. return MOJO_RESULT_FAILED_PRECONDITION;
  201. } else if (region_.GetMode() ==
  202. base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
  203. region_ = base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
  204. base::WritableSharedMemoryRegion::ConvertToReadOnly(
  205. base::WritableSharedMemoryRegion::Deserialize(
  206. std::move(region_))));
  207. }
  208. DCHECK_EQ(region_.GetMode(),
  209. base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly);
  210. } else {
  211. // A writable duplicate was requested. If this is already a read-only handle
  212. // we have to reject. Otherwise we have to convert to unsafe to ensure that
  213. // no future read-only duplication requests can succeed.
  214. if (region_.GetMode() ==
  215. base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly) {
  216. return MOJO_RESULT_FAILED_PRECONDITION;
  217. } else if (region_.GetMode() ==
  218. base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
  219. auto handle = region_.PassPlatformHandle();
  220. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
  221. // On POSIX systems excluding Android, Fuchsia, iOS, and macOS, we
  222. // explicitly wipe out the secondary (read-only) FD from the platform
  223. // handle to repurpose it for exclusive unsafe usage.
  224. handle.readonly_fd.reset();
  225. #endif
  226. region_ = base::subtle::PlatformSharedMemoryRegion::Take(
  227. std::move(handle),
  228. base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
  229. region_.GetSize(), region_.GetGUID());
  230. }
  231. }
  232. *new_dispatcher = CreateInternal(region_.Duplicate());
  233. return MOJO_RESULT_OK;
  234. }
  235. MojoResult SharedBufferDispatcher::MapBuffer(
  236. uint64_t offset,
  237. uint64_t num_bytes,
  238. std::unique_ptr<PlatformSharedMemoryMapping>* mapping) {
  239. if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
  240. return MOJO_RESULT_INVALID_ARGUMENT;
  241. if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
  242. return MOJO_RESULT_INVALID_ARGUMENT;
  243. base::AutoLock lock(lock_);
  244. DCHECK(region_.IsValid());
  245. if (in_transit_ || num_bytes == 0 ||
  246. static_cast<size_t>(offset + num_bytes) > region_.GetSize()) {
  247. return MOJO_RESULT_INVALID_ARGUMENT;
  248. }
  249. DCHECK(mapping);
  250. *mapping = std::make_unique<PlatformSharedMemoryMapping>(
  251. &region_, static_cast<size_t>(offset), static_cast<size_t>(num_bytes));
  252. if (!(*mapping)->IsValid()) {
  253. LOG(ERROR) << "Failed to map shared memory region.";
  254. return MOJO_RESULT_RESOURCE_EXHAUSTED;
  255. }
  256. return MOJO_RESULT_OK;
  257. }
  258. MojoResult SharedBufferDispatcher::GetBufferInfo(MojoSharedBufferInfo* info) {
  259. if (!info)
  260. return MOJO_RESULT_INVALID_ARGUMENT;
  261. base::AutoLock lock(lock_);
  262. info->struct_size = sizeof(*info);
  263. info->size = region_.GetSize();
  264. return MOJO_RESULT_OK;
  265. }
  266. void SharedBufferDispatcher::StartSerialize(uint32_t* num_bytes,
  267. uint32_t* num_ports,
  268. uint32_t* num_platform_handles) {
  269. *num_bytes = sizeof(SerializedState);
  270. *num_ports = 0;
  271. *num_platform_handles = 1;
  272. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
  273. if (region_.GetMode() ==
  274. base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
  275. *num_platform_handles = 2;
  276. }
  277. #endif
  278. }
  279. bool SharedBufferDispatcher::EndSerialize(void* destination,
  280. ports::PortName* ports,
  281. PlatformHandle* handles) {
  282. SerializedState* serialized_state =
  283. static_cast<SerializedState*>(destination);
  284. base::AutoLock lock(lock_);
  285. serialized_state->num_bytes = region_.GetSize();
  286. switch (region_.GetMode()) {
  287. case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly:
  288. serialized_state->access_mode =
  289. MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY;
  290. break;
  291. case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable:
  292. serialized_state->access_mode =
  293. MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE;
  294. break;
  295. case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe:
  296. serialized_state->access_mode =
  297. MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE;
  298. break;
  299. default:
  300. NOTREACHED();
  301. return false;
  302. }
  303. const base::UnguessableToken& guid = region_.GetGUID();
  304. serialized_state->guid_high = guid.GetHighForSerialization();
  305. serialized_state->guid_low = guid.GetLowForSerialization();
  306. serialized_state->padding = 0;
  307. auto region = std::move(region_);
  308. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
  309. if (region.GetMode() ==
  310. base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
  311. PlatformHandle platform_handles[2];
  312. ExtractPlatformHandlesFromSharedMemoryRegionHandle(
  313. region.PassPlatformHandle(), &platform_handles[0],
  314. &platform_handles[1]);
  315. handles[0] = std::move(platform_handles[0]);
  316. handles[1] = std::move(platform_handles[1]);
  317. return true;
  318. }
  319. #endif
  320. PlatformHandle platform_handle;
  321. PlatformHandle ignored_handle;
  322. ExtractPlatformHandlesFromSharedMemoryRegionHandle(
  323. region.PassPlatformHandle(), &platform_handle, &ignored_handle);
  324. handles[0] = std::move(platform_handle);
  325. return true;
  326. }
  327. bool SharedBufferDispatcher::BeginTransit() {
  328. base::AutoLock lock(lock_);
  329. if (in_transit_)
  330. return false;
  331. in_transit_ = region_.IsValid();
  332. return in_transit_;
  333. }
  334. void SharedBufferDispatcher::CompleteTransitAndClose() {
  335. base::AutoLock lock(lock_);
  336. in_transit_ = false;
  337. region_ = base::subtle::PlatformSharedMemoryRegion();
  338. }
  339. void SharedBufferDispatcher::CancelTransit() {
  340. base::AutoLock lock(lock_);
  341. in_transit_ = false;
  342. }
  343. SharedBufferDispatcher::SharedBufferDispatcher(
  344. base::subtle::PlatformSharedMemoryRegion region)
  345. : region_(std::move(region)) {
  346. DCHECK(region_.IsValid());
  347. }
  348. SharedBufferDispatcher::~SharedBufferDispatcher() {
  349. DCHECK(!region_.IsValid() && !in_transit_);
  350. }
  351. // static
  352. scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::CreateInternal(
  353. base::subtle::PlatformSharedMemoryRegion region) {
  354. return base::WrapRefCounted(new SharedBufferDispatcher(std::move(region)));
  355. }
  356. // static
  357. MojoResult SharedBufferDispatcher::ValidateDuplicateOptions(
  358. const MojoDuplicateBufferHandleOptions* in_options,
  359. MojoDuplicateBufferHandleOptions* out_options) {
  360. const MojoDuplicateBufferHandleFlags kKnownFlags =
  361. MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY;
  362. static const MojoDuplicateBufferHandleOptions kDefaultOptions = {
  363. static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)),
  364. MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_NONE};
  365. *out_options = kDefaultOptions;
  366. if (!in_options)
  367. return MOJO_RESULT_OK;
  368. UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options);
  369. if (!reader.is_valid())
  370. return MOJO_RESULT_INVALID_ARGUMENT;
  371. if (!OPTIONS_STRUCT_HAS_MEMBER(MojoDuplicateBufferHandleOptions, flags,
  372. reader))
  373. return MOJO_RESULT_OK;
  374. if ((reader.options().flags & ~kKnownFlags))
  375. return MOJO_RESULT_UNIMPLEMENTED;
  376. out_options->flags = reader.options().flags;
  377. // Checks for fields beyond |flags|:
  378. // (Nothing here yet.)
  379. return MOJO_RESULT_OK;
  380. }
  381. } // namespace core
  382. } // namespace mojo