blob: 7de87a98a9dd91a3647c4c20c47e8c977136e9c9 [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"
erikchen1d7cb7e2016-05-20 23:34:0412#include "base/metrics/histogram_macros.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
erikchen1d7cb7e2016-05-20 23:34:0419// Errors that can occur during Shared Memory construction.
20// These match tools/metrics/histograms/histograms.xml.
21// This enum is append-only.
22enum CreateError {
23 SUCCESS = 0,
24 SIZE_ZERO = 1,
25 SIZE_TOO_LARGE = 2,
26 INITIALIZE_ACL_FAILURE = 3,
27 INITIALIZE_SECURITY_DESC_FAILURE = 4,
28 SET_SECURITY_DESC_FAILURE = 5,
29 CREATE_FILE_MAPPING_FAILURE = 6,
30 REDUCE_PERMISSIONS_FAILURE = 7,
31 ALREADY_EXISTS = 8,
32 CREATE_ERROR_LAST = ALREADY_EXISTS
33};
34
35// Emits an UMA metric.
36void LogError(CreateError error) {
37 UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error,
38 CREATE_ERROR_LAST + 1);
39}
40
forshaw0474abe2015-12-18 02:16:5941typedef enum _SECTION_INFORMATION_CLASS {
42 SectionBasicInformation,
43} SECTION_INFORMATION_CLASS;
44
45typedef struct _SECTION_BASIC_INFORMATION {
46 PVOID BaseAddress;
47 ULONG Attributes;
48 LARGE_INTEGER Size;
49} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
50
51typedef ULONG(__stdcall* NtQuerySectionType)(
52 HANDLE SectionHandle,
53 SECTION_INFORMATION_CLASS SectionInformationClass,
54 PVOID SectionInformation,
55 ULONG SectionInformationLength,
56 PULONG ResultLength);
57
[email protected]67ea5072013-03-28 02:02:1858// Returns the length of the memory section starting at the supplied address.
59size_t GetMemorySectionSize(void* address) {
60 MEMORY_BASIC_INFORMATION memory_info;
61 if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
62 return 0;
63 return memory_info.RegionSize - (static_cast<char*>(address) -
64 static_cast<char*>(memory_info.AllocationBase));
65}
66
forshaw0474abe2015-12-18 02:16:5967// Checks if the section object is safe to map. At the moment this just means
68// it's not an image section.
69bool IsSectionSafeToMap(HANDLE handle) {
70 static NtQuerySectionType nt_query_section_func;
71 if (!nt_query_section_func) {
72 nt_query_section_func = reinterpret_cast<NtQuerySectionType>(
73 ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
74 DCHECK(nt_query_section_func);
75 }
76
77 // The handle must have SECTION_QUERY access for this to succeed.
78 SECTION_BASIC_INFORMATION basic_information = {};
79 ULONG status =
80 nt_query_section_func(handle, SectionBasicInformation, &basic_information,
81 sizeof(basic_information), nullptr);
82 if (status)
83 return false;
84 return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
85}
86
erikchen4b12c0a2016-02-19 03:15:4387// Returns a HANDLE on success and |nullptr| on failure.
88// This function is similar to CreateFileMapping, but removes the permissions
89// WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE.
90//
91// A newly created file mapping has two sets of permissions. It has access
92// control permissions (WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE) and
93// file permissions (FILE_MAP_READ, FILE_MAP_WRITE, etc.). ::DuplicateHandle()
94// with the parameter DUPLICATE_SAME_ACCESS copies both sets of permissions.
95//
96// The Chrome sandbox prevents HANDLEs with the WRITE_DAC permission from being
97// duplicated into unprivileged processes. But the only way to copy file
98// permissions is with the parameter DUPLICATE_SAME_ACCESS. This means that
99// there is no way for a privileged process to duplicate a file mapping into an
100// unprivileged process while maintaining the previous file permissions.
101//
102// By removing all access control permissions of a file mapping immediately
103// after creation, ::DuplicateHandle() effectively only copies the file
104// permissions.
105HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa,
106 size_t rounded_size,
107 LPCWSTR name) {
108 HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0,
109 static_cast<DWORD>(rounded_size), name);
erikchen1d7cb7e2016-05-20 23:34:04110 if (!h) {
111 LogError(CREATE_FILE_MAPPING_FAILURE);
erikchen4b12c0a2016-02-19 03:15:43112 return nullptr;
erikchen1d7cb7e2016-05-20 23:34:04113 }
erikchen4b12c0a2016-02-19 03:15:43114
115 HANDLE h2;
116 BOOL success = ::DuplicateHandle(
117 GetCurrentProcess(), h, GetCurrentProcess(), &h2,
118 FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY, FALSE, 0);
119 BOOL rv = ::CloseHandle(h);
120 DCHECK(rv);
erikchen1d7cb7e2016-05-20 23:34:04121
122 if (!success) {
123 LogError(REDUCE_PERMISSIONS_FAILURE);
124 return nullptr;
125 }
126
127 return h2;
erikchen4b12c0a2016-02-19 03:15:43128}
129
[email protected]67ea5072013-03-28 02:02:18130} // namespace.
131
[email protected]176aa482008-11-14 03:25:15132namespace base {
133
erikchenbaac9112015-10-23 20:20:34134SharedMemoryCreateOptions::SharedMemoryCreateOptions()
135 : name_deprecated(nullptr),
136 open_existing_deprecated(false),
137 size(0),
138 executable(false),
139 share_read_only(false) {}
140
initial.commitd7cae122008-07-26 21:49:38141SharedMemory::SharedMemory()
forshaw0474abe2015-12-18 02:16:59142 : external_section_(false),
sammc5648c852015-07-02 01:25:00143 mapped_file_(NULL),
144 mapped_size_(0),
[email protected]8cc41942010-11-05 19:16:07145 memory_(NULL),
146 read_only_(false),
forshaw0474abe2015-12-18 02:16:59147 requested_size_(0) {}
148
149SharedMemory::SharedMemory(const std::wstring& name)
150 : external_section_(false),
151 name_(name),
152 mapped_file_(NULL),
153 mapped_size_(0),
154 memory_(NULL),
155 read_only_(false),
156 requested_size_(0) {}
[email protected]8cc41942010-11-05 19:16:07157
scottmgd19b4f72015-06-19 22:51:00158SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
forshaw0474abe2015-12-18 02:16:59159 : external_section_(true),
160 mapped_file_(handle.GetHandle()),
sammc5648c852015-07-02 01:25:00161 mapped_size_(0),
initial.commitd7cae122008-07-26 21:49:38162 memory_(NULL),
163 read_only_(read_only),
sammc5648c852015-07-02 01:25:00164 requested_size_(0) {
erikchen5ea2ab72015-09-25 22:34:31165 DCHECK(!handle.IsValid() || handle.BelongsToCurrentProcess());
initial.commitd7cae122008-07-26 21:49:38166}
167
initial.commitd7cae122008-07-26 21:49:38168SharedMemory::~SharedMemory() {
jbauman569918b2014-12-10 22:07:20169 Unmap();
initial.commitd7cae122008-07-26 21:49:38170 Close();
initial.commitd7cae122008-07-26 21:49:38171}
172
[email protected]5fe733de2009-02-11 18:59:20173// static
174bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
erikchen5ea2ab72015-09-25 22:34:31175 return handle.IsValid();
[email protected]5fe733de2009-02-11 18:59:20176}
177
[email protected]76aac1e2009-03-16 16:45:36178// static
179SharedMemoryHandle SharedMemory::NULLHandle() {
erikchen5ea2ab72015-09-25 22:34:31180 return SharedMemoryHandle();
[email protected]76aac1e2009-03-16 16:45:36181}
182
[email protected]b0af04c2009-05-18 17:46:31183// static
184void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
erikchen5ea2ab72015-09-25 22:34:31185 handle.Close();
[email protected]b0af04c2009-05-18 17:46:31186}
187
[email protected]c14eda92013-05-09 23:15:40188// static
189size_t SharedMemory::GetHandleLimit() {
190 // Rounded down from value reported here:
191 // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
192 return static_cast<size_t>(1 << 23);
193}
194
erikchen2096f622015-06-03 00:26:59195// static
196SharedMemoryHandle SharedMemory::DuplicateHandle(
erikchen8539d852015-05-30 01:49:19197 const SharedMemoryHandle& handle) {
erikchen5ea2ab72015-09-25 22:34:31198 DCHECK(handle.BelongsToCurrentProcess());
199 HANDLE duped_handle;
erikchen2096f622015-06-03 00:26:59200 ProcessHandle process = GetCurrentProcess();
erikchen5ea2ab72015-09-25 22:34:31201 BOOL success =
202 ::DuplicateHandle(process, handle.GetHandle(), process, &duped_handle, 0,
203 FALSE, DUPLICATE_SAME_ACCESS);
erikchenad6f6d82016-02-08 01:34:13204 if (success) {
205 base::SharedMemoryHandle handle(duped_handle, GetCurrentProcId());
206 handle.SetOwnershipPassesToIPC(true);
207 return handle;
208 }
erikchen5ea2ab72015-09-25 22:34:31209 return SharedMemoryHandle();
erikchen8539d852015-05-30 01:49:19210}
211
[email protected]374f1a82013-01-10 02:16:24212bool SharedMemory::CreateAndMapAnonymous(size_t size) {
[email protected]54e3dfa22010-10-27 18:16:06213 return CreateAnonymous(size) && Map(size);
214}
215
[email protected]b05df6b2011-12-01 23:19:31216bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
[email protected]67ea5072013-03-28 02:02:18217 // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here,
218 // wasting 32k per mapping on average.
219 static const size_t kSectionMask = 65536 - 1;
[email protected]b05df6b2011-12-01 23:19:31220 DCHECK(!options.executable);
[email protected]5d2b4492011-03-01 02:48:05221 DCHECK(!mapped_file_);
erikchen1d7cb7e2016-05-20 23:34:04222 if (options.size == 0) {
223 LogError(SIZE_ZERO);
[email protected]54e3dfa22010-10-27 18:16:06224 return false;
erikchen1d7cb7e2016-05-20 23:34:04225 }
initial.commitd7cae122008-07-26 21:49:38226
[email protected]67ea5072013-03-28 02:02:18227 // Check maximum accounting for overflow.
228 if (options.size >
erikchen1d7cb7e2016-05-20 23:34:04229 static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask) {
230 LogError(SIZE_TOO_LARGE);
[email protected]374f1a82013-01-10 02:16:24231 return false;
erikchen1d7cb7e2016-05-20 23:34:04232 }
[email protected]374f1a82013-01-10 02:16:24233
[email protected]67ea5072013-03-28 02:02:18234 size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
thestig8badc792014-12-04 22:14:22235 name_ = options.name_deprecated ?
236 ASCIIToUTF16(*options.name_deprecated) : L"";
[email protected]6d6797eb2014-08-07 22:07:43237 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE };
238 SECURITY_DESCRIPTOR sd;
239 ACL dacl;
240
erikchenb5856b12016-05-24 17:21:59241 if (name_.empty()) {
[email protected]6d6797eb2014-08-07 22:07:43242 // Add an empty DACL to enforce anonymous read-only sections.
243 sa.lpSecurityDescriptor = &sd;
erikchen1d7cb7e2016-05-20 23:34:04244 if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) {
245 LogError(INITIALIZE_ACL_FAILURE);
[email protected]6d6797eb2014-08-07 22:07:43246 return false;
erikchen1d7cb7e2016-05-20 23:34:04247 }
248 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
249 LogError(INITIALIZE_SECURITY_DESC_FAILURE);
[email protected]6d6797eb2014-08-07 22:07:43250 return false;
erikchen1d7cb7e2016-05-20 23:34:04251 }
252 if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) {
253 LogError(SET_SECURITY_DESC_FAILURE);
[email protected]6d6797eb2014-08-07 22:07:43254 return false;
erikchen1d7cb7e2016-05-20 23:34:04255 }
[email protected]6d6797eb2014-08-07 22:07:43256
[email protected]dc84fcc2014-07-24 11:42:59257 // Windows ignores DACLs on certain unnamed objects (like shared sections).
258 // So, we generate a random name when we need to enforce read-only.
259 uint64_t rand_values[4];
thestig8badc792014-12-04 22:14:22260 RandBytes(&rand_values, sizeof(rand_values));
brucedawson5604a11d2015-10-06 19:22:00261 name_ = StringPrintf(L"CrSharedMem_%016llx%016llx%016llx%016llx",
thestig8badc792014-12-04 22:14:22262 rand_values[0], rand_values[1],
263 rand_values[2], rand_values[3]);
[email protected]dc84fcc2014-07-24 11:42:59264 }
erikchen4b12c0a2016-02-19 03:15:43265 mapped_file_ = CreateFileMappingWithReducedPermissions(
266 &sa, rounded_size, name_.empty() ? nullptr : name_.c_str());
erikchen1d7cb7e2016-05-20 23:34:04267 if (!mapped_file_) {
268 // The error is logged within CreateFileMappingWithReducedPermissions().
initial.commitd7cae122008-07-26 21:49:38269 return false;
erikchen1d7cb7e2016-05-20 23:34:04270 }
initial.commitd7cae122008-07-26 21:49:38271
[email protected]67ea5072013-03-28 02:02:18272 requested_size_ = options.size;
[email protected]54e3dfa22010-10-27 18:16:06273
initial.commitd7cae122008-07-26 21:49:38274 // Check if the shared memory pre-exists.
[email protected]54e3dfa22010-10-27 18:16:06275 if (GetLastError() == ERROR_ALREADY_EXISTS) {
[email protected]67ea5072013-03-28 02:02:18276 // If the file already existed, set requested_size_ to 0 to show that
[email protected]54e3dfa22010-10-27 18:16:06277 // we don't know the size.
[email protected]67ea5072013-03-28 02:02:18278 requested_size_ = 0;
forshaw0474abe2015-12-18 02:16:59279 external_section_ = true;
[email protected]ff672b72014-03-05 21:13:52280 if (!options.open_existing_deprecated) {
[email protected]54e3dfa22010-10-27 18:16:06281 Close();
erikchen1d7cb7e2016-05-20 23:34:04282 LogError(ALREADY_EXISTS);
[email protected]54e3dfa22010-10-27 18:16:06283 return false;
284 }
initial.commitd7cae122008-07-26 21:49:38285 }
[email protected]54e3dfa22010-10-27 18:16:06286
erikchen1d7cb7e2016-05-20 23:34:04287 LogError(SUCCESS);
initial.commitd7cae122008-07-26 21:49:38288 return true;
289}
290
[email protected]b6413b49b2010-09-29 20:32:22291bool SharedMemory::Delete(const std::string& name) {
[email protected]9e51af92009-02-04 00:58:39292 // intentionally empty -- there is nothing for us to do on Windows.
293 return true;
294}
295
[email protected]b6413b49b2010-09-29 20:32:22296bool SharedMemory::Open(const std::string& name, bool read_only) {
[email protected]5d2b4492011-03-01 02:48:05297 DCHECK(!mapped_file_);
forshaw0474abe2015-12-18 02:16:59298 DWORD access = FILE_MAP_READ | SECTION_QUERY;
299 if (!read_only)
300 access |= FILE_MAP_WRITE;
thestig8badc792014-12-04 22:14:22301 name_ = ASCIIToUTF16(name);
initial.commitd7cae122008-07-26 21:49:38302 read_only_ = read_only;
forshaw0474abe2015-12-18 02:16:59303 mapped_file_ =
304 OpenFileMapping(access, false, name_.empty() ? nullptr : name_.c_str());
305 if (!mapped_file_)
306 return false;
307 // If a name specified assume it's an external section.
308 if (!name_.empty())
309 external_section_ = true;
310 // Note: size_ is not set in this case.
311 return true;
initial.commitd7cae122008-07-26 21:49:38312}
313
[email protected]e29e3f552013-01-16 09:02:34314bool SharedMemory::MapAt(off_t offset, size_t bytes) {
initial.commitd7cae122008-07-26 21:49:38315 if (mapped_file_ == NULL)
316 return false;
317
[email protected]374f1a82013-01-10 02:16:24318 if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
319 return false;
320
[email protected]421c1502014-03-18 22:33:28321 if (memory_)
322 return false;
323
forshaw0474abe2015-12-18 02:16:59324 if (external_section_ && !IsSectionSafeToMap(mapped_file_))
325 return false;
326
avi9beac252015-12-24 08:44:47327 memory_ = MapViewOfFile(
328 mapped_file_, read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
329 static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), bytes);
initial.commitd7cae122008-07-26 21:49:38330 if (memory_ != NULL) {
[email protected]404a0582012-08-18 02:17:26331 DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
332 (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
[email protected]67ea5072013-03-28 02:02:18333 mapped_size_ = GetMemorySectionSize(memory_);
initial.commitd7cae122008-07-26 21:49:38334 return true;
335 }
336 return false;
337}
338
339bool SharedMemory::Unmap() {
340 if (memory_ == NULL)
341 return false;
342
343 UnmapViewOfFile(memory_);
344 memory_ = NULL;
345 return true;
346}
347
348bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
thestig8badc792014-12-04 22:14:22349 SharedMemoryHandle* new_handle,
[email protected]5f58adab2013-11-20 23:41:25350 bool close_self,
351 ShareMode share_mode) {
erikchen5ea2ab72015-09-25 22:34:31352 *new_handle = SharedMemoryHandle();
forshaw0474abe2015-12-18 02:16:59353 DWORD access = FILE_MAP_READ | SECTION_QUERY;
initial.commitd7cae122008-07-26 21:49:38354 DWORD options = 0;
355 HANDLE mapped_file = mapped_file_;
356 HANDLE result;
[email protected]5f58adab2013-11-20 23:41:25357 if (share_mode == SHARE_CURRENT_MODE && !read_only_)
initial.commitd7cae122008-07-26 21:49:38358 access |= FILE_MAP_WRITE;
359 if (close_self) {
360 // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
361 options = DUPLICATE_CLOSE_SOURCE;
362 mapped_file_ = NULL;
363 Unmap();
364 }
365
366 if (process == GetCurrentProcess() && close_self) {
erikchen5ea2ab72015-09-25 22:34:31367 *new_handle = SharedMemoryHandle(mapped_file, base::GetCurrentProcId());
initial.commitd7cae122008-07-26 21:49:38368 return true;
369 }
370
erikchen2096f622015-06-03 00:26:59371 if (!::DuplicateHandle(GetCurrentProcess(), mapped_file, process, &result,
372 access, FALSE, options)) {
initial.commitd7cae122008-07-26 21:49:38373 return false;
erikchen2096f622015-06-03 00:26:59374 }
erikchen5ea2ab72015-09-25 22:34:31375 *new_handle = SharedMemoryHandle(result, base::GetProcId(process));
erikchen71bc3b22016-02-01 22:14:28376 new_handle->SetOwnershipPassesToIPC(true);
initial.commitd7cae122008-07-26 21:49:38377 return true;
378}
379
380
381void SharedMemory::Close() {
initial.commitd7cae122008-07-26 21:49:38382 if (mapped_file_ != NULL) {
erikchen5ea2ab72015-09-25 22:34:31383 ::CloseHandle(mapped_file_);
initial.commitd7cae122008-07-26 21:49:38384 mapped_file_ = NULL;
385 }
386}
387
[email protected]5fe733de2009-02-11 18:59:20388SharedMemoryHandle SharedMemory::handle() const {
erikchen5ea2ab72015-09-25 22:34:31389 return SharedMemoryHandle(mapped_file_, base::GetCurrentProcId());
[email protected]5fe733de2009-02-11 18:59:20390}
391
[email protected]176aa482008-11-14 03:25:15392} // namespace base