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