summaryrefslogtreecommitdiffstats
path: root/ipc/chromium/src/base/shared_memory.h
blob: ec3f9fc25972aea4bd22e6c961fffd0180dc1732 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
// Copyright (c) 2006-2008 The Chromium 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 BASE_SHARED_MEMORY_H_
#define BASE_SHARED_MEMORY_H_

#include "build/build_config.h"

#if defined(OS_POSIX)
#  include <sys/types.h>
#  include <semaphore.h>
#endif
#include <string>

#include "base/basictypes.h"
#include "base/process.h"
#include "mozilla/Attributes.h"
#include "mozilla/UniquePtrExtensions.h"

namespace base {

// SharedMemoryHandle is a platform specific type which represents
// the underlying OS handle to a shared memory segment.
typedef mozilla::UniqueFileHandle SharedMemoryHandle;

// Platform abstraction for shared memory.  Provides a C++ wrapper
// around the OS primitive for a memory mapped file.
class SharedMemory {
 public:
  // Create a new SharedMemory object.
  SharedMemory() = default;

  // Create a new SharedMemory object from an existing, open
  // shared memory file.
  SharedMemory(SharedMemoryHandle init_handle, bool read_only)
      : SharedMemory() {
    SetHandle(std::move(init_handle), read_only);
  }

  // Move constructor; transfers ownership.
  SharedMemory(SharedMemory&& other) = default;

  // Destructor.  Will close any open files.
  ~SharedMemory();

  // Initialize a new SharedMemory object from an existing, open
  // shared memory file.
  bool SetHandle(SharedMemoryHandle handle, bool read_only);

  // Return true iff the given handle is valid (i.e. not the distingished
  // invalid value; NULL for a HANDLE and -1 for a file descriptor)
  static bool IsHandleValid(const SharedMemoryHandle& handle);

  // IsHandleValid applied to this object's handle.
  bool IsValid() const { return static_cast<bool>(mapped_file_); }

  // Return invalid handle (see comment above for exact definition).
  static SharedMemoryHandle NULLHandle();

  // Creates a shared memory segment.
  // Returns true on success, false on failure.
  bool Create(size_t size) { return CreateInternal(size, false); }

  // Creates a shared memory segment that supports the Freeze()
  // method; see below.  (Warning: creating freezeable shared memory
  // within a sandboxed process isn't possible on some platforms.)
  // Returns true on success, false on failure.
  bool CreateFreezeable(size_t size) { return CreateInternal(size, true); }

  // Maps the shared memory into the caller's address space.
  // Returns true on success, false otherwise.  The memory address
  // is accessed via the memory() accessor.
  //
  // If the specified fixed address is not null, it is the address that the
  // shared memory must be mapped at.  Returns false if the shared memory
  // could not be mapped at that address.
  bool Map(size_t bytes, void* fixed_address = nullptr);

  // Unmaps the shared memory from the caller's address space.
  void Unmap() { memory_ = nullptr; }

  // Get the size of the opened shared memory backing file.
  // Note:  This size is only available to the creator of the
  // shared memory, and not to those that opened shared memory
  // created externally.
  // Returns 0 if not opened or unknown.
  size_t max_size() const { return max_size_; }

  // Gets a pointer to the opened memory space if it has been
  // Mapped via Map().  Returns NULL if it is not mapped.
  void* memory() const { return memory_.get(); }

  // Extracts the underlying file handle, returning a RAII type.
  // This unmaps the memory as a side-effect (and cleans up any OS-specific
  // resources).
  mozilla::UniqueFileHandle TakeHandle() {
    mozilla::UniqueFileHandle handle = std::move(mapped_file_);
    Close();
    return handle;
  }

  // Creates a copy of the underlying file handle, returning a RAII type.
  // This operation may fail, in which case the returned file handle will be
  // invalid.
  mozilla::UniqueFileHandle CloneHandle();

  // Make the shared memory object read-only, such that it cannot be
  // written even if it's sent to an untrusted process.  If it was
  // mapped in this process, it will be unmapped.  The object must
  // have been created with CreateFreezeable(), and must not have
  // already been shared to another process.
  //
  // (See bug 1479960 comment #0 for OS-specific implementation
  // details.)
  [[nodiscard]] bool Freeze() {
    Unmap();
    return ReadOnlyCopy(this);
  }

  // Similar to Freeze(), but assigns the read-only capability to
  // another SharedMemory object and leaves this object's mapping in
  // place and writeable.  This can be used to broadcast data to
  // several untrusted readers without copying.
  //
  // The other constraints of Freeze() still apply: this object closes
  // its handle (as if by `Close(false)`), it cannot have been
  // previously shared, and the read-only handle cannot be used to
  // write the memory even by a malicious process.
  //
  // (The out parameter can currently be the same as `this` if and
  // only if the memory was unmapped, but this is an implementation
  // detail and shouldn't be relied on; for that use case Freeze()
  // should be used instead.)
  [[nodiscard]] bool ReadOnlyCopy(SharedMemory* ro_out);

  // Closes the open shared memory segment.
  // It is safe to call Close repeatedly.
  void Close(bool unmap_view = true);

  // Returns a page-aligned address at which the given number of bytes could
  // probably be mapped.  Returns NULL on error or if there is insufficient
  // contiguous address space to map the required number of pages.
  //
  // Note that there is no guarantee that the given address space will actually
  // be free by the time this function returns, since another thread might map
  // something there in the meantime.
  static void* FindFreeAddressSpace(size_t size);

#ifdef OS_POSIX
  // If named POSIX shm is being used, append the prefix (including
  // the leading '/') that would be used by a process with the given
  // pid to the given string and return true.  If not, return false.
  // (This is public so that the Linux sandboxing code can use it.)
  static bool AppendPosixShmPrefix(std::string* str, pid_t pid);
  // Similar, but simply returns whether POSIX shm is in use.
  static bool UsingPosixShm();
#endif

 private:
  bool CreateInternal(size_t size, bool freezeable);

  // Unmapping shared memory requires the mapped size on Unix but not
  // Windows; this encapsulates that difference.
  struct MappingDeleter {
#ifdef OS_POSIX
    // A default-constructed deleter must be used only with nullptr
    // (to allow default-constructing UniqueMapping).  A deleter with
    // a size must be used at most once.
    size_t mapped_size_ = 0;
    explicit MappingDeleter(size_t size) : mapped_size_(size) {}
#endif
    MappingDeleter() = default;
    void operator()(void* ptr);
  };
  using UniqueMapping = mozilla::UniquePtr<void, MappingDeleter>;

  UniqueMapping memory_;
  size_t max_size_ = 0;
  mozilla::UniqueFileHandle mapped_file_;
#if defined(OS_WIN)
  // If true indicates this came from an external source so needs extra checks
  // before being mapped.
  bool external_section_ = false;
#elif defined(OS_POSIX) && !defined(ANDROID)
  mozilla::UniqueFileHandle frozen_file_;
  bool is_memfd_ = false;
#endif
  bool read_only_ = false;
  bool freezeable_ = false;

  DISALLOW_EVIL_CONSTRUCTORS(SharedMemory);
};

}  // namespace base

#endif  // BASE_SHARED_MEMORY_H_