| // Copyright 2020 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef SRC_SYS_FUZZING_COMMON_SHARED_MEMORY_H_ | |
| #define SRC_SYS_FUZZING_COMMON_SHARED_MEMORY_H_ | |
| #include <fuchsia/mem/cpp/fidl.h> | |
| #include <lib/zx/vmo.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <zircon/compiler.h> | |
| #include <zircon/types.h> | |
| #include "src/lib/fxl/macros.h" | |
| #include "src/sys/fuzzing/common/async-types.h" | |
| namespace fuzzing { | |
| // This class can be used to share VMOs mapped into multiple processes. | |
| // | |
| // For example, to share a fixed length data, one process may create an object using: | |
| // SharedMemory sender; | |
| // sender.Mirror(data, size); | |
| // | |
| // To share variable-length data, |Mirror| can be replaced with |Reserve|, e.g.: | |
| // SharedMemory sender; | |
| // sender.Reserve(capacity); | |
| // | |
| // In either case, the process can created a shared VMO from the object: | |
| // zx::vmo vmo; | |
| // sender.Share(&vmo); | |
| // | |
| // It can then send it to another process via FIDL, which can link it: | |
| // SharedMemory receiver; | |
| // receiver.Link(std::move(vmo)); | |
| // | |
| // At this point, the sender can |Update| the fixed length data, or |Write| to the variable length | |
| // data. In the latter case, the receiver needs to |Read| before accessing the data with |data| and | |
| // |size|. Reading and writing this size is not guaranteed to be atomic, so callers should use some | |
| // other method to coordinate when the size changes, e.g. with an |AsyncEventPair|. | |
| // | |
| class SharedMemory final { | |
| public: | |
| SharedMemory() = default; | |
| SharedMemory(SharedMemory&& other) { *this = std::move(other); } | |
| SharedMemory& operator=(SharedMemory&& other) noexcept; | |
| ~SharedMemory(); | |
| uint8_t* data() { return data_; } | |
| size_t size() const { return size_; } | |
| size_t capacity() const { return mapped_size_; } | |
| // Resets this object, then creates a VMO of at least |capacity| bytes, maps it. The size of the | |
| // shared memory is recorded in the buffer itself, making it compatible with |Resize| and |Write|. | |
| __WARN_UNUSED_RESULT zx_status_t Reserve(size_t capacity); | |
| // Resets and configures the object so subsequent calls to |Update| copy the region of memory | |
| // described by |data| and |size|. This region of memory MUST remain valid until this object is | |
| // destroyed or reset. The primary use of this method is to share compiler-provided | |
| // instrumentation across processes. | |
| __WARN_UNUSED_RESULT zx_status_t Mirror(void* data, size_t size); | |
| // Returns a buffer containing a duplicate of the VMO backing this memory region via |out|, | |
| // suitable for sending to another process. The size is written to the ZX_PROP_VMO_CONTENT_SIZE | |
| // property of the VMO, as in |fuchsia.debugdata.Publisher|. | |
| __WARN_UNUSED_RESULT zx_status_t Share(zx::vmo* out) const; | |
| // Resets this object, then takes ownership of the |vmo| and maps it. The VMO must have been | |
| // |Share|d from an object that was |Reserve|d or |Mirror|ed. | |
| __WARN_UNUSED_RESULT zx_status_t Link(zx::vmo vmo); | |
| // Refreshes the valid region of the mapped memory. Callers should use this method before calling | |
| // |size()|. | |
| __WARN_UNUSED_RESULT zx_status_t Read(); | |
| // Replaces the contents of the VMO with the given |data|. | |
| __WARN_UNUSED_RESULT zx_status_t Write(const void* data, size_t size); | |
| // Copies data from the mirrored memory region into this object. Must only be called on an object | |
| // that was |Mirror|ed. | |
| void Update(); | |
| // Zeros the |Mirror|ed memory, if any. | |
| void Clear(); | |
| private: | |
| // Unmaps the VMO (if mapped) and closes the VMO handle. | |
| void Reset(); | |
| // Creates a new VMO with at least the given |capacity|. | |
| zx_status_t Create(size_t capacity); | |
| // Maps the current VMO into this process' address space. | |
| zx_status_t Map(); | |
| // Sets the size for the valid region of the mapped memory. | |
| zx_status_t Resize(size_t size); | |
| // If AddressSanitizer is available, this will unpoison memory up to the first ASAN alignment | |
| // boundary following the first |size| bytes. See also | |
| // https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning. | |
| void Unpoison(size_t size); | |
| // The mapped VMO backing this object. | |
| zx::vmo vmo_; | |
| // Memory region published by |Mirror|ed objects. | |
| void* mirror_ = nullptr; | |
| // Memory region shared by the mapped VMO. | |
| uint8_t* data_ = 0; | |
| // Size of the mapped region that is valid. | |
| size_t size_ = 0; | |
| // Total size of the VMO mapped into memory. | |
| size_t mapped_size_ = 0; | |
| FXL_DISALLOW_COPY_AND_ASSIGN(SharedMemory); | |
| }; | |
| } // namespace fuzzing | |
| #endif // SRC_SYS_FUZZING_COMMON_SHARED_MEMORY_H_ |