1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "util/win/process_info.h"
16 
17 #include <dbghelp.h>
18 #include <intrin.h>
19 #include <wchar.h>
20 
21 #include <memory>
22 
23 #include "base/files/file_path.h"
24 #include "base/logging.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "build/build_config.h"
28 #include "gtest/gtest.h"
29 #include "test/errors.h"
30 #include "test/scoped_temp_dir.h"
31 #include "test/test_paths.h"
32 #include "test/win/child_launcher.h"
33 #include "util/file/file_io.h"
34 #include "util/misc/from_pointer_cast.h"
35 #include "util/misc/random_string.h"
36 #include "util/misc/uuid.h"
37 #include "util/win/command_line.h"
38 #include "util/win/get_function.h"
39 #include "util/win/handle.h"
40 #include "util/win/scoped_handle.h"
41 #include "util/win/scoped_registry_key.h"
42 
43 namespace crashpad {
44 namespace test {
45 namespace {
46 
47 constexpr wchar_t kNtdllName[] = L"\\ntdll.dll";
48 
49 #if !defined(ARCH_CPU_64_BITS)
IsProcessWow64(HANDLE process_handle)50 bool IsProcessWow64(HANDLE process_handle) {
51   static const auto is_wow64_process =
52       GET_FUNCTION(L"kernel32.dll", ::IsWow64Process);
53   if (!is_wow64_process)
54     return false;
55   BOOL is_wow64;
56   if (!is_wow64_process(process_handle, &is_wow64)) {
57     PLOG(ERROR) << "IsWow64Process";
58     return false;
59   }
60   return !!is_wow64;
61 }
62 #endif
63 
VerifyAddressInInCodePage(const ProcessInfo & process_info,WinVMAddress code_address)64 void VerifyAddressInInCodePage(const ProcessInfo& process_info,
65                                WinVMAddress code_address) {
66   // Make sure the child code address is an code page address with the right
67   // information.
68   const ProcessInfo::MemoryBasicInformation64Vector& memory_info =
69       process_info.MemoryInfo();
70   bool found_region = false;
71   for (const auto& mi : memory_info) {
72     if (mi.BaseAddress <= code_address &&
73         mi.BaseAddress + mi.RegionSize > code_address) {
74       EXPECT_EQ(mi.State, static_cast<DWORD>(MEM_COMMIT));
75       EXPECT_EQ(mi.Protect, static_cast<DWORD>(PAGE_EXECUTE_READ));
76       EXPECT_EQ(mi.Type, static_cast<DWORD>(MEM_IMAGE));
77       EXPECT_FALSE(found_region);
78       found_region = true;
79     }
80   }
81   EXPECT_TRUE(found_region);
82 }
83 
TEST(ProcessInfo,Self)84 TEST(ProcessInfo, Self) {
85   ProcessInfo process_info;
86   ASSERT_TRUE(process_info.Initialize(GetCurrentProcess()));
87   EXPECT_EQ(process_info.ProcessID(), GetCurrentProcessId());
88   EXPECT_GT(process_info.ParentProcessID(), 0u);
89 
90 #if defined(ARCH_CPU_64_BITS)
91   EXPECT_TRUE(process_info.Is64Bit());
92   EXPECT_FALSE(process_info.IsWow64());
93 #else
94   EXPECT_FALSE(process_info.Is64Bit());
95   if (IsProcessWow64(GetCurrentProcess()))
96     EXPECT_TRUE(process_info.IsWow64());
97   else
98     EXPECT_FALSE(process_info.IsWow64());
99 #endif
100 
101   std::wstring command_line;
102   EXPECT_TRUE(process_info.CommandLine(&command_line));
103   EXPECT_EQ(command_line, std::wstring(GetCommandLine()));
104 
105   std::vector<ProcessInfo::Module> modules;
106   EXPECT_TRUE(process_info.Modules(&modules));
107   ASSERT_GE(modules.size(), 2u);
108   std::wstring self_name =
109       std::wstring(1, '\\') +
110       TestPaths::ExpectedExecutableBasename(L"crashpad_util_test").value();
111   ASSERT_GE(modules[0].name.size(), self_name.size());
112   EXPECT_EQ(modules[0].name.substr(modules[0].name.size() - self_name.size()),
113             self_name);
114   ASSERT_GE(modules[1].name.size(), wcslen(kNtdllName));
115   EXPECT_EQ(modules[1].name.substr(modules[1].name.size() - wcslen(kNtdllName)),
116             kNtdllName);
117 
118   EXPECT_EQ(modules[0].dll_base,
119             reinterpret_cast<uintptr_t>(GetModuleHandle(nullptr)));
120   EXPECT_EQ(modules[1].dll_base,
121             reinterpret_cast<uintptr_t>(GetModuleHandle(L"ntdll.dll")));
122 
123   EXPECT_GT(modules[0].size, 0u);
124   EXPECT_GT(modules[1].size, 0u);
125 
126   EXPECT_EQ(modules[0].timestamp,
127             GetTimestampForLoadedLibrary(GetModuleHandle(nullptr)));
128   // System modules are forced to particular stamps and the file header values
129   // don't match the on-disk times. Just make sure we got some data here.
130   EXPECT_GT(modules[1].timestamp, 0);
131 
132   // Find something we know is a code address and confirm expected memory
133   // information settings.
134   VerifyAddressInInCodePage(process_info,
135                             FromPointerCast<WinVMAddress>(_ReturnAddress()));
136 }
137 
TestOtherProcess(TestPaths::Architecture architecture)138 void TestOtherProcess(TestPaths::Architecture architecture) {
139   ProcessInfo process_info;
140 
141   UUID done_uuid;
142   done_uuid.InitializeWithNew();
143 
144   ScopedKernelHANDLE done(
145       CreateEvent(nullptr, true, false, done_uuid.ToWString().c_str()));
146   ASSERT_TRUE(done.get()) << ErrorMessage("CreateEvent");
147 
148   base::FilePath child_test_executable =
149       TestPaths::BuildArtifact(L"util",
150                                L"process_info_test_child",
151                                TestPaths::FileType::kExecutable,
152                                architecture);
153   std::wstring args;
154   AppendCommandLineArgument(done_uuid.ToWString(), &args);
155 
156   ChildLauncher child(child_test_executable, args);
157   ASSERT_NO_FATAL_FAILURE(child.Start());
158 
159   // The child sends us a code address we can look up in the memory map.
160   WinVMAddress code_address;
161   CheckedReadFileExactly(
162       child.stdout_read_handle(), &code_address, sizeof(code_address));
163 
164   ASSERT_TRUE(process_info.Initialize(child.process_handle()));
165 
166   // Tell the test it's OK to shut down now that we've read our data.
167   EXPECT_TRUE(SetEvent(done.get())) << ErrorMessage("SetEvent");
168 
169   EXPECT_EQ(child.WaitForExit(), 0u);
170 
171   std::vector<ProcessInfo::Module> modules;
172   EXPECT_TRUE(process_info.Modules(&modules));
173   ASSERT_GE(modules.size(), 3u);
174   std::wstring child_name = L"\\crashpad_util_test_process_info_test_child.exe";
175   ASSERT_GE(modules[0].name.size(), child_name.size());
176   EXPECT_EQ(modules[0].name.substr(modules[0].name.size() - child_name.size()),
177             child_name);
178   ASSERT_GE(modules[1].name.size(), wcslen(kNtdllName));
179   EXPECT_EQ(modules[1].name.substr(modules[1].name.size() - wcslen(kNtdllName)),
180             kNtdllName);
181   // lz32.dll is an uncommonly-used-but-always-available module that the test
182   // binary manually loads.
183   static constexpr wchar_t kLz32dllName[] = L"\\lz32.dll";
184   auto& lz32 = modules[modules.size() - 2];
185   ASSERT_GE(lz32.name.size(), wcslen(kLz32dllName));
186   EXPECT_EQ(lz32.name.substr(lz32.name.size() - wcslen(kLz32dllName)),
187             kLz32dllName);
188 
189   // Note that the test code corrupts the PEB MemoryOrder list, whereas
190   // ProcessInfo::Modules() retrieves the module names via the PEB LoadOrder
191   // list. These are expected to point to the same strings, but theoretically
192   // could be separate.
193   auto& corrupted = modules.back();
194   EXPECT_EQ(corrupted.name, L"???");
195 
196   VerifyAddressInInCodePage(process_info, code_address);
197 }
198 
TEST(ProcessInfo,OtherProcess)199 TEST(ProcessInfo, OtherProcess) {
200   TestOtherProcess(TestPaths::Architecture::kDefault);
201 }
202 
203 #if defined(ARCH_CPU_64_BITS)
TEST(ProcessInfo,OtherProcessWOW64)204 TEST(ProcessInfo, OtherProcessWOW64) {
205   if (!TestPaths::Has32BitBuildArtifacts()) {
206     GTEST_SKIP();
207   }
208 
209   TestOtherProcess(TestPaths::Architecture::k32Bit);
210 }
211 #endif  // ARCH_CPU_64_BITS
212 
TEST(ProcessInfo,AccessibleRangesNone)213 TEST(ProcessInfo, AccessibleRangesNone) {
214   ProcessInfo::MemoryBasicInformation64Vector memory_info;
215   MEMORY_BASIC_INFORMATION64 mbi = {0};
216 
217   mbi.BaseAddress = 0;
218   mbi.RegionSize = 10;
219   mbi.State = MEM_FREE;
220   memory_info.push_back(mbi);
221 
222   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
223       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(2, 4),
224                                    memory_info);
225 
226   EXPECT_TRUE(result.empty());
227 }
228 
TEST(ProcessInfo,AccessibleRangesOneInside)229 TEST(ProcessInfo, AccessibleRangesOneInside) {
230   ProcessInfo::MemoryBasicInformation64Vector memory_info;
231   MEMORY_BASIC_INFORMATION64 mbi = {0};
232 
233   mbi.BaseAddress = 0;
234   mbi.RegionSize = 10;
235   mbi.State = MEM_COMMIT;
236   memory_info.push_back(mbi);
237 
238   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
239       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(2, 4),
240                                    memory_info);
241 
242   ASSERT_EQ(result.size(), 1u);
243   EXPECT_EQ(result[0].base(), 2u);
244   EXPECT_EQ(result[0].size(), 4u);
245 }
246 
TEST(ProcessInfo,AccessibleRangesOneTruncatedSize)247 TEST(ProcessInfo, AccessibleRangesOneTruncatedSize) {
248   ProcessInfo::MemoryBasicInformation64Vector memory_info;
249   MEMORY_BASIC_INFORMATION64 mbi = {0};
250 
251   mbi.BaseAddress = 0;
252   mbi.RegionSize = 10;
253   mbi.State = MEM_COMMIT;
254   memory_info.push_back(mbi);
255 
256   mbi.BaseAddress = 10;
257   mbi.RegionSize = 20;
258   mbi.State = MEM_FREE;
259   memory_info.push_back(mbi);
260 
261   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
262       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(5, 10),
263                                    memory_info);
264 
265   ASSERT_EQ(result.size(), 1u);
266   EXPECT_EQ(result[0].base(), 5u);
267   EXPECT_EQ(result[0].size(), 5u);
268 }
269 
TEST(ProcessInfo,AccessibleRangesOneMovedStart)270 TEST(ProcessInfo, AccessibleRangesOneMovedStart) {
271   ProcessInfo::MemoryBasicInformation64Vector memory_info;
272   MEMORY_BASIC_INFORMATION64 mbi = {0};
273 
274   mbi.BaseAddress = 0;
275   mbi.RegionSize = 10;
276   mbi.State = MEM_FREE;
277   memory_info.push_back(mbi);
278 
279   mbi.BaseAddress = 10;
280   mbi.RegionSize = 20;
281   mbi.State = MEM_COMMIT;
282   memory_info.push_back(mbi);
283 
284   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
285       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(5, 10),
286                                    memory_info);
287 
288   ASSERT_EQ(result.size(), 1u);
289   EXPECT_EQ(result[0].base(), 10u);
290   EXPECT_EQ(result[0].size(), 5u);
291 }
292 
TEST(ProcessInfo,ReserveIsInaccessible)293 TEST(ProcessInfo, ReserveIsInaccessible) {
294   ProcessInfo::MemoryBasicInformation64Vector memory_info;
295   MEMORY_BASIC_INFORMATION64 mbi = {0};
296 
297   mbi.BaseAddress = 0;
298   mbi.RegionSize = 10;
299   mbi.State = MEM_RESERVE;
300   memory_info.push_back(mbi);
301 
302   mbi.BaseAddress = 10;
303   mbi.RegionSize = 20;
304   mbi.State = MEM_COMMIT;
305   memory_info.push_back(mbi);
306 
307   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
308       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(5, 10),
309                                    memory_info);
310 
311   ASSERT_EQ(result.size(), 1u);
312   EXPECT_EQ(result[0].base(), 10u);
313   EXPECT_EQ(result[0].size(), 5u);
314 }
315 
TEST(ProcessInfo,PageGuardIsInaccessible)316 TEST(ProcessInfo, PageGuardIsInaccessible) {
317   ProcessInfo::MemoryBasicInformation64Vector memory_info;
318   MEMORY_BASIC_INFORMATION64 mbi = {0};
319 
320   mbi.BaseAddress = 0;
321   mbi.RegionSize = 10;
322   mbi.State = MEM_COMMIT;
323   mbi.Protect = PAGE_GUARD;
324   memory_info.push_back(mbi);
325 
326   mbi.BaseAddress = 10;
327   mbi.RegionSize = 20;
328   mbi.State = MEM_COMMIT;
329   mbi.Protect = 0;
330   memory_info.push_back(mbi);
331 
332   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
333       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(5, 10),
334                                    memory_info);
335 
336   ASSERT_EQ(result.size(), 1u);
337   EXPECT_EQ(result[0].base(), 10u);
338   EXPECT_EQ(result[0].size(), 5u);
339 }
340 
TEST(ProcessInfo,PageNoAccessIsInaccessible)341 TEST(ProcessInfo, PageNoAccessIsInaccessible) {
342   ProcessInfo::MemoryBasicInformation64Vector memory_info;
343   MEMORY_BASIC_INFORMATION64 mbi = {0};
344 
345   mbi.BaseAddress = 0;
346   mbi.RegionSize = 10;
347   mbi.State = MEM_COMMIT;
348   mbi.Protect = PAGE_NOACCESS;
349   memory_info.push_back(mbi);
350 
351   mbi.BaseAddress = 10;
352   mbi.RegionSize = 20;
353   mbi.State = MEM_COMMIT;
354   mbi.Protect = 0;
355   memory_info.push_back(mbi);
356 
357   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
358       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(5, 10),
359                                    memory_info);
360 
361   ASSERT_EQ(result.size(), 1u);
362   EXPECT_EQ(result[0].base(), 10u);
363   EXPECT_EQ(result[0].size(), 5u);
364 }
365 
TEST(ProcessInfo,AccessibleRangesCoalesced)366 TEST(ProcessInfo, AccessibleRangesCoalesced) {
367   ProcessInfo::MemoryBasicInformation64Vector memory_info;
368   MEMORY_BASIC_INFORMATION64 mbi = {0};
369 
370   mbi.BaseAddress = 0;
371   mbi.RegionSize = 10;
372   mbi.State = MEM_FREE;
373   memory_info.push_back(mbi);
374 
375   mbi.BaseAddress = 10;
376   mbi.RegionSize = 2;
377   mbi.State = MEM_COMMIT;
378   memory_info.push_back(mbi);
379 
380   mbi.BaseAddress = 12;
381   mbi.RegionSize = 5;
382   mbi.State = MEM_COMMIT;
383   memory_info.push_back(mbi);
384 
385   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
386       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(11, 4),
387                                    memory_info);
388 
389   ASSERT_EQ(result.size(), 1u);
390   EXPECT_EQ(result[0].base(), 11u);
391   EXPECT_EQ(result[0].size(), 4u);
392 }
393 
TEST(ProcessInfo,AccessibleRangesMiddleUnavailable)394 TEST(ProcessInfo, AccessibleRangesMiddleUnavailable) {
395   ProcessInfo::MemoryBasicInformation64Vector memory_info;
396   MEMORY_BASIC_INFORMATION64 mbi = {0};
397 
398   mbi.BaseAddress = 0;
399   mbi.RegionSize = 10;
400   mbi.State = MEM_COMMIT;
401   memory_info.push_back(mbi);
402 
403   mbi.BaseAddress = 10;
404   mbi.RegionSize = 5;
405   mbi.State = MEM_FREE;
406   memory_info.push_back(mbi);
407 
408   mbi.BaseAddress = 15;
409   mbi.RegionSize = 100;
410   mbi.State = MEM_COMMIT;
411   memory_info.push_back(mbi);
412 
413   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
414       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(5, 45),
415                                    memory_info);
416 
417   ASSERT_EQ(result.size(), 2u);
418   EXPECT_EQ(result[0].base(), 5u);
419   EXPECT_EQ(result[0].size(), 5u);
420   EXPECT_EQ(result[1].base(), 15u);
421   EXPECT_EQ(result[1].size(), 35u);
422 }
423 
TEST(ProcessInfo,RequestedBeforeMap)424 TEST(ProcessInfo, RequestedBeforeMap) {
425   ProcessInfo::MemoryBasicInformation64Vector memory_info;
426   MEMORY_BASIC_INFORMATION64 mbi = {0};
427 
428   mbi.BaseAddress = 10;
429   mbi.RegionSize = 10;
430   mbi.State = MEM_COMMIT;
431   memory_info.push_back(mbi);
432 
433   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
434       GetReadableRangesOfMemoryMap(CheckedRange<WinVMAddress, WinVMSize>(5, 10),
435                                    memory_info);
436 
437   ASSERT_EQ(result.size(), 1u);
438   EXPECT_EQ(result[0].base(), 10u);
439   EXPECT_EQ(result[0].size(), 5u);
440 }
441 
TEST(ProcessInfo,RequestedAfterMap)442 TEST(ProcessInfo, RequestedAfterMap) {
443   ProcessInfo::MemoryBasicInformation64Vector memory_info;
444   MEMORY_BASIC_INFORMATION64 mbi = {0};
445 
446   mbi.BaseAddress = 10;
447   mbi.RegionSize = 10;
448   mbi.State = MEM_COMMIT;
449   memory_info.push_back(mbi);
450 
451   std::vector<CheckedRange<WinVMAddress, WinVMSize>> result =
452       GetReadableRangesOfMemoryMap(
453           CheckedRange<WinVMAddress, WinVMSize>(15, 100), memory_info);
454 
455   ASSERT_EQ(result.size(), 1u);
456   EXPECT_EQ(result[0].base(), 15u);
457   EXPECT_EQ(result[0].size(), 5u);
458 }
459 
TEST(ProcessInfo,ReadableRanges)460 TEST(ProcessInfo, ReadableRanges) {
461   SYSTEM_INFO system_info;
462   GetSystemInfo(&system_info);
463 
464   const size_t kBlockSize = system_info.dwPageSize;
465 
466   // Allocate 6 pages, and then commit the second, fourth, and fifth, and mark
467   // two as committed, but PAGE_NOACCESS, so we have a setup like this:
468   // 0       1       2       3       4       5
469   // +-----------------------------------------------+
470   // | ????? |       | xxxxx |       |       | ????? |
471   // +-----------------------------------------------+
472   void* reserve_region =
473       VirtualAlloc(nullptr, kBlockSize * 6, MEM_RESERVE, PAGE_READWRITE);
474   ASSERT_TRUE(reserve_region);
475   uintptr_t reserved_as_int = reinterpret_cast<uintptr_t>(reserve_region);
476   void* readable1 =
477       VirtualAlloc(reinterpret_cast<void*>(reserved_as_int + kBlockSize),
478                    kBlockSize,
479                    MEM_COMMIT,
480                    PAGE_READWRITE);
481   ASSERT_TRUE(readable1);
482   void* readable2 =
483       VirtualAlloc(reinterpret_cast<void*>(reserved_as_int + (kBlockSize * 3)),
484                    kBlockSize * 2,
485                    MEM_COMMIT,
486                    PAGE_READWRITE);
487   ASSERT_TRUE(readable2);
488 
489   void* no_access =
490       VirtualAlloc(reinterpret_cast<void*>(reserved_as_int + (kBlockSize * 2)),
491                    kBlockSize,
492                    MEM_COMMIT,
493                    PAGE_NOACCESS);
494   ASSERT_TRUE(no_access);
495 
496   HANDLE current_process = GetCurrentProcess();
497   ProcessInfo info;
498   info.Initialize(current_process);
499   auto ranges = info.GetReadableRanges(
500       CheckedRange<WinVMAddress, WinVMSize>(reserved_as_int, kBlockSize * 6));
501 
502   ASSERT_EQ(ranges.size(), 2u);
503   EXPECT_EQ(ranges[0].base(), reserved_as_int + kBlockSize);
504   EXPECT_EQ(ranges[0].size(), kBlockSize);
505   EXPECT_EQ(ranges[1].base(), reserved_as_int + (kBlockSize * 3));
506   EXPECT_EQ(ranges[1].size(), kBlockSize * 2);
507 
508   // Also make sure what we think we can read corresponds with what we can
509   // actually read.
510   std::unique_ptr<unsigned char[]> into(new unsigned char[kBlockSize * 6]);
511   SIZE_T bytes_read;
512 
513   EXPECT_TRUE(ReadProcessMemory(
514       current_process, readable1, into.get(), kBlockSize, &bytes_read));
515   EXPECT_EQ(bytes_read, kBlockSize);
516 
517   EXPECT_TRUE(ReadProcessMemory(
518       current_process, readable2, into.get(), kBlockSize * 2, &bytes_read));
519   EXPECT_EQ(bytes_read, kBlockSize * 2);
520 
521   EXPECT_FALSE(ReadProcessMemory(
522       current_process, no_access, into.get(), kBlockSize, &bytes_read));
523   EXPECT_FALSE(ReadProcessMemory(
524       current_process, reserve_region, into.get(), kBlockSize, &bytes_read));
525   EXPECT_FALSE(ReadProcessMemory(current_process,
526                                  reserve_region,
527                                  into.get(),
528                                  kBlockSize * 6,
529                                  &bytes_read));
530 }
531 
TEST(ProcessInfo,Handles)532 TEST(ProcessInfo, Handles) {
533   ScopedTempDir temp_dir;
534 
535   ScopedFileHandle file(LoggingOpenFileForWrite(
536       temp_dir.path().Append(FILE_PATH_LITERAL("test_file")),
537       FileWriteMode::kTruncateOrCreate,
538       FilePermissions::kWorldReadable));
539   ASSERT_TRUE(file.is_valid());
540 
541   SECURITY_ATTRIBUTES security_attributes = {0};
542   security_attributes.nLength = sizeof(security_attributes);
543   security_attributes.bInheritHandle = true;
544   ScopedFileHandle inherited_file(CreateFile(
545       temp_dir.path().Append(FILE_PATH_LITERAL("inheritable")).value().c_str(),
546       GENERIC_WRITE,
547       0,
548       &security_attributes,
549       CREATE_NEW,
550       FILE_ATTRIBUTE_NORMAL,
551       nullptr));
552   ASSERT_TRUE(inherited_file.is_valid());
553 
554   HKEY key;
555   ASSERT_EQ(RegOpenKeyEx(
556                 HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft", 0, KEY_READ, &key),
557             ERROR_SUCCESS);
558   ScopedRegistryKey scoped_key(key);
559   ASSERT_TRUE(scoped_key.is_valid());
560 
561   std::wstring mapping_name =
562       base::UTF8ToWide(base::StringPrintf("Local\\test_mapping_%lu_%s",
563                                           GetCurrentProcessId(),
564                                           RandomString().c_str()));
565   ScopedKernelHANDLE mapping(CreateFileMapping(INVALID_HANDLE_VALUE,
566                                                nullptr,
567                                                PAGE_READWRITE,
568                                                0,
569                                                1024,
570                                                mapping_name.c_str()));
571   ASSERT_TRUE(mapping.is_valid()) << ErrorMessage("CreateFileMapping");
572 
573   ProcessInfo info;
574   info.Initialize(GetCurrentProcess());
575   bool found_file_handle = false;
576   bool found_inherited_file_handle = false;
577   bool found_key_handle = false;
578   bool found_mapping_handle = false;
579   for (auto handle : info.Handles()) {
580     if (handle.handle == HandleToInt(file.get())) {
581       EXPECT_FALSE(found_file_handle);
582       found_file_handle = true;
583       EXPECT_EQ(handle.type_name, L"File");
584       EXPECT_EQ(handle.handle_count, 1u);
585       EXPECT_NE(handle.pointer_count, 0u);
586       EXPECT_EQ(handle.granted_access & STANDARD_RIGHTS_ALL,
587                 static_cast<uint32_t>(STANDARD_RIGHTS_READ |
588                                       STANDARD_RIGHTS_WRITE | SYNCHRONIZE));
589       EXPECT_EQ(handle.attributes, 0u);
590     }
591     if (handle.handle == HandleToInt(inherited_file.get())) {
592       EXPECT_FALSE(found_inherited_file_handle);
593       found_inherited_file_handle = true;
594       EXPECT_EQ(handle.type_name, L"File");
595       EXPECT_EQ(handle.handle_count, 1u);
596       EXPECT_NE(handle.pointer_count, 0u);
597       EXPECT_EQ(handle.granted_access & STANDARD_RIGHTS_ALL,
598                 static_cast<uint32_t>(STANDARD_RIGHTS_READ |
599                                       STANDARD_RIGHTS_WRITE | SYNCHRONIZE));
600 
601       // OBJ_INHERIT from ntdef.h, but including that conflicts with other
602       // headers.
603       constexpr uint32_t kObjInherit = 0x2;
604       EXPECT_EQ(handle.attributes, kObjInherit);
605     }
606     if (handle.handle == HandleToInt(scoped_key.get())) {
607       EXPECT_FALSE(found_key_handle);
608       found_key_handle = true;
609       EXPECT_EQ(handle.type_name, L"Key");
610       EXPECT_EQ(handle.handle_count, 1u);
611       EXPECT_NE(handle.pointer_count, 0u);
612       EXPECT_EQ(handle.granted_access & STANDARD_RIGHTS_ALL,
613                 static_cast<uint32_t>(STANDARD_RIGHTS_READ));
614       EXPECT_EQ(handle.attributes, 0u);
615     }
616     if (handle.handle == HandleToInt(mapping.get())) {
617       EXPECT_FALSE(found_mapping_handle);
618       found_mapping_handle = true;
619       EXPECT_EQ(handle.type_name, L"Section");
620       EXPECT_EQ(handle.handle_count, 1u);
621       EXPECT_NE(handle.pointer_count, 0u);
622       EXPECT_EQ(handle.granted_access & STANDARD_RIGHTS_ALL,
623                 static_cast<uint32_t>(DELETE | READ_CONTROL | WRITE_DAC |
624                                       WRITE_OWNER | STANDARD_RIGHTS_READ |
625                                       STANDARD_RIGHTS_WRITE));
626       EXPECT_EQ(handle.attributes, 0u);
627     }
628   }
629   EXPECT_TRUE(found_file_handle);
630   EXPECT_TRUE(found_inherited_file_handle);
631   EXPECT_TRUE(found_key_handle);
632   EXPECT_TRUE(found_mapping_handle);
633 }
634 
TEST(ProcessInfo,OutOfRangeCheck)635 TEST(ProcessInfo, OutOfRangeCheck) {
636   constexpr size_t kAllocationSize = 12345;
637   std::unique_ptr<char[]> safe_memory(new char[kAllocationSize]);
638 
639   ProcessInfo info;
640   info.Initialize(GetCurrentProcess());
641 
642   EXPECT_TRUE(
643       info.LoggingRangeIsFullyReadable(CheckedRange<WinVMAddress, WinVMSize>(
644           FromPointerCast<WinVMAddress>(safe_memory.get()), kAllocationSize)));
645   EXPECT_FALSE(info.LoggingRangeIsFullyReadable(
646       CheckedRange<WinVMAddress, WinVMSize>(0, 1024)));
647 }
648 
649 }  // namespace
650 }  // namespace test
651 }  // namespace crashpad
652