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