[email protected] | b05df6b | 2011-12-01 23:19:31 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 4 | |
[email protected] | 99873aa | 2013-03-29 17:46:23 | [diff] [blame] | 5 | #include "base/memory/shared_memory.h" |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 6 | |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 7 | #include <aclapi.h> |
avi | 9beac25 | 2015-12-24 08:44:47 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | #include <stdint.h> |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 10 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 11 | #include "base/logging.h" |
hajimehoshi | e80c576 | 2017-05-26 05:49:36 | [diff] [blame] | 12 | #include "base/memory/shared_memory_tracker.h" |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 13 | #include "base/metrics/histogram_macros.h" |
[email protected] | dc84fcc | 2014-07-24 11:42:59 | [diff] [blame] | 14 | #include "base/rand_util.h" |
| 15 | #include "base/strings/stringprintf.h" |
[email protected] | a4ea1f1 | 2013-06-07 18:37:07 | [diff] [blame] | 16 | #include "base/strings/utf_string_conversions.h" |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 17 | #include "base/unguessable_token.h" |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 18 | |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 19 | namespace { |
| 20 | |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 21 | // Errors that can occur during Shared Memory construction. |
| 22 | // These match tools/metrics/histograms/histograms.xml. |
| 23 | // This enum is append-only. |
| 24 | enum CreateError { |
| 25 | SUCCESS = 0, |
| 26 | SIZE_ZERO = 1, |
| 27 | SIZE_TOO_LARGE = 2, |
| 28 | INITIALIZE_ACL_FAILURE = 3, |
| 29 | INITIALIZE_SECURITY_DESC_FAILURE = 4, |
| 30 | SET_SECURITY_DESC_FAILURE = 5, |
| 31 | CREATE_FILE_MAPPING_FAILURE = 6, |
| 32 | REDUCE_PERMISSIONS_FAILURE = 7, |
| 33 | ALREADY_EXISTS = 8, |
| 34 | CREATE_ERROR_LAST = ALREADY_EXISTS |
| 35 | }; |
| 36 | |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 37 | // Emits UMA metrics about encountered errors. Pass zero (0) for |winerror| |
| 38 | // if there is no associated Windows error. |
| 39 | void LogError(CreateError error, DWORD winerror) { |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 40 | UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error, |
| 41 | CREATE_ERROR_LAST + 1); |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 42 | static_assert(ERROR_SUCCESS == 0, "Windows error code changed!"); |
| 43 | if (winerror != ERROR_SUCCESS) |
| 44 | UMA_HISTOGRAM_SPARSE_SLOWLY("SharedMemory.CreateWinError", winerror); |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 45 | } |
| 46 | |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 47 | typedef enum _SECTION_INFORMATION_CLASS { |
| 48 | SectionBasicInformation, |
| 49 | } SECTION_INFORMATION_CLASS; |
| 50 | |
| 51 | typedef struct _SECTION_BASIC_INFORMATION { |
| 52 | PVOID BaseAddress; |
| 53 | ULONG Attributes; |
| 54 | LARGE_INTEGER Size; |
| 55 | } SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION; |
| 56 | |
| 57 | typedef ULONG(__stdcall* NtQuerySectionType)( |
| 58 | HANDLE SectionHandle, |
| 59 | SECTION_INFORMATION_CLASS SectionInformationClass, |
| 60 | PVOID SectionInformation, |
| 61 | ULONG SectionInformationLength, |
| 62 | PULONG ResultLength); |
| 63 | |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 64 | // Returns the length of the memory section starting at the supplied address. |
| 65 | size_t GetMemorySectionSize(void* address) { |
| 66 | MEMORY_BASIC_INFORMATION memory_info; |
| 67 | if (!::VirtualQuery(address, &memory_info, sizeof(memory_info))) |
| 68 | return 0; |
| 69 | return memory_info.RegionSize - (static_cast<char*>(address) - |
| 70 | static_cast<char*>(memory_info.AllocationBase)); |
| 71 | } |
| 72 | |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 73 | // Checks if the section object is safe to map. At the moment this just means |
| 74 | // it's not an image section. |
| 75 | bool IsSectionSafeToMap(HANDLE handle) { |
| 76 | static NtQuerySectionType nt_query_section_func; |
| 77 | if (!nt_query_section_func) { |
| 78 | nt_query_section_func = reinterpret_cast<NtQuerySectionType>( |
| 79 | ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection")); |
| 80 | DCHECK(nt_query_section_func); |
| 81 | } |
| 82 | |
| 83 | // The handle must have SECTION_QUERY access for this to succeed. |
| 84 | SECTION_BASIC_INFORMATION basic_information = {}; |
| 85 | ULONG status = |
| 86 | nt_query_section_func(handle, SectionBasicInformation, &basic_information, |
| 87 | sizeof(basic_information), nullptr); |
| 88 | if (status) |
| 89 | return false; |
| 90 | return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE; |
| 91 | } |
| 92 | |
erikchen | 4b12c0a | 2016-02-19 03:15:43 | [diff] [blame] | 93 | // Returns a HANDLE on success and |nullptr| on failure. |
| 94 | // This function is similar to CreateFileMapping, but removes the permissions |
| 95 | // WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE. |
| 96 | // |
| 97 | // A newly created file mapping has two sets of permissions. It has access |
| 98 | // control permissions (WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE) and |
| 99 | // file permissions (FILE_MAP_READ, FILE_MAP_WRITE, etc.). ::DuplicateHandle() |
| 100 | // with the parameter DUPLICATE_SAME_ACCESS copies both sets of permissions. |
| 101 | // |
| 102 | // The Chrome sandbox prevents HANDLEs with the WRITE_DAC permission from being |
| 103 | // duplicated into unprivileged processes. But the only way to copy file |
| 104 | // permissions is with the parameter DUPLICATE_SAME_ACCESS. This means that |
| 105 | // there is no way for a privileged process to duplicate a file mapping into an |
| 106 | // unprivileged process while maintaining the previous file permissions. |
| 107 | // |
| 108 | // By removing all access control permissions of a file mapping immediately |
| 109 | // after creation, ::DuplicateHandle() effectively only copies the file |
| 110 | // permissions. |
| 111 | HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa, |
| 112 | size_t rounded_size, |
| 113 | LPCWSTR name) { |
| 114 | HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0, |
| 115 | static_cast<DWORD>(rounded_size), name); |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 116 | if (!h) { |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 117 | LogError(CREATE_FILE_MAPPING_FAILURE, GetLastError()); |
erikchen | 4b12c0a | 2016-02-19 03:15:43 | [diff] [blame] | 118 | return nullptr; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 119 | } |
erikchen | 4b12c0a | 2016-02-19 03:15:43 | [diff] [blame] | 120 | |
| 121 | HANDLE h2; |
| 122 | BOOL success = ::DuplicateHandle( |
| 123 | GetCurrentProcess(), h, GetCurrentProcess(), &h2, |
| 124 | FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY, FALSE, 0); |
| 125 | BOOL rv = ::CloseHandle(h); |
| 126 | DCHECK(rv); |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 127 | |
| 128 | if (!success) { |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 129 | LogError(REDUCE_PERMISSIONS_FAILURE, GetLastError()); |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 130 | return nullptr; |
| 131 | } |
| 132 | |
| 133 | return h2; |
erikchen | 4b12c0a | 2016-02-19 03:15:43 | [diff] [blame] | 134 | } |
| 135 | |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 136 | } // namespace. |
| 137 | |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 138 | namespace base { |
| 139 | |
asvitkine | 182427f | 2017-05-10 20:06:18 | [diff] [blame] | 140 | SharedMemory::SharedMemory() {} |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 141 | |
asvitkine | 182427f | 2017-05-10 20:06:18 | [diff] [blame] | 142 | SharedMemory::SharedMemory(const string16& name) : name_(name) {} |
[email protected] | 8cc4194 | 2010-11-05 19:16:07 | [diff] [blame] | 143 | |
scottmg | d19b4f7 | 2015-06-19 22:51:00 | [diff] [blame] | 144 | SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) |
asvitkine | 182427f | 2017-05-10 20:06:18 | [diff] [blame] | 145 | : external_section_(true), shm_(handle), read_only_(read_only) {} |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 146 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 147 | SharedMemory::~SharedMemory() { |
jbauman | 569918b | 2014-12-10 22:07:20 | [diff] [blame] | 148 | Unmap(); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 149 | Close(); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 150 | } |
| 151 | |
[email protected] | 5fe733de | 2009-02-11 18:59:20 | [diff] [blame] | 152 | // static |
| 153 | bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { |
erikchen | 5ea2ab7 | 2015-09-25 22:34:31 | [diff] [blame] | 154 | return handle.IsValid(); |
[email protected] | 5fe733de | 2009-02-11 18:59:20 | [diff] [blame] | 155 | } |
| 156 | |
[email protected] | 76aac1e | 2009-03-16 16:45:36 | [diff] [blame] | 157 | // static |
[email protected] | b0af04c | 2009-05-18 17:46:31 | [diff] [blame] | 158 | void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { |
erikchen | 5ea2ab7 | 2015-09-25 22:34:31 | [diff] [blame] | 159 | handle.Close(); |
[email protected] | b0af04c | 2009-05-18 17:46:31 | [diff] [blame] | 160 | } |
| 161 | |
[email protected] | c14eda9 | 2013-05-09 23:15:40 | [diff] [blame] | 162 | // static |
| 163 | size_t SharedMemory::GetHandleLimit() { |
| 164 | // Rounded down from value reported here: |
| 165 | // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx |
| 166 | return static_cast<size_t>(1 << 23); |
| 167 | } |
| 168 | |
erikchen | 2096f62 | 2015-06-03 00:26:59 | [diff] [blame] | 169 | // static |
| 170 | SharedMemoryHandle SharedMemory::DuplicateHandle( |
erikchen | 8539d85 | 2015-05-30 01:49:19 | [diff] [blame] | 171 | const SharedMemoryHandle& handle) { |
erikchen | 6384088 | 2017-05-02 20:52:31 | [diff] [blame] | 172 | return handle.Duplicate(); |
erikchen | 8539d85 | 2015-05-30 01:49:19 | [diff] [blame] | 173 | } |
| 174 | |
[email protected] | 374f1a8 | 2013-01-10 02:16:24 | [diff] [blame] | 175 | bool SharedMemory::CreateAndMapAnonymous(size_t size) { |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 176 | return CreateAnonymous(size) && Map(size); |
| 177 | } |
| 178 | |
[email protected] | b05df6b | 2011-12-01 23:19:31 | [diff] [blame] | 179 | bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 180 | // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here, |
| 181 | // wasting 32k per mapping on average. |
| 182 | static const size_t kSectionMask = 65536 - 1; |
[email protected] | b05df6b | 2011-12-01 23:19:31 | [diff] [blame] | 183 | DCHECK(!options.executable); |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 184 | DCHECK(!shm_.IsValid()); |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 185 | if (options.size == 0) { |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 186 | LogError(SIZE_ZERO, 0); |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 187 | return false; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 188 | } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 189 | |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 190 | // Check maximum accounting for overflow. |
| 191 | if (options.size > |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 192 | static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask) { |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 193 | LogError(SIZE_TOO_LARGE, 0); |
[email protected] | 374f1a8 | 2013-01-10 02:16:24 | [diff] [blame] | 194 | return false; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 195 | } |
[email protected] | 374f1a8 | 2013-01-10 02:16:24 | [diff] [blame] | 196 | |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 197 | size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask; |
thestig | 8badc79 | 2014-12-04 22:14:22 | [diff] [blame] | 198 | name_ = options.name_deprecated ? |
| 199 | ASCIIToUTF16(*options.name_deprecated) : L""; |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 200 | SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE }; |
| 201 | SECURITY_DESCRIPTOR sd; |
| 202 | ACL dacl; |
| 203 | |
erikchen | b5856b1 | 2016-05-24 17:21:59 | [diff] [blame] | 204 | if (name_.empty()) { |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 205 | // Add an empty DACL to enforce anonymous read-only sections. |
| 206 | sa.lpSecurityDescriptor = &sd; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 207 | if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) { |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 208 | LogError(INITIALIZE_ACL_FAILURE, GetLastError()); |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 209 | return false; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 210 | } |
| 211 | if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 212 | LogError(INITIALIZE_SECURITY_DESC_FAILURE, GetLastError()); |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 213 | return false; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 214 | } |
| 215 | if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) { |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 216 | LogError(SET_SECURITY_DESC_FAILURE, GetLastError()); |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 217 | return false; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 218 | } |
[email protected] | 6d6797eb | 2014-08-07 22:07:43 | [diff] [blame] | 219 | |
[email protected] | dc84fcc | 2014-07-24 11:42:59 | [diff] [blame] | 220 | // Windows ignores DACLs on certain unnamed objects (like shared sections). |
| 221 | // So, we generate a random name when we need to enforce read-only. |
| 222 | uint64_t rand_values[4]; |
thestig | 8badc79 | 2014-12-04 22:14:22 | [diff] [blame] | 223 | RandBytes(&rand_values, sizeof(rand_values)); |
brucedawson | 5604a11d | 2015-10-06 19:22:00 | [diff] [blame] | 224 | name_ = StringPrintf(L"CrSharedMem_%016llx%016llx%016llx%016llx", |
thestig | 8badc79 | 2014-12-04 22:14:22 | [diff] [blame] | 225 | rand_values[0], rand_values[1], |
| 226 | rand_values[2], rand_values[3]); |
[email protected] | dc84fcc | 2014-07-24 11:42:59 | [diff] [blame] | 227 | } |
hajimehoshi | df47edd | 2017-03-02 16:48:12 | [diff] [blame] | 228 | DCHECK(!name_.empty()); |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 229 | shm_ = SharedMemoryHandle( |
| 230 | CreateFileMappingWithReducedPermissions(&sa, rounded_size, name_.c_str()), |
erikchen | 9d6afd71 | 2017-05-18 17:49:06 | [diff] [blame] | 231 | rounded_size, UnguessableToken::Create()); |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 232 | if (!shm_.IsValid()) { |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 233 | // The error is logged within CreateFileMappingWithReducedPermissions(). |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 234 | return false; |
erikchen | 1d7cb7e | 2016-05-20 23:34:04 | [diff] [blame] | 235 | } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 236 | |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 237 | requested_size_ = options.size; |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 238 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 239 | // Check if the shared memory pre-exists. |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 240 | if (GetLastError() == ERROR_ALREADY_EXISTS) { |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 241 | // If the file already existed, set requested_size_ to 0 to show that |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 242 | // we don't know the size. |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 243 | requested_size_ = 0; |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 244 | external_section_ = true; |
[email protected] | ff672b7 | 2014-03-05 21:13:52 | [diff] [blame] | 245 | if (!options.open_existing_deprecated) { |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 246 | Close(); |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 247 | // From "if" above: GetLastError() == ERROR_ALREADY_EXISTS. |
| 248 | LogError(ALREADY_EXISTS, ERROR_ALREADY_EXISTS); |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 249 | return false; |
| 250 | } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 251 | } |
[email protected] | 54e3dfa2 | 2010-10-27 18:16:06 | [diff] [blame] | 252 | |
bcwhite | 8ea0791 | 2016-11-09 23:38:26 | [diff] [blame] | 253 | LogError(SUCCESS, ERROR_SUCCESS); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 254 | return true; |
| 255 | } |
| 256 | |
[email protected] | b6413b49b | 2010-09-29 20:32:22 | [diff] [blame] | 257 | bool SharedMemory::Delete(const std::string& name) { |
[email protected] | 9e51af9 | 2009-02-04 00:58:39 | [diff] [blame] | 258 | // intentionally empty -- there is nothing for us to do on Windows. |
| 259 | return true; |
| 260 | } |
| 261 | |
[email protected] | b6413b49b | 2010-09-29 20:32:22 | [diff] [blame] | 262 | bool SharedMemory::Open(const std::string& name, bool read_only) { |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 263 | DCHECK(!shm_.IsValid()); |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 264 | DWORD access = FILE_MAP_READ | SECTION_QUERY; |
| 265 | if (!read_only) |
| 266 | access |= FILE_MAP_WRITE; |
thestig | 8badc79 | 2014-12-04 22:14:22 | [diff] [blame] | 267 | name_ = ASCIIToUTF16(name); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 268 | read_only_ = read_only; |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 269 | |
| 270 | // This form of sharing shared memory is deprecated. https://crbug.com/345734. |
| 271 | // However, we can't get rid of it without a significant refactor because its |
| 272 | // used to communicate between two versions of the same service process, very |
| 273 | // early in the life cycle. |
| 274 | // Technically, we should also pass the GUID from the original shared memory |
| 275 | // region. We don't do that - this means that we will overcount this memory, |
| 276 | // which thankfully isn't relevant since Chrome only communicates with a |
| 277 | // single version of the service process. |
erikchen | 9d6afd71 | 2017-05-18 17:49:06 | [diff] [blame] | 278 | // We pass the size |0|, which is a dummy size and wrong, but otherwise |
| 279 | // harmless. |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 280 | shm_ = SharedMemoryHandle( |
erikchen | 1452520 | 2017-05-06 19:16:51 | [diff] [blame] | 281 | OpenFileMapping(access, false, name_.empty() ? nullptr : name_.c_str()), |
erikchen | 9d6afd71 | 2017-05-18 17:49:06 | [diff] [blame] | 282 | 0u, UnguessableToken::Create()); |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 283 | if (!shm_.IsValid()) |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 284 | return false; |
| 285 | // If a name specified assume it's an external section. |
| 286 | if (!name_.empty()) |
| 287 | external_section_ = true; |
| 288 | // Note: size_ is not set in this case. |
| 289 | return true; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 290 | } |
| 291 | |
[email protected] | e29e3f55 | 2013-01-16 09:02:34 | [diff] [blame] | 292 | bool SharedMemory::MapAt(off_t offset, size_t bytes) { |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 293 | if (!shm_.IsValid()) { |
| 294 | DLOG(ERROR) << "Invalid SharedMemoryHandle."; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 295 | return false; |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 296 | } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 297 | |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 298 | if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) { |
| 299 | DLOG(ERROR) << "Bytes required exceeds the 2G limitation."; |
[email protected] | 374f1a8 | 2013-01-10 02:16:24 | [diff] [blame] | 300 | return false; |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 301 | } |
[email protected] | 374f1a8 | 2013-01-10 02:16:24 | [diff] [blame] | 302 | |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 303 | if (memory_) { |
| 304 | DLOG(ERROR) << "The SharedMemory has been mapped already."; |
[email protected] | 421c150 | 2014-03-18 22:33:28 | [diff] [blame] | 305 | return false; |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 306 | } |
[email protected] | 421c150 | 2014-03-18 22:33:28 | [diff] [blame] | 307 | |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 308 | if (external_section_ && !IsSectionSafeToMap(shm_.GetHandle())) { |
| 309 | DLOG(ERROR) << "SharedMemoryHandle is not safe to be mapped."; |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 310 | return false; |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 311 | } |
forshaw | 0474abe | 2015-12-18 02:16:59 | [diff] [blame] | 312 | |
avi | 9beac25 | 2015-12-24 08:44:47 | [diff] [blame] | 313 | memory_ = MapViewOfFile( |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 314 | shm_.GetHandle(), |
stanisc | 2660facb | 2016-06-30 03:47:47 | [diff] [blame] | 315 | read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, |
avi | 9beac25 | 2015-12-24 08:44:47 | [diff] [blame] | 316 | static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), bytes); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 317 | if (memory_ != NULL) { |
[email protected] | 404a058 | 2012-08-18 02:17:26 | [diff] [blame] | 318 | DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) & |
| 319 | (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); |
[email protected] | 67ea507 | 2013-03-28 02:02:18 | [diff] [blame] | 320 | mapped_size_ = GetMemorySectionSize(memory_); |
Hajime Hoshi | 5d64433 | 2017-07-13 14:50:22 | [diff] [blame] | 321 | mapped_id_ = shm_.GetGUID(); |
hajimehoshi | e80c576 | 2017-05-26 05:49:36 | [diff] [blame] | 322 | SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 323 | return true; |
| 324 | } |
Zijie He | acbe01b | 2017-10-06 20:24:56 | [diff] [blame] | 325 | DPLOG(ERROR) << "Failed executing MapViewOfFile"; |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 326 | return false; |
| 327 | } |
| 328 | |
| 329 | bool SharedMemory::Unmap() { |
| 330 | if (memory_ == NULL) |
| 331 | return false; |
| 332 | |
hajimehoshi | e80c576 | 2017-05-26 05:49:36 | [diff] [blame] | 333 | SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 334 | UnmapViewOfFile(memory_); |
| 335 | memory_ = NULL; |
Hajime Hoshi | 5d64433 | 2017-07-13 14:50:22 | [diff] [blame] | 336 | mapped_id_ = UnguessableToken(); |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 337 | return true; |
| 338 | } |
| 339 | |
erikchen | c87903e | 2017-05-02 19:05:01 | [diff] [blame] | 340 | SharedMemoryHandle SharedMemory::GetReadOnlyHandle() { |
| 341 | HANDLE result; |
| 342 | ProcessHandle process = GetCurrentProcess(); |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 343 | if (!::DuplicateHandle(process, shm_.GetHandle(), process, &result, |
erikchen | c87903e | 2017-05-02 19:05:01 | [diff] [blame] | 344 | FILE_MAP_READ | SECTION_QUERY, FALSE, 0)) { |
| 345 | return SharedMemoryHandle(); |
| 346 | } |
erikchen | 9d6afd71 | 2017-05-18 17:49:06 | [diff] [blame] | 347 | SharedMemoryHandle handle = |
| 348 | SharedMemoryHandle(result, shm_.GetSize(), shm_.GetGUID()); |
erikchen | c87903e | 2017-05-02 19:05:01 | [diff] [blame] | 349 | handle.SetOwnershipPassesToIPC(true); |
| 350 | return handle; |
| 351 | } |
| 352 | |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 353 | void SharedMemory::Close() { |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 354 | if (shm_.IsValid()) { |
| 355 | shm_.Close(); |
| 356 | shm_ = SharedMemoryHandle(); |
| 357 | } |
initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 358 | } |
| 359 | |
[email protected] | 5fe733de | 2009-02-11 18:59:20 | [diff] [blame] | 360 | SharedMemoryHandle SharedMemory::handle() const { |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 361 | return shm_; |
[email protected] | 5fe733de | 2009-02-11 18:59:20 | [diff] [blame] | 362 | } |
| 363 | |
sadrul | f08f1e4a | 2016-11-15 00:40:02 | [diff] [blame] | 364 | SharedMemoryHandle SharedMemory::TakeHandle() { |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 365 | SharedMemoryHandle handle(shm_); |
sadrul | f08f1e4a | 2016-11-15 00:40:02 | [diff] [blame] | 366 | handle.SetOwnershipPassesToIPC(true); |
erikchen | 3df1dd5 | 2017-05-03 22:53:40 | [diff] [blame] | 367 | shm_ = SharedMemoryHandle(); |
sadrul | f08f1e4a | 2016-11-15 00:40:02 | [diff] [blame] | 368 | memory_ = nullptr; |
| 369 | mapped_size_ = 0; |
| 370 | return handle; |
| 371 | } |
| 372 | |
[email protected] | 176aa48 | 2008-11-14 03:25:15 | [diff] [blame] | 373 | } // namespace base |