1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/chrome_elf/nt_registry/nt_registry.h"
6
7 #include <windows.h>
8
9 #include <rpc.h>
10 #include <stddef.h>
11
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/stl_util.h"
15 #include "base/test/test_reg_util_win.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace {
19
20 //------------------------------------------------------------------------------
21 // WOW64 redirection tests
22 //
23 // - Only HKCU will be tested on the auto (try) bots.
24 // HKLM will be kept separate (and manual) for local testing only.
25 //
26 // NOTE: Currently no real WOW64 context testing, as building x86 projects
27 // during x64 builds is not currently supported for performance reasons.
28 // https://cs.chromium.org/chromium/src/build/toolchain/win/BUILD.gn?sq%3Dpackage:chromium&l=314
29 //------------------------------------------------------------------------------
30
31 // Utility function for the WOW64 redirection test suites.
32 // Note: Testing redirection through ADVAPI32 here as well, to get notice if
33 // expected behaviour changes!
34 // If |redirected_path| == nullptr, no redirection is expected in any case.
DoRedirectTest(nt::ROOT_KEY nt_root_key,const wchar_t * path,const wchar_t * redirected_path OPTIONAL)35 void DoRedirectTest(nt::ROOT_KEY nt_root_key,
36 const wchar_t* path,
37 const wchar_t* redirected_path OPTIONAL) {
38 HANDLE handle = INVALID_HANDLE_VALUE;
39 HKEY key_handle = nullptr;
40 constexpr ACCESS_MASK kAccess = KEY_WRITE | DELETE;
41 const HKEY root_key =
42 (nt_root_key == nt::HKCU) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
43
44 // Make sure clean before starting.
45 nt::DeleteRegKey(nt_root_key, nt::NONE, path);
46 if (redirected_path)
47 nt::DeleteRegKey(nt_root_key, nt::NONE, redirected_path);
48
49 //----------------------------------------------------------------------------
50 // No redirection through ADVAPI32 on straight x86 or x64.
51 ASSERT_EQ(ERROR_SUCCESS,
52 RegCreateKeyExW(root_key, path, 0, nullptr, REG_OPTION_NON_VOLATILE,
53 kAccess, nullptr, &key_handle, nullptr));
54 ASSERT_EQ(ERROR_SUCCESS, RegCloseKey(key_handle));
55 ASSERT_TRUE(nt::OpenRegKey(nt_root_key, path, kAccess, &handle, nullptr));
56 ASSERT_TRUE(nt::DeleteRegKey(handle));
57 nt::CloseRegKey(handle);
58
59 #ifdef _WIN64
60 //----------------------------------------------------------------------------
61 // Try forcing WOW64 redirection on x64 through ADVAPI32.
62 ASSERT_EQ(ERROR_SUCCESS,
63 RegCreateKeyExW(root_key, path, 0, nullptr, REG_OPTION_NON_VOLATILE,
64 kAccess | KEY_WOW64_32KEY, nullptr, &key_handle,
65 nullptr));
66 ASSERT_EQ(ERROR_SUCCESS, RegCloseKey(key_handle));
67 // Check path:
68 if (nt::OpenRegKey(nt_root_key, path, kAccess, &handle, nullptr)) {
69 if (redirected_path)
70 ADD_FAILURE();
71 ASSERT_TRUE(nt::DeleteRegKey(handle));
72 nt::CloseRegKey(handle);
73 } else if (!redirected_path) {
74 // Should have succeeded.
75 ADD_FAILURE();
76 }
77 if (redirected_path) {
78 // Check redirected path:
79 if (nt::OpenRegKey(nt_root_key, redirected_path, kAccess, &handle,
80 nullptr)) {
81 if (!redirected_path)
82 ADD_FAILURE();
83 ASSERT_TRUE(nt::DeleteRegKey(handle));
84 nt::CloseRegKey(handle);
85 } else {
86 // Should have succeeded.
87 ADD_FAILURE();
88 }
89 }
90
91 //----------------------------------------------------------------------------
92 // Try forcing WOW64 redirection on x64 through NTDLL.
93 ASSERT_TRUE(
94 nt::CreateRegKey(nt_root_key, path, kAccess | KEY_WOW64_32KEY, nullptr));
95 // Check path:
96 if (nt::OpenRegKey(nt_root_key, path, kAccess, &handle, nullptr)) {
97 if (redirected_path)
98 ADD_FAILURE();
99 ASSERT_TRUE(nt::DeleteRegKey(handle));
100 nt::CloseRegKey(handle);
101 } else if (!redirected_path) {
102 // Should have succeeded.
103 ADD_FAILURE();
104 }
105 if (redirected_path) {
106 // Check redirected path:
107 if (nt::OpenRegKey(nt_root_key, redirected_path, kAccess, &handle,
108 nullptr)) {
109 if (!redirected_path)
110 ADD_FAILURE();
111 ASSERT_TRUE(nt::DeleteRegKey(handle));
112 nt::CloseRegKey(handle);
113 } else {
114 // Should have succeeded.
115 ADD_FAILURE();
116 }
117 }
118 #endif // _WIN64
119 }
120
121 // These test reg paths match |kClassesSubtree| in nt_registry.cc.
122 constexpr const wchar_t* kClassesRedirects[] = {
123 L"SOFTWARE\\Classes\\CLSID\\chrome_testing",
124 L"SOFTWARE\\Classes\\WOW6432Node\\CLSID\\chrome_testing",
125 L"SOFTWARE\\Classes\\DirectShow\\chrome_testing",
126 L"SOFTWARE\\Classes\\WOW6432Node\\DirectShow\\chrome_testing",
127 L"SOFTWARE\\Classes\\Interface\\chrome_testing",
128 L"SOFTWARE\\Classes\\WOW6432Node\\Interface\\chrome_testing",
129 L"SOFTWARE\\Classes\\Media Type\\chrome_testing",
130 L"SOFTWARE\\Classes\\WOW6432Node\\Media Type\\chrome_testing",
131 L"SOFTWARE\\Classes\\MediaFoundation\\chrome_testing",
132 L"SOFTWARE\\Classes\\WOW6432Node\\MediaFoundation\\chrome_testing"};
133
134 static_assert((_countof(kClassesRedirects) & 0x01) == 0,
135 "Must have an even number of kClassesRedirects.");
136
137 // This test does NOT use NtRegistryTest class. It requires Windows WOW64
138 // redirection to take place, which would not happen with a testing redirection
139 // layer.
TEST(NtRegistryTestRedirection,Wow64RedirectionHKCU)140 TEST(NtRegistryTestRedirection, Wow64RedirectionHKCU) {
141 // Using two elements for each loop.
142 for (size_t index = 0; index < _countof(kClassesRedirects); index += 2) {
143 DoRedirectTest(nt::HKCU, kClassesRedirects[index],
144 kClassesRedirects[index + 1]);
145 }
146 }
147
148 // These test reg paths match |kHklmSoftwareSubtree| in nt_registry.cc.
149 constexpr const wchar_t* kHKLMNoRedirects[] = {
150 L"SOFTWARE\\Classes\\chrome_testing",
151 L"SOFTWARE\\Clients\\chrome_testing",
152 L"SOFTWARE\\Microsoft\\COM3\\chrome_testing",
153 L"SOFTWARE\\Microsoft\\Cryptography\\Calais\\Current\\chrome_testing",
154 L"SOFTWARE\\Microsoft\\Cryptography\\Calais\\Readers\\chrome_testing",
155 L"SOFTWARE\\Microsoft\\Cryptography\\Services\\chrome_testing",
156 L"SOFTWARE\\Microsoft\\CTF\\SystemShared\\chrome_testing",
157 L"SOFTWARE\\Microsoft\\CTF\\TIP\\chrome_testing",
158 L"SOFTWARE\\Microsoft\\DFS\\chrome_testing",
159 L"SOFTWARE\\Microsoft\\Driver Signing\\chrome_testing",
160 L"SOFTWARE\\Microsoft\\EnterpriseCertificates\\chrome_testing",
161 L"SOFTWARE\\Microsoft\\EventSystem\\chrome_testing",
162 L"SOFTWARE\\Microsoft\\MSMQ\\chrome_testing",
163 L"SOFTWARE\\Microsoft\\Non-Driver Signing\\chrome_testing",
164 L"SOFTWARE\\Microsoft\\Notepad\\DefaultFonts\\chrome_testing",
165 L"SOFTWARE\\Microsoft\\OLE\\chrome_testing",
166 L"SOFTWARE\\Microsoft\\RAS\\chrome_testing",
167 L"SOFTWARE\\Microsoft\\RPC\\chrome_testing",
168 L"SOFTWARE\\Microsoft\\SOFTWARE\\Microsoft\\Shared "
169 L"Tools\\MSInfo\\chrome_testing",
170 L"SOFTWARE\\Microsoft\\SystemCertificates\\chrome_testing",
171 L"SOFTWARE\\Microsoft\\TermServLicensing\\chrome_testing",
172 L"SOFTWARE\\Microsoft\\Transaction Server\\chrome_testing",
173 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App "
174 L"Paths\\chrome_testing",
175 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control "
176 L"Panel\\Cursors\\Schemes\\chrome_testing",
177 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers"
178 L"\\chrome_testing",
179 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons"
180 L"\\chrome_testing",
181 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap"
182 L"\\chrome_testing",
183 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group "
184 L"Policy\\chrome_testing",
185 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\chrome_testing",
186 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers"
187 L"\\chrome_testing",
188 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\chrome_testing",
189 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations"
190 L"\\chrome_testing",
191 L"SOFTWARE\\Microsoft\\Windows "
192 L"NT\\CurrentVersion\\Console\\chrome_testing",
193 L"SOFTWARE\\Microsoft\\Windows "
194 L"NT\\CurrentVersion\\FontDpi\\chrome_testing",
195 L"SOFTWARE\\Microsoft\\Windows "
196 L"NT\\CurrentVersion\\FontLink\\chrome_testing",
197 L"SOFTWARE\\Microsoft\\Windows "
198 L"NT\\CurrentVersion\\FontMapper\\chrome_testing",
199 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\chrome_testing",
200 L"SOFTWARE\\Microsoft\\Windows "
201 L"NT\\CurrentVersion\\FontSubstitutes\\chrome_testing",
202 L"SOFTWARE\\Microsoft\\Windows "
203 L"NT\\CurrentVersion\\Gre_initialize\\chrome_testing",
204 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution "
205 L"Options\\chrome_testing",
206 L"SOFTWARE\\Microsoft\\Windows "
207 L"NT\\CurrentVersion\\LanguagePack\\chrome_testing",
208 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"
209 L"\\chrome_testing",
210 L"SOFTWARE\\Microsoft\\Windows "
211 L"NT\\CurrentVersion\\Perflib\\chrome_testing",
212 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports\\chrome_testing",
213 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\chrome_testing",
214 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
215 L"\\chrome_testing",
216 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time "
217 L"Zones\\chrome_testing",
218 L"SOFTWARE\\Policies\\chrome_testing",
219 L"SOFTWARE\\RegisteredApplications\\chrome_testing"};
220
221 // Run from administrator command prompt!
222 // Note: Disabled for automated testing (HKLM protection). Local testing
223 // only.
224 //
225 // This test does NOT use NtRegistryTest class. It requires Windows WOW64
226 // redirection to take place, which would not happen with a testing redirection
227 // layer.
TEST(NtRegistryTestRedirection,DISABLED_Wow64RedirectionHKLM)228 TEST(NtRegistryTestRedirection, DISABLED_Wow64RedirectionHKLM) {
229 // 1) SOFTWARE is redirected.
230 DoRedirectTest(nt::HKLM, L"SOFTWARE\\chrome_testing",
231 L"SOFTWARE\\WOW6432Node\\chrome_testing");
232
233 // 2) Except some subkeys are not.
234 for (size_t index = 0; index < _countof(kHKLMNoRedirects); ++index) {
235 DoRedirectTest(nt::HKLM, kHKLMNoRedirects[index], nullptr);
236 }
237
238 // 3) But then some Classes subkeys are redirected.
239 // Using two elements for each loop.
240 for (size_t index = 0; index < _countof(kClassesRedirects); index += 2) {
241 DoRedirectTest(nt::HKLM, kClassesRedirects[index],
242 kClassesRedirects[index + 1]);
243 }
244
245 // 4) And just make sure other Classes subkeys are shared.
246 DoRedirectTest(nt::HKLM, L"SOFTWARE\\Classes\\chrome_testing", nullptr);
247 }
248
TEST(NtRegistryTestMisc,SanitizeSubkeyPaths)249 TEST(NtRegistryTestMisc, SanitizeSubkeyPaths) {
250 std::wstring new_path;
251 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
252 std::wstring sani_path = nt::GetTestingOverride(nt::HKCU);
253 EXPECT_STREQ(L"", sani_path.c_str());
254
255 new_path = L"boo";
256 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
257 sani_path = nt::GetTestingOverride(nt::HKCU);
258 EXPECT_STREQ(L"boo", sani_path.c_str());
259
260 new_path = L"\\boo";
261 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
262 sani_path = nt::GetTestingOverride(nt::HKCU);
263 EXPECT_STREQ(L"boo", sani_path.c_str());
264
265 new_path = L"boo\\";
266 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
267 sani_path = nt::GetTestingOverride(nt::HKCU);
268 EXPECT_STREQ(L"boo", sani_path.c_str());
269
270 new_path = L"\\\\\\";
271 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
272 sani_path = nt::GetTestingOverride(nt::HKCU);
273 EXPECT_STREQ(L"", sani_path.c_str());
274
275 new_path = L"boo\\\\\\ya";
276 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
277 sani_path = nt::GetTestingOverride(nt::HKCU);
278 EXPECT_STREQ(L"boo\\ya", sani_path.c_str());
279
280 new_path = L"\\\\\\boo\\ya\\\\";
281 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
282 sani_path = nt::GetTestingOverride(nt::HKCU);
283 EXPECT_STREQ(L"boo\\ya", sani_path.c_str());
284
285 // Be sure to leave the environment clean.
286 new_path.clear();
287 EXPECT_TRUE(nt::SetTestingOverride(nt::HKCU, new_path));
288 sani_path = nt::GetTestingOverride(nt::HKCU);
289 EXPECT_STREQ(L"", sani_path.c_str());
290 }
291
292 //------------------------------------------------------------------------------
293 // NtRegistryTest class
294 //
295 // Only use this class for tests that need testing registry redirection.
296 //------------------------------------------------------------------------------
297
298 class NtRegistryTest : public testing::Test {
299 protected:
SetUp()300 void SetUp() override {
301 base::string16 temp;
302 ASSERT_NO_FATAL_FAILURE(
303 override_manager_.OverrideRegistry(HKEY_CURRENT_USER, &temp));
304 ASSERT_TRUE(nt::SetTestingOverride(nt::HKCU, temp));
305 ASSERT_NO_FATAL_FAILURE(
306 override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, &temp));
307 ASSERT_TRUE(nt::SetTestingOverride(nt::HKLM, temp));
308 }
309
TearDown()310 void TearDown() override {
311 base::string16 temp;
312 ASSERT_TRUE(nt::SetTestingOverride(nt::HKCU, temp));
313 ASSERT_TRUE(nt::SetTestingOverride(nt::HKLM, temp));
314 }
315
316 private:
317 registry_util::RegistryOverrideManager override_manager_;
318 };
319
320 //------------------------------------------------------------------------------
321 // NT registry API tests
322 //------------------------------------------------------------------------------
323
TEST_F(NtRegistryTest,ApiDword)324 TEST_F(NtRegistryTest, ApiDword) {
325 HANDLE key_handle;
326 const wchar_t* dword_val_name = L"DwordTestValue";
327 DWORD dword_val = 1234;
328
329 // Create a subkey to play under.
330 ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, L"NTRegistry\\dword", KEY_ALL_ACCESS,
331 &key_handle));
332 ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
333 ASSERT_NE(key_handle, nullptr);
334 base::ScopedClosureRunner key_closer(
335 base::BindOnce(&nt::CloseRegKey, key_handle));
336
337 DWORD get_dword = 0;
338 EXPECT_FALSE(nt::QueryRegValueDWORD(key_handle, dword_val_name, &get_dword));
339
340 // Set
341 EXPECT_TRUE(nt::SetRegValueDWORD(key_handle, dword_val_name, dword_val));
342
343 // Get
344 EXPECT_TRUE(nt::QueryRegValueDWORD(key_handle, dword_val_name, &get_dword));
345 EXPECT_EQ(get_dword, dword_val);
346
347 // Clean up done by NtRegistryTest.
348 }
349
TEST_F(NtRegistryTest,ApiSz)350 TEST_F(NtRegistryTest, ApiSz) {
351 HANDLE key_handle;
352 const wchar_t* sz_val_name = L"SzTestValue";
353 std::wstring sz_val = L"blah de blah de blahhhhh.";
354 const wchar_t* sz_val_name2 = L"SzTestValueEmpty";
355 std::wstring sz_val2;
356 const wchar_t* sz_val_name3 = L"SzTestValueMalformed";
357 const wchar_t* sz_val_name4 = L"SzTestValueMalformed2";
358 std::wstring sz_val3 = L"malformed";
359 BYTE* sz_val3_byte = reinterpret_cast<BYTE*>(&sz_val3[0]);
360 std::vector<BYTE> malform;
361 for (size_t i = 0; i < (sz_val3.size() * sizeof(wchar_t)); i++)
362 malform.push_back(sz_val3_byte[i]);
363 const wchar_t* sz_val_name5 = L"SzTestValueSize0";
364
365 // Create a subkey to play under.
366 // ------------------------------
367 ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, L"NTRegistry\\sz", KEY_ALL_ACCESS,
368 &key_handle));
369 ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
370 ASSERT_NE(key_handle, nullptr);
371 base::ScopedClosureRunner key_closer(
372 base::BindOnce(&nt::CloseRegKey, key_handle));
373
374 std::wstring get_sz;
375 EXPECT_FALSE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz));
376
377 // Set
378 // ------------------------------
379 EXPECT_TRUE(nt::SetRegValueSZ(key_handle, sz_val_name, sz_val));
380 EXPECT_TRUE(nt::SetRegValueSZ(key_handle, sz_val_name2, sz_val2));
381 // No null terminator.
382 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, sz_val_name3, REG_SZ,
383 malform.data(),
384 static_cast<DWORD>(malform.size())));
385 malform.push_back(0);
386 // Single trailing 0 byte.
387 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, sz_val_name4, REG_SZ,
388 malform.data(),
389 static_cast<DWORD>(malform.size())));
390 // Size 0 value.
391 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, sz_val_name5, REG_SZ, nullptr, 0));
392
393 // Get
394 // ------------------------------
395 EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz));
396 EXPECT_EQ(get_sz, sz_val);
397 EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name2, &get_sz));
398 EXPECT_EQ(get_sz, sz_val2);
399 EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name3, &get_sz));
400 // Should be adjusted under the hood to equal sz_val3.
401 EXPECT_EQ(get_sz, sz_val3);
402 EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name4, &get_sz));
403 // Should be adjusted under the hood to equal sz_val3.
404 EXPECT_EQ(get_sz, sz_val3);
405 EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name5, &get_sz));
406 // Should be adjusted under the hood to an empty string.
407 EXPECT_EQ(get_sz, sz_val2);
408
409 // Clean up done by NtRegistryTest.
410 }
411
TEST_F(NtRegistryTest,ApiMultiSz)412 TEST_F(NtRegistryTest, ApiMultiSz) {
413 HANDLE key_handle;
414 std::vector<std::wstring> multisz_val_set;
415 std::vector<std::wstring> multisz_val_get;
416
417 // Create a subkey to play under.
418 // ------------------------------
419 ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, L"NTRegistry\\multisz", KEY_ALL_ACCESS,
420 &key_handle));
421 ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
422 ASSERT_NE(key_handle, nullptr);
423 base::ScopedClosureRunner key_closer(
424 base::BindOnce(&nt::CloseRegKey, key_handle));
425
426 // Test 1 - Success
427 // ------------------------------
428 const wchar_t* multisz_val_name = L"SzmultiTestValue";
429 std::wstring multi1 = L"one";
430 std::wstring multi2 = L"two";
431 std::wstring multi3 = L"three";
432
433 multisz_val_set.push_back(multi1);
434 multisz_val_set.push_back(multi2);
435 multisz_val_set.push_back(multi3);
436 EXPECT_TRUE(
437 nt::SetRegValueMULTISZ(key_handle, multisz_val_name, multisz_val_set));
438
439 EXPECT_TRUE(
440 nt::QueryRegValueMULTISZ(key_handle, multisz_val_name, &multisz_val_get));
441 EXPECT_EQ(multisz_val_get, multisz_val_set);
442 multisz_val_set.clear();
443 multisz_val_get.clear();
444
445 // Test 2 - Bad value
446 // ------------------------------
447 const wchar_t* multisz_val_name2 = L"SzmultiTestValueBad";
448 std::wstring multi_empty;
449
450 multisz_val_set.push_back(multi_empty);
451 EXPECT_TRUE(
452 nt::SetRegValueMULTISZ(key_handle, multisz_val_name2, multisz_val_set));
453
454 EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name2,
455 &multisz_val_get));
456 EXPECT_EQ(multisz_val_get.size(), static_cast<DWORD>(0));
457 multisz_val_set.clear();
458 multisz_val_get.clear();
459
460 // Test 3 - Malformed
461 // ------------------------------
462 std::wstring multisz_val3 = L"malformed";
463 multisz_val_set.push_back(multisz_val3);
464 BYTE* multisz_val3_byte = reinterpret_cast<BYTE*>(&multisz_val3[0]);
465 std::vector<BYTE> malform;
466 for (size_t i = 0; i < (multisz_val3.size() * sizeof(wchar_t)); i++)
467 malform.push_back(multisz_val3_byte[i]);
468
469 // 3.1: No null terminator.
470 // ------------------------------
471 const wchar_t* multisz_val_name3 = L"SzmultiTestValueMalformed";
472 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name3, REG_MULTI_SZ,
473 malform.data(),
474 static_cast<DWORD>(malform.size())));
475 EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name3,
476 &multisz_val_get));
477 // Should be adjusted under the hood to equal multisz_val3.
478 EXPECT_EQ(multisz_val_get, multisz_val_set);
479 multisz_val_get.clear();
480
481 // 3.2: Single trailing 0 byte.
482 // ------------------------------
483 const wchar_t* multisz_val_name4 = L"SzmultiTestValueMalformed2";
484 malform.push_back(0);
485 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name4, REG_MULTI_SZ,
486 malform.data(),
487 static_cast<DWORD>(malform.size())));
488 EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name4,
489 &multisz_val_get));
490 // Should be adjusted under the hood to equal multisz_val3.
491 EXPECT_EQ(multisz_val_get, multisz_val_set);
492 multisz_val_get.clear();
493
494 // 3.3: Two trailing 0 bytes.
495 // ------------------------------
496 const wchar_t* multisz_val_name5 = L"SzmultiTestValueMalformed3";
497 malform.push_back(0);
498 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name5, REG_MULTI_SZ,
499 malform.data(),
500 static_cast<DWORD>(malform.size())));
501 EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name5,
502 &multisz_val_get));
503 // Should be adjusted under the hood to equal multisz_val3.
504 EXPECT_EQ(multisz_val_get, multisz_val_set);
505 multisz_val_get.clear();
506
507 // 3.4: Three trailing 0 bytes.
508 // ------------------------------
509 const wchar_t* multisz_val_name6 = L"SzmultiTestValueMalformed4";
510 malform.push_back(0);
511 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name6, REG_MULTI_SZ,
512 malform.data(),
513 static_cast<DWORD>(malform.size())));
514 EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name6,
515 &multisz_val_get));
516 // Should be adjusted under the hood to equal multisz_val3.
517 EXPECT_EQ(multisz_val_get, multisz_val_set);
518 multisz_val_set.clear();
519 multisz_val_get.clear();
520
521 // Test 4 - Size zero
522 // ------------------------------
523 const wchar_t* multisz_val_name7 = L"SzmultiTestValueSize0";
524 EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name7, REG_MULTI_SZ,
525 nullptr, 0));
526 EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name7,
527 &multisz_val_get));
528 // Should be empty.
529 EXPECT_EQ(multisz_val_get, multisz_val_set);
530
531 // Clean up done by NtRegistryTest.
532 }
533
TEST_F(NtRegistryTest,CreateRegKeyRecursion)534 TEST_F(NtRegistryTest, CreateRegKeyRecursion) {
535 HANDLE key_handle;
536 const wchar_t* sz_new_key_1 = L"test1\\new\\subkey";
537 const wchar_t* sz_new_key_2 = L"test2\\new\\subkey\\blah\\";
538 const wchar_t* sz_new_key_3 = L"\\test3\\new\\subkey\\\\blah2";
539
540 // Tests for CreateRegKey recursion.
541 ASSERT_TRUE(
542 nt::CreateRegKey(nt::HKCU, sz_new_key_1, KEY_ALL_ACCESS, nullptr));
543 EXPECT_TRUE(nt::OpenRegKey(nt::HKCU, sz_new_key_1, KEY_ALL_ACCESS,
544 &key_handle, nullptr));
545 EXPECT_TRUE(nt::DeleteRegKey(key_handle));
546 nt::CloseRegKey(key_handle);
547
548 ASSERT_TRUE(
549 nt::CreateRegKey(nt::HKCU, sz_new_key_2, KEY_ALL_ACCESS, nullptr));
550 EXPECT_TRUE(nt::OpenRegKey(nt::HKCU, sz_new_key_2, KEY_ALL_ACCESS,
551 &key_handle, nullptr));
552 EXPECT_TRUE(nt::DeleteRegKey(key_handle));
553 nt::CloseRegKey(key_handle);
554
555 ASSERT_TRUE(
556 nt::CreateRegKey(nt::HKCU, sz_new_key_3, KEY_ALL_ACCESS, nullptr));
557 EXPECT_TRUE(nt::OpenRegKey(nt::HKCU, L"test3\\new\\subkey\\blah2",
558 KEY_ALL_ACCESS, &key_handle, nullptr));
559 EXPECT_TRUE(nt::DeleteRegKey(key_handle));
560 nt::CloseRegKey(key_handle);
561
562 // Subkey path can be null.
563 ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, nullptr, KEY_ALL_ACCESS, &key_handle));
564 ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
565 ASSERT_NE(key_handle, nullptr);
566 nt::CloseRegKey(key_handle);
567
568 // Clean up done by NtRegistryTest.
569 }
570
TEST_F(NtRegistryTest,ApiEnumeration)571 TEST_F(NtRegistryTest, ApiEnumeration) {
572 HANDLE key_handle;
573 HANDLE subkey_handle;
574 static constexpr wchar_t key[] = L"NTRegistry\\enum";
575 static constexpr wchar_t subkey1[] = L"NTRegistry\\enum\\subkey1";
576 static constexpr wchar_t subkey2[] = L"NTRegistry\\enum\\subkey2";
577 static constexpr wchar_t subkey3[] = L"NTRegistry\\enum\\subkey3";
578 static constexpr const wchar_t* check_names[] = {
579 L"subkey1",
580 L"subkey2",
581 L"subkey3",
582 };
583 // Test out the "(Default)" value name in this suite.
584 static constexpr wchar_t subkey_val_name[] = L"";
585 DWORD subkey_val = 1234;
586
587 // Create a subkey to play under.
588 // ------------------------------
589 ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, key, KEY_ALL_ACCESS, &key_handle));
590 ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
591 ASSERT_NE(key_handle, nullptr);
592 base::ScopedClosureRunner key_closer(
593 base::BindOnce(&nt::CloseRegKey, key_handle));
594
595 // Set
596 // ------------------------------
597 // Sub-subkey with a default value.
598 ASSERT_TRUE(
599 nt::CreateRegKey(nt::HKCU, subkey1, KEY_ALL_ACCESS, &subkey_handle));
600 ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE);
601 ASSERT_NE(subkey_handle, nullptr);
602 EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val));
603 nt::CloseRegKey(subkey_handle);
604
605 // Sub-subkey with a default value.
606 ASSERT_TRUE(
607 nt::CreateRegKey(nt::HKCU, subkey2, KEY_ALL_ACCESS, &subkey_handle));
608 ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE);
609 ASSERT_NE(subkey_handle, nullptr);
610 EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val));
611 nt::CloseRegKey(subkey_handle);
612
613 // Sub-subkey with a default value.
614 ASSERT_TRUE(
615 nt::CreateRegKey(nt::HKCU, subkey3, KEY_ALL_ACCESS, &subkey_handle));
616 ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE);
617 ASSERT_NE(subkey_handle, nullptr);
618 EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val));
619 nt::CloseRegKey(subkey_handle);
620
621 // Get (via enumeration)
622 // ------------------------------
623 ULONG subkey_count = 0;
624 EXPECT_TRUE(nt::QueryRegEnumerationInfo(key_handle, &subkey_count));
625 ASSERT_EQ(subkey_count, ULONG{3});
626
627 std::wstring subkey_name;
628 for (ULONG i = 0; i < subkey_count; i++) {
629 ASSERT_TRUE(nt::QueryRegSubkey(key_handle, i, &subkey_name));
630
631 bool found = false;
632 for (size_t index = 0; index < base::size(check_names); index++) {
633 if (0 == subkey_name.compare(check_names[index])) {
634 found = true;
635 break;
636 }
637 }
638 ASSERT_TRUE(found);
639
640 // Grab the default DWORD value out of this subkey.
641 DWORD value = 0;
642 std::wstring temp(key);
643 temp.append(L"\\");
644 temp.append(subkey_name);
645 EXPECT_TRUE(nt::QueryRegValueDWORD(nt::HKCU, nt::NONE, temp.c_str(),
646 subkey_val_name, &value));
647 EXPECT_EQ(value, subkey_val);
648 }
649 // Also test a known bad index.
650 EXPECT_FALSE(nt::QueryRegSubkey(key_handle, subkey_count, &subkey_name));
651
652 // Clean up done by NtRegistryTest.
653 }
654
655 } // namespace
656