blob: 70dd04cbef6996520f864c0c1ef8a6cc0f7fca57 [file] [log] [blame]
// 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_