platform_shared_memory_region_fuchsia.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright 2018 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 "base/memory/platform_shared_memory_region.h"
  5. #include <lib/zx/vmar.h>
  6. #include <zircon/process.h>
  7. #include <zircon/rights.h>
  8. #include "base/bits.h"
  9. #include "base/check_op.h"
  10. #include "base/fuchsia/fuchsia_logging.h"
  11. #include "base/memory/page_size.h"
  12. namespace base {
  13. namespace subtle {
  14. static constexpr int kNoWriteOrExec =
  15. ZX_DEFAULT_VMO_RIGHTS &
  16. ~(ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE | ZX_RIGHT_SET_PROPERTY);
  17. // static
  18. PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
  19. zx::vmo handle,
  20. Mode mode,
  21. size_t size,
  22. const UnguessableToken& guid) {
  23. if (!handle.is_valid())
  24. return {};
  25. if (size == 0)
  26. return {};
  27. if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
  28. return {};
  29. CHECK(CheckPlatformHandlePermissionsCorrespondToMode(zx::unowned_vmo(handle),
  30. mode, size));
  31. return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
  32. }
  33. zx::unowned_vmo PlatformSharedMemoryRegion::GetPlatformHandle() const {
  34. return zx::unowned_vmo(handle_);
  35. }
  36. bool PlatformSharedMemoryRegion::IsValid() const {
  37. return handle_.is_valid();
  38. }
  39. PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() const {
  40. if (!IsValid())
  41. return {};
  42. CHECK_NE(mode_, Mode::kWritable)
  43. << "Duplicating a writable shared memory region is prohibited";
  44. zx::vmo duped_handle;
  45. zx_status_t status = handle_.duplicate(ZX_RIGHT_SAME_RIGHTS, &duped_handle);
  46. if (status != ZX_OK) {
  47. ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
  48. return {};
  49. }
  50. return PlatformSharedMemoryRegion(std::move(duped_handle), mode_, size_,
  51. guid_);
  52. }
  53. bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
  54. if (!IsValid())
  55. return false;
  56. CHECK_EQ(mode_, Mode::kWritable)
  57. << "Only writable shared memory region can be converted to read-only";
  58. zx_status_t status = handle_.replace(kNoWriteOrExec, &handle_);
  59. if (status != ZX_OK) {
  60. ZX_DLOG(ERROR, status) << "zx_handle_replace";
  61. return false;
  62. }
  63. mode_ = Mode::kReadOnly;
  64. return true;
  65. }
  66. bool PlatformSharedMemoryRegion::ConvertToUnsafe() {
  67. if (!IsValid())
  68. return false;
  69. CHECK_EQ(mode_, Mode::kWritable)
  70. << "Only writable shared memory region can be converted to unsafe";
  71. mode_ = Mode::kUnsafe;
  72. return true;
  73. }
  74. // static
  75. PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
  76. size_t size) {
  77. if (size == 0)
  78. return {};
  79. // Aligning may overflow so check that the result doesn't decrease.
  80. size_t rounded_size = bits::AlignUp(size, GetPageSize());
  81. if (rounded_size < size ||
  82. rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
  83. return {};
  84. }
  85. CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
  86. "lead to this region being non-modifiable";
  87. zx::vmo vmo;
  88. zx_status_t status = zx::vmo::create(rounded_size, 0, &vmo);
  89. if (status != ZX_OK) {
  90. ZX_DLOG(ERROR, status) << "zx_vmo_create";
  91. return {};
  92. }
  93. // TODO(crbug.com/991805): Take base::Location from the caller and use it to
  94. // generate the name here.
  95. constexpr char kVmoName[] = "cr-shared-memory-region";
  96. status = vmo.set_property(ZX_PROP_NAME, kVmoName, strlen(kVmoName));
  97. ZX_DCHECK(status == ZX_OK, status);
  98. const int kNoExecFlags = ZX_DEFAULT_VMO_RIGHTS & ~ZX_RIGHT_EXECUTE;
  99. status = vmo.replace(kNoExecFlags, &vmo);
  100. if (status != ZX_OK) {
  101. ZX_DLOG(ERROR, status) << "zx_handle_replace";
  102. return {};
  103. }
  104. return PlatformSharedMemoryRegion(std::move(vmo), mode, size,
  105. UnguessableToken::Create());
  106. }
  107. // static
  108. bool PlatformSharedMemoryRegion::CheckPlatformHandlePermissionsCorrespondToMode(
  109. PlatformSharedMemoryHandle handle,
  110. Mode mode,
  111. size_t size) {
  112. zx_info_handle_basic_t basic = {};
  113. zx_status_t status = handle->get_info(ZX_INFO_HANDLE_BASIC, &basic,
  114. sizeof(basic), nullptr, nullptr);
  115. ZX_CHECK(status == ZX_OK, status) << "zx_object_get_info";
  116. if (basic.type != ZX_OBJ_TYPE_VMO) {
  117. // TODO(crbug.com/838365): convert to DLOG when bug fixed.
  118. LOG(ERROR) << "Received zircon handle is not a VMO";
  119. return false;
  120. }
  121. bool is_read_only = (basic.rights & (ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE)) == 0;
  122. bool expected_read_only = mode == Mode::kReadOnly;
  123. if (is_read_only != expected_read_only) {
  124. // TODO(crbug.com/838365): convert to DLOG when bug fixed.
  125. LOG(ERROR) << "VMO object has wrong access rights: it is"
  126. << (is_read_only ? " " : " not ") << "read-only but it should"
  127. << (expected_read_only ? " " : " not ") << "be";
  128. return false;
  129. }
  130. return true;
  131. }
  132. PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
  133. zx::vmo handle,
  134. Mode mode,
  135. size_t size,
  136. const UnguessableToken& guid)
  137. : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
  138. } // namespace subtle
  139. } // namespace base