blob: 992e7277856f6d58206226c15585dbc5a4583c27 [file] [log] [blame]
[email protected]b05df6b2011-12-01 23:19:311// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
[email protected]99873aa2013-03-29 17:46:235#include "base/memory/shared_memory.h"
initial.commitd7cae122008-07-26 21:49:386
[email protected]6d6797eb2014-08-07 22:07:437#include <aclapi.h>
avi9beac252015-12-24 08:44:478#include <stddef.h>
9#include <stdint.h>
[email protected]6d6797eb2014-08-07 22:07:4310
initial.commitd7cae122008-07-26 21:49:3811#include "base/logging.h"
[email protected]6d6797eb2014-08-07 22:07:4312#include "base/memory/scoped_ptr.h"
[email protected]dc84fcc2014-07-24 11:42:5913#include "base/rand_util.h"
14#include "base/strings/stringprintf.h"
[email protected]a4ea1f12013-06-07 18:37:0715#include "base/strings/utf_string_conversions.h"
initial.commitd7cae122008-07-26 21:49:3816
[email protected]67ea5072013-03-28 02:02:1817namespace {
18
forshaw0474abe2015-12-18 02:16:5919typedef enum _SECTION_INFORMATION_CLASS {
20 SectionBasicInformation,
21} SECTION_INFORMATION_CLASS;
22
23typedef struct _SECTION_BASIC_INFORMATION {
24 PVOID BaseAddress;
25 ULONG Attributes;
26 LARGE_INTEGER Size;
27} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
28
29typedef ULONG(__stdcall* NtQuerySectionType)(
30 HANDLE SectionHandle,
31 SECTION_INFORMATION_CLASS SectionInformationClass,
32 PVOID SectionInformation,
33 ULONG SectionInformationLength,
34 PULONG ResultLength);
35
[email protected]67ea5072013-03-28 02:02:1836// Returns the length of the memory section starting at the supplied address.
37size_t GetMemorySectionSize(void* address) {
38 MEMORY_BASIC_INFORMATION memory_info;
39 if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
40 return 0;
41 return memory_info.RegionSize - (static_cast<char*>(address) -
42 static_cast<char*>(memory_info.AllocationBase));
43}
44
forshaw0474abe2015-12-18 02:16:5945// Checks if the section object is safe to map. At the moment this just means
46// it's not an image section.
47bool IsSectionSafeToMap(HANDLE handle) {
48 static NtQuerySectionType nt_query_section_func;
49 if (!nt_query_section_func) {
50 nt_query_section_func = reinterpret_cast<NtQuerySectionType>(
51 ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
52 DCHECK(nt_query_section_func);
53 }
54
55 // The handle must have SECTION_QUERY access for this to succeed.
56 SECTION_BASIC_INFORMATION basic_information = {};
57 ULONG status =
58 nt_query_section_func(handle, SectionBasicInformation, &basic_information,
59 sizeof(basic_information), nullptr);
60 if (status)
61 return false;
62 return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
63}
64
[email protected]67ea5072013-03-28 02:02:1865} // namespace.
66
[email protected]176aa482008-11-14 03:25:1567namespace base {
68
erikchenbaac9112015-10-23 20:20:3469SharedMemoryCreateOptions::SharedMemoryCreateOptions()
70 : name_deprecated(nullptr),
71 open_existing_deprecated(false),
72 size(0),
73 executable(false),
74 share_read_only(false) {}
75
initial.commitd7cae122008-07-26 21:49:3876SharedMemory::SharedMemory()
forshaw0474abe2015-12-18 02:16:5977 : external_section_(false),
sammc5648c852015-07-02 01:25:0078 mapped_file_(NULL),
79 mapped_size_(0),
[email protected]8cc41942010-11-05 19:16:0780 memory_(NULL),
81 read_only_(false),
forshaw0474abe2015-12-18 02:16:5982 requested_size_(0) {}
83
84SharedMemory::SharedMemory(const std::wstring& name)
85 : external_section_(false),
86 name_(name),
87 mapped_file_(NULL),
88 mapped_size_(0),
89 memory_(NULL),
90 read_only_(false),
91 requested_size_(0) {}
[email protected]8cc41942010-11-05 19:16:0792
scottmgd19b4f72015-06-19 22:51:0093SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
forshaw0474abe2015-12-18 02:16:5994 : external_section_(true),
95 mapped_file_(handle.GetHandle()),
sammc5648c852015-07-02 01:25:0096 mapped_size_(0),
initial.commitd7cae122008-07-26 21:49:3897 memory_(NULL),
98 read_only_(read_only),
sammc5648c852015-07-02 01:25:0099 requested_size_(0) {
erikchen5ea2ab72015-09-25 22:34:31100 DCHECK(!handle.IsValid() || handle.BelongsToCurrentProcess());
initial.commitd7cae122008-07-26 21:49:38101}
102
erikchen9d6889152016-01-30 00:06:24103SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
104 bool read_only,
105 ProcessHandle process)
106 : external_section_(true),
107 mapped_file_(NULL),
108 mapped_size_(0),
109 memory_(NULL),
110 read_only_(read_only),
111 requested_size_(0) {
112 DWORD access = FILE_MAP_READ | SECTION_QUERY;
113 ::DuplicateHandle(process, handle.GetHandle(), GetCurrentProcess(),
114 &mapped_file_,
115 read_only_ ? access : access | FILE_MAP_WRITE, FALSE, 0);
116}
117
initial.commitd7cae122008-07-26 21:49:38118SharedMemory::~SharedMemory() {
jbauman569918b2014-12-10 22:07:20119 Unmap();
initial.commitd7cae122008-07-26 21:49:38120 Close();
initial.commitd7cae122008-07-26 21:49:38121}
122
[email protected]5fe733de2009-02-11 18:59:20123// static
124bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
erikchen5ea2ab72015-09-25 22:34:31125 return handle.IsValid();
[email protected]5fe733de2009-02-11 18:59:20126}
127
[email protected]76aac1e2009-03-16 16:45:36128// static
129SharedMemoryHandle SharedMemory::NULLHandle() {
erikchen5ea2ab72015-09-25 22:34:31130 return SharedMemoryHandle();
[email protected]76aac1e2009-03-16 16:45:36131}
132
[email protected]b0af04c2009-05-18 17:46:31133// static
134void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
erikchen5ea2ab72015-09-25 22:34:31135 handle.Close();
[email protected]b0af04c2009-05-18 17:46:31136}
137
[email protected]c14eda92013-05-09 23:15:40138// static
139size_t SharedMemory::GetHandleLimit() {
140 // Rounded down from value reported here:
141 // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
142 return static_cast<size_t>(1 << 23);
143}
144
erikchen2096f622015-06-03 00:26:59145// static
146SharedMemoryHandle SharedMemory::DuplicateHandle(
erikchen8539d852015-05-30 01:49:19147 const SharedMemoryHandle& handle) {
erikchen5ea2ab72015-09-25 22:34:31148 DCHECK(handle.BelongsToCurrentProcess());
149 HANDLE duped_handle;
erikchen2096f622015-06-03 00:26:59150 ProcessHandle process = GetCurrentProcess();
erikchen5ea2ab72015-09-25 22:34:31151 BOOL success =
152 ::DuplicateHandle(process, handle.GetHandle(), process, &duped_handle, 0,
153 FALSE, DUPLICATE_SAME_ACCESS);
erikchen2096f622015-06-03 00:26:59154 if (success)
erikchen5ea2ab72015-09-25 22:34:31155 return SharedMemoryHandle(duped_handle, GetCurrentProcId());
156 return SharedMemoryHandle();
erikchen8539d852015-05-30 01:49:19157}
158
[email protected]374f1a82013-01-10 02:16:24159bool SharedMemory::CreateAndMapAnonymous(size_t size) {
[email protected]54e3dfa22010-10-27 18:16:06160 return CreateAnonymous(size) && Map(size);
161}
162
[email protected]b05df6b2011-12-01 23:19:31163bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
[email protected]67ea5072013-03-28 02:02:18164 // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here,
165 // wasting 32k per mapping on average.
166 static const size_t kSectionMask = 65536 - 1;
[email protected]b05df6b2011-12-01 23:19:31167 DCHECK(!options.executable);
[email protected]5d2b4492011-03-01 02:48:05168 DCHECK(!mapped_file_);
[email protected]b05df6b2011-12-01 23:19:31169 if (options.size == 0)
[email protected]54e3dfa22010-10-27 18:16:06170 return false;
initial.commitd7cae122008-07-26 21:49:38171
[email protected]67ea5072013-03-28 02:02:18172 // Check maximum accounting for overflow.
173 if (options.size >
174 static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask)
[email protected]374f1a82013-01-10 02:16:24175 return false;
176
[email protected]67ea5072013-03-28 02:02:18177 size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
thestig8badc792014-12-04 22:14:22178 name_ = options.name_deprecated ?
179 ASCIIToUTF16(*options.name_deprecated) : L"";
[email protected]6d6797eb2014-08-07 22:07:43180 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE };
181 SECURITY_DESCRIPTOR sd;
182 ACL dacl;
183
[email protected]dc84fcc2014-07-24 11:42:59184 if (options.share_read_only && name_.empty()) {
[email protected]6d6797eb2014-08-07 22:07:43185 // Add an empty DACL to enforce anonymous read-only sections.
186 sa.lpSecurityDescriptor = &sd;
187 if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION))
188 return false;
189 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
190 return false;
191 if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))
192 return false;
193
[email protected]dc84fcc2014-07-24 11:42:59194 // Windows ignores DACLs on certain unnamed objects (like shared sections).
195 // So, we generate a random name when we need to enforce read-only.
196 uint64_t rand_values[4];
thestig8badc792014-12-04 22:14:22197 RandBytes(&rand_values, sizeof(rand_values));
brucedawson5604a11d2015-10-06 19:22:00198 name_ = StringPrintf(L"CrSharedMem_%016llx%016llx%016llx%016llx",
thestig8badc792014-12-04 22:14:22199 rand_values[0], rand_values[1],
200 rand_values[2], rand_values[3]);
[email protected]dc84fcc2014-07-24 11:42:59201 }
[email protected]6d6797eb2014-08-07 22:07:43202 mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
shrikant9426fb82015-02-24 00:27:33203 PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
204 name_.empty() ? nullptr : name_.c_str());
initial.commitd7cae122008-07-26 21:49:38205 if (!mapped_file_)
206 return false;
207
[email protected]67ea5072013-03-28 02:02:18208 requested_size_ = options.size;
[email protected]54e3dfa22010-10-27 18:16:06209
initial.commitd7cae122008-07-26 21:49:38210 // Check if the shared memory pre-exists.
[email protected]54e3dfa22010-10-27 18:16:06211 if (GetLastError() == ERROR_ALREADY_EXISTS) {
[email protected]67ea5072013-03-28 02:02:18212 // If the file already existed, set requested_size_ to 0 to show that
[email protected]54e3dfa22010-10-27 18:16:06213 // we don't know the size.
[email protected]67ea5072013-03-28 02:02:18214 requested_size_ = 0;
forshaw0474abe2015-12-18 02:16:59215 external_section_ = true;
[email protected]ff672b72014-03-05 21:13:52216 if (!options.open_existing_deprecated) {
[email protected]54e3dfa22010-10-27 18:16:06217 Close();
218 return false;
219 }
initial.commitd7cae122008-07-26 21:49:38220 }
[email protected]54e3dfa22010-10-27 18:16:06221
initial.commitd7cae122008-07-26 21:49:38222 return true;
223}
224
[email protected]b6413b49b2010-09-29 20:32:22225bool SharedMemory::Delete(const std::string& name) {
[email protected]9e51af92009-02-04 00:58:39226 // intentionally empty -- there is nothing for us to do on Windows.
227 return true;
228}
229
[email protected]b6413b49b2010-09-29 20:32:22230bool SharedMemory::Open(const std::string& name, bool read_only) {
[email protected]5d2b4492011-03-01 02:48:05231 DCHECK(!mapped_file_);
forshaw0474abe2015-12-18 02:16:59232 DWORD access = FILE_MAP_READ | SECTION_QUERY;
233 if (!read_only)
234 access |= FILE_MAP_WRITE;
thestig8badc792014-12-04 22:14:22235 name_ = ASCIIToUTF16(name);
initial.commitd7cae122008-07-26 21:49:38236 read_only_ = read_only;
forshaw0474abe2015-12-18 02:16:59237 mapped_file_ =
238 OpenFileMapping(access, false, name_.empty() ? nullptr : name_.c_str());
239 if (!mapped_file_)
240 return false;
241 // If a name specified assume it's an external section.
242 if (!name_.empty())
243 external_section_ = true;
244 // Note: size_ is not set in this case.
245 return true;
initial.commitd7cae122008-07-26 21:49:38246}
247
[email protected]e29e3f552013-01-16 09:02:34248bool SharedMemory::MapAt(off_t offset, size_t bytes) {
initial.commitd7cae122008-07-26 21:49:38249 if (mapped_file_ == NULL)
250 return false;
251
[email protected]374f1a82013-01-10 02:16:24252 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
253 return false;
254
[email protected]421c1502014-03-18 22:33:28255 if (memory_)
256 return false;
257
forshaw0474abe2015-12-18 02:16:59258 if (external_section_ && !IsSectionSafeToMap(mapped_file_))
259 return false;
260
avi9beac252015-12-24 08:44:47261 memory_ = MapViewOfFile(
262 mapped_file_, read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
263 static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), bytes);
initial.commitd7cae122008-07-26 21:49:38264 if (memory_ != NULL) {
[email protected]404a0582012-08-18 02:17:26265 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
266 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
[email protected]67ea5072013-03-28 02:02:18267 mapped_size_ = GetMemorySectionSize(memory_);
initial.commitd7cae122008-07-26 21:49:38268 return true;
269 }
270 return false;
271}
272
273bool SharedMemory::Unmap() {
274 if (memory_ == NULL)
275 return false;
276
277 UnmapViewOfFile(memory_);
278 memory_ = NULL;
279 return true;
280}
281
282bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
thestig8badc792014-12-04 22:14:22283 SharedMemoryHandle* new_handle,
[email protected]5f58adab2013-11-20 23:41:25284 bool close_self,
285 ShareMode share_mode) {
erikchen5ea2ab72015-09-25 22:34:31286 *new_handle = SharedMemoryHandle();
forshaw0474abe2015-12-18 02:16:59287 DWORD access = FILE_MAP_READ | SECTION_QUERY;
initial.commitd7cae122008-07-26 21:49:38288 DWORD options = 0;
289 HANDLE mapped_file = mapped_file_;
290 HANDLE result;
[email protected]5f58adab2013-11-20 23:41:25291 if (share_mode == SHARE_CURRENT_MODE && !read_only_)
initial.commitd7cae122008-07-26 21:49:38292 access |= FILE_MAP_WRITE;
293 if (close_self) {
294 // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
295 options = DUPLICATE_CLOSE_SOURCE;
296 mapped_file_ = NULL;
297 Unmap();
298 }
299
300 if (process == GetCurrentProcess() && close_self) {
erikchen5ea2ab72015-09-25 22:34:31301 *new_handle = SharedMemoryHandle(mapped_file, base::GetCurrentProcId());
initial.commitd7cae122008-07-26 21:49:38302 return true;
303 }
304
erikchen2096f622015-06-03 00:26:59305 if (!::DuplicateHandle(GetCurrentProcess(), mapped_file, process, &result,
306 access, FALSE, options)) {
initial.commitd7cae122008-07-26 21:49:38307 return false;
erikchen2096f622015-06-03 00:26:59308 }
erikchen5ea2ab72015-09-25 22:34:31309 *new_handle = SharedMemoryHandle(result, base::GetProcId(process));
erikchen71bc3b22016-02-01 22:14:28310 new_handle->SetOwnershipPassesToIPC(true);
initial.commitd7cae122008-07-26 21:49:38311 return true;
312}
313
314
315void SharedMemory::Close() {
initial.commitd7cae122008-07-26 21:49:38316 if (mapped_file_ != NULL) {
erikchen5ea2ab72015-09-25 22:34:31317 ::CloseHandle(mapped_file_);
initial.commitd7cae122008-07-26 21:49:38318 mapped_file_ = NULL;
319 }
320}
321
[email protected]5fe733de2009-02-11 18:59:20322SharedMemoryHandle SharedMemory::handle() const {
erikchen5ea2ab72015-09-25 22:34:31323 return SharedMemoryHandle(mapped_file_, base::GetCurrentProcId());
[email protected]5fe733de2009-02-11 18:59:20324}
325
[email protected]176aa482008-11-14 03:25:15326} // namespace base