OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 <algorithm> | |
6 #include <cctype> | |
7 | |
8 #include <windows.h> | |
9 #include <winioctl.h> | |
10 | |
11 #include "base/win/scoped_handle.h" | |
12 #include "sandbox/src/nt_internals.h" | |
13 #include "sandbox/src/sandbox.h" | |
14 #include "sandbox/src/sandbox_factory.h" | |
15 #include "sandbox/src/sandbox_policy.h" | |
16 #include "sandbox/src/win_utils.h" | |
17 #include "sandbox/tests/common/controller.h" | |
18 #include "sandbox/tests/common/test_utils.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 #define BINDNTDLL(name) \ | |
22 name ## Function name = reinterpret_cast<name ## Function>( \ | |
23 ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name)) | |
24 | |
25 namespace sandbox { | |
26 | |
27 const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE; | |
28 | |
29 // Creates a file using different desired access. Returns if the call succeeded | |
30 // or not. The first argument in argv is the filename. If the second argument | |
31 // is "read", we try read only access. Otherwise we try read-write access. | |
32 SBOX_TESTS_COMMAND int File_Create(int argc, wchar_t **argv) { | |
33 if (argc != 2) | |
34 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
35 | |
36 bool read = (_wcsicmp(argv[0], L"Read") == 0); | |
37 | |
38 if (read) { | |
39 base::win::ScopedHandle file1(CreateFile( | |
40 argv[1], GENERIC_READ, kSharing, NULL, OPEN_EXISTING, 0, NULL)); | |
41 base::win::ScopedHandle file2(CreateFile( | |
42 argv[1], FILE_EXECUTE, kSharing, NULL, OPEN_EXISTING, 0, NULL)); | |
43 | |
44 if (file1.Get() && file2.Get()) | |
45 return SBOX_TEST_SUCCEEDED; | |
46 return SBOX_TEST_DENIED; | |
47 } else { | |
48 base::win::ScopedHandle file1(CreateFile( | |
49 argv[1], GENERIC_ALL, kSharing, NULL, OPEN_EXISTING, 0, NULL)); | |
50 base::win::ScopedHandle file2(CreateFile( | |
51 argv[1], GENERIC_READ | FILE_WRITE_DATA, kSharing, NULL, OPEN_EXISTING, | |
52 0, NULL)); | |
53 | |
54 if (file1.Get() && file2.Get()) | |
55 return SBOX_TEST_SUCCEEDED; | |
56 return SBOX_TEST_DENIED; | |
57 } | |
58 } | |
59 | |
60 SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t **argv) { | |
61 if (argc != 1) { | |
62 SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
63 } | |
64 | |
65 std::wstring full_path = MakePathToSys(argv[0], false); | |
66 if (full_path.empty()) { | |
67 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
68 } | |
69 | |
70 HANDLE file = ::CreateFileW(full_path.c_str(), GENERIC_READ, kSharing, | |
71 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
72 | |
73 if (INVALID_HANDLE_VALUE != file) { | |
74 ::CloseHandle(file); | |
75 return SBOX_TEST_SUCCEEDED; | |
76 } else { | |
77 if (ERROR_ACCESS_DENIED == ::GetLastError()) { | |
78 return SBOX_TEST_DENIED; | |
79 } else { | |
80 return SBOX_TEST_FAILED; | |
81 } | |
82 } | |
83 return SBOX_TEST_SUCCEEDED; | |
84 } | |
85 | |
86 // Creates the file in parameter using the NtCreateFile api and returns if the | |
87 // call succeeded or not. | |
88 SBOX_TESTS_COMMAND int File_CreateSys32(int argc, wchar_t **argv) { | |
89 BINDNTDLL(NtCreateFile); | |
90 BINDNTDLL(RtlInitUnicodeString); | |
91 if (!NtCreateFile || !RtlInitUnicodeString) | |
92 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
93 | |
94 if (argc != 1) | |
95 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
96 | |
97 std::wstring file(argv[0]); | |
98 if (0 != _wcsnicmp(file.c_str(), kNTObjManPrefix, kNTObjManPrefixLen)) | |
99 file = MakePathToSys(argv[0], true); | |
100 | |
101 UNICODE_STRING object_name; | |
102 RtlInitUnicodeString(&object_name, file.c_str()); | |
103 | |
104 OBJECT_ATTRIBUTES obj_attributes = {0}; | |
105 InitializeObjectAttributes(&obj_attributes, &object_name, | |
106 OBJ_CASE_INSENSITIVE, NULL, NULL); | |
107 | |
108 HANDLE handle; | |
109 IO_STATUS_BLOCK io_block = {0}; | |
110 NTSTATUS status = NtCreateFile(&handle, FILE_READ_DATA, &obj_attributes, | |
111 &io_block, NULL, 0, kSharing, FILE_OPEN, | |
112 0, NULL, 0); | |
113 if (NT_SUCCESS(status)) { | |
114 ::CloseHandle(handle); | |
115 return SBOX_TEST_SUCCEEDED; | |
116 } else if (STATUS_ACCESS_DENIED == status) { | |
117 return SBOX_TEST_DENIED; | |
118 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { | |
119 return SBOX_TEST_NOT_FOUND; | |
120 } | |
121 return SBOX_TEST_FAILED; | |
122 } | |
123 | |
124 // Opens the file in parameter using the NtOpenFile api and returns if the | |
125 // call succeeded or not. | |
126 SBOX_TESTS_COMMAND int File_OpenSys32(int argc, wchar_t **argv) { | |
127 BINDNTDLL(NtOpenFile); | |
128 BINDNTDLL(RtlInitUnicodeString); | |
129 if (!NtOpenFile || !RtlInitUnicodeString) | |
130 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
131 | |
132 if (argc != 1) | |
133 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
134 | |
135 std::wstring file = MakePathToSys(argv[0], true); | |
136 UNICODE_STRING object_name; | |
137 RtlInitUnicodeString(&object_name, file.c_str()); | |
138 | |
139 OBJECT_ATTRIBUTES obj_attributes = {0}; | |
140 InitializeObjectAttributes(&obj_attributes, &object_name, | |
141 OBJ_CASE_INSENSITIVE, NULL, NULL); | |
142 | |
143 HANDLE handle; | |
144 IO_STATUS_BLOCK io_block = {0}; | |
145 NTSTATUS status = NtOpenFile(&handle, FILE_READ_DATA, &obj_attributes, | |
146 &io_block, kSharing, 0); | |
147 if (NT_SUCCESS(status)) { | |
148 ::CloseHandle(handle); | |
149 return SBOX_TEST_SUCCEEDED; | |
150 } else if (STATUS_ACCESS_DENIED == status) { | |
151 return SBOX_TEST_DENIED; | |
152 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { | |
153 return SBOX_TEST_NOT_FOUND; | |
154 } | |
155 return SBOX_TEST_FAILED; | |
156 } | |
157 | |
158 SBOX_TESTS_COMMAND int File_GetDiskSpace(int argc, wchar_t **argv) { | |
159 std::wstring sys_path = MakePathToSys(L"", false); | |
160 if (sys_path.empty()) { | |
161 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
162 } | |
163 ULARGE_INTEGER free_user = {0}; | |
164 ULARGE_INTEGER total = {0}; | |
165 ULARGE_INTEGER free_total = {0}; | |
166 if (::GetDiskFreeSpaceExW(sys_path.c_str(), &free_user, &total, | |
167 &free_total)) { | |
168 if ((total.QuadPart != 0) && (free_total.QuadPart !=0)) { | |
169 return SBOX_TEST_SUCCEEDED; | |
170 } | |
171 } else { | |
172 if (ERROR_ACCESS_DENIED == ::GetLastError()) { | |
173 return SBOX_TEST_DENIED; | |
174 } else { | |
175 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
176 } | |
177 } | |
178 return SBOX_TEST_SUCCEEDED; | |
179 } | |
180 | |
181 // Move a file using the MoveFileEx api and returns if the call succeeded or | |
182 // not. | |
183 SBOX_TESTS_COMMAND int File_Rename(int argc, wchar_t **argv) { | |
184 if (argc != 2) | |
185 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
186 | |
187 if (::MoveFileEx(argv[0], argv[1], 0)) | |
188 return SBOX_TEST_SUCCEEDED; | |
189 | |
190 if (::GetLastError() != ERROR_ACCESS_DENIED) | |
191 return SBOX_TEST_FAILED; | |
192 | |
193 return SBOX_TEST_DENIED; | |
194 } | |
195 | |
196 // Query the attributes of file in parameter using the NtQueryAttributesFile api | |
197 // and NtQueryFullAttributesFile and returns if the call succeeded or not. The | |
198 // second argument in argv is "d" or "f" telling if we expect the attributes to | |
199 // specify a file or a directory. The expected attribute has to match the real | |
200 // attributes for the call to be successful. | |
201 SBOX_TESTS_COMMAND int File_QueryAttributes(int argc, wchar_t **argv) { | |
202 BINDNTDLL(NtQueryAttributesFile); | |
203 BINDNTDLL(NtQueryFullAttributesFile); | |
204 BINDNTDLL(RtlInitUnicodeString); | |
205 if (!NtQueryAttributesFile || !NtQueryFullAttributesFile || | |
206 !RtlInitUnicodeString) | |
207 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
208 | |
209 if (argc != 2) | |
210 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
211 | |
212 bool expect_directory = (L'd' == argv[1][0]); | |
213 | |
214 UNICODE_STRING object_name; | |
215 std::wstring file = MakePathToSys(argv[0], true); | |
216 RtlInitUnicodeString(&object_name, file.c_str()); | |
217 | |
218 OBJECT_ATTRIBUTES obj_attributes = {0}; | |
219 InitializeObjectAttributes(&obj_attributes, &object_name, | |
220 OBJ_CASE_INSENSITIVE, NULL, NULL); | |
221 | |
222 FILE_BASIC_INFORMATION info = {0}; | |
223 FILE_NETWORK_OPEN_INFORMATION full_info = {0}; | |
224 NTSTATUS status1 = NtQueryAttributesFile(&obj_attributes, &info); | |
225 NTSTATUS status2 = NtQueryFullAttributesFile(&obj_attributes, &full_info); | |
226 | |
227 if (status1 != status2) | |
228 return SBOX_TEST_FAILED; | |
229 | |
230 if (NT_SUCCESS(status1)) { | |
231 if (info.FileAttributes != full_info.FileAttributes) | |
232 return SBOX_TEST_FAILED; | |
233 | |
234 bool is_directory1 = (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
235 if (expect_directory == is_directory1) | |
236 return SBOX_TEST_SUCCEEDED; | |
237 } else if (STATUS_ACCESS_DENIED == status1) { | |
238 return SBOX_TEST_DENIED; | |
239 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status1) { | |
240 return SBOX_TEST_NOT_FOUND; | |
241 } | |
242 | |
243 return SBOX_TEST_FAILED; | |
244 } | |
245 | |
246 TEST(FilePolicyTest, DenyNtCreateCalc) { | |
247 TestRunner runner; | |
248 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, | |
249 L"calc.exe")); | |
250 | |
251 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 calc.exe")); | |
252 | |
253 runner.SetTestState(BEFORE_REVERT); | |
254 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe")); | |
255 } | |
256 | |
257 TEST(FilePolicyTest, AllowNtCreateCalc) { | |
258 TestRunner runner; | |
259 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"calc.exe")); | |
260 | |
261 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe")); | |
262 | |
263 runner.SetTestState(BEFORE_REVERT); | |
264 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe")); | |
265 } | |
266 | |
267 TEST(FilePolicyTest, AllowNtCreateWithNativePath) { | |
268 std::wstring calc = MakePathToSys(L"calc.exe", false); | |
269 std::wstring nt_path; | |
270 ASSERT_TRUE(GetNtPathFromWin32Path(calc, &nt_path)); | |
271 TestRunner runner; | |
272 runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, nt_path.c_str()); | |
273 | |
274 wchar_t buff[MAX_PATH]; | |
275 ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str()); | |
276 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff)); | |
277 | |
278 std::transform(nt_path.begin(), nt_path.end(), nt_path.begin(), std::tolower); | |
279 ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str()); | |
280 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff)); | |
281 } | |
282 | |
283 TEST(FilePolicyTest, AllowReadOnly) { | |
284 TestRunner runner; | |
285 | |
286 // Create a temp file because we need write access to it. | |
287 wchar_t temp_directory[MAX_PATH]; | |
288 wchar_t temp_file_name[MAX_PATH]; | |
289 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); | |
290 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u); | |
291 | |
292 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, | |
293 temp_file_name)); | |
294 | |
295 wchar_t command_read[MAX_PATH + 20] = {0}; | |
296 wsprintf(command_read, L"File_Create Read \"%ls\"", temp_file_name); | |
297 wchar_t command_write[MAX_PATH + 20] = {0}; | |
298 wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name); | |
299 | |
300 // Verify that we have read access after revert. | |
301 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_read)); | |
302 | |
303 // Verify that we don't have write access after revert. | |
304 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write)); | |
305 | |
306 // Verify that we really have write access to the file. | |
307 runner.SetTestState(BEFORE_REVERT); | |
308 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write)); | |
309 | |
310 DeleteFile(temp_file_name); | |
311 } | |
312 | |
313 TEST(FilePolicyTest, AllowWildcard) { | |
314 TestRunner runner; | |
315 | |
316 // Create a temp file because we need write access to it. | |
317 wchar_t temp_directory[MAX_PATH]; | |
318 wchar_t temp_file_name[MAX_PATH]; | |
319 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); | |
320 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u); | |
321 | |
322 wcscat_s(temp_directory, MAX_PATH, L"*"); | |
323 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_directory)); | |
324 | |
325 wchar_t command_write[MAX_PATH + 20] = {0}; | |
326 wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name); | |
327 | |
328 // Verify that we have write access after revert. | |
329 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write)); | |
330 | |
331 DeleteFile(temp_file_name); | |
332 } | |
333 | |
334 TEST(FilePolicyTest, AllowNtCreatePatternRule) { | |
335 TestRunner runner; | |
336 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"App*.dll")); | |
337 | |
338 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
339 runner.RunTest(L"File_OpenSys32 appmgmts.dll")); | |
340 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_OpenSys32 appwiz.cpl")); | |
341 | |
342 runner.SetTestState(BEFORE_REVERT); | |
343 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
344 runner.RunTest(L"File_OpenSys32 appmgmts.dll")); | |
345 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_OpenSys32 appwiz.cpl")); | |
346 } | |
347 | |
348 TEST(FilePolicyTest, CheckNotFound) { | |
349 TestRunner runner; | |
350 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"n*.dll")); | |
351 | |
352 EXPECT_EQ(SBOX_TEST_NOT_FOUND, | |
353 runner.RunTest(L"File_OpenSys32 notfound.dll")); | |
354 } | |
355 | |
356 TEST(FilePolicyTest, CheckNoLeak) { | |
357 TestRunner runner; | |
358 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 notfound.exe")); | |
359 } | |
360 | |
361 TEST(FilePolicyTest, TestQueryAttributesFile) { | |
362 TestRunner runner; | |
363 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, | |
364 L"appmgmts.dll")); | |
365 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, | |
366 L"notfound.exe")); | |
367 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"drivers")); | |
368 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_QUERY, | |
369 L"ipconfig.exe")); | |
370 | |
371 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
372 runner.RunTest(L"File_QueryAttributes drivers d")); | |
373 | |
374 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
375 runner.RunTest(L"File_QueryAttributes appmgmts.dll f")); | |
376 | |
377 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
378 runner.RunTest(L"File_QueryAttributes ipconfig.exe f")); | |
379 | |
380 EXPECT_EQ(SBOX_TEST_DENIED, | |
381 runner.RunTest(L"File_QueryAttributes ftp.exe f")); | |
382 | |
383 EXPECT_EQ(SBOX_TEST_NOT_FOUND, | |
384 runner.RunTest(L"File_QueryAttributes notfound.exe f")); | |
385 } | |
386 | |
387 // Makes sure that we don't leak information when there is not policy to allow | |
388 // a path. | |
389 TEST(FilePolicyTest, TestQueryAttributesFileNoPolicy) { | |
390 TestRunner runner; | |
391 EXPECT_EQ(SBOX_TEST_DENIED, | |
392 runner.RunTest(L"File_QueryAttributes ftp.exe f")); | |
393 | |
394 EXPECT_EQ(SBOX_TEST_DENIED, | |
395 runner.RunTest(L"File_QueryAttributes notfound.exe f")); | |
396 } | |
397 | |
398 TEST(FilePolicyTest, TestRename) { | |
399 TestRunner runner; | |
400 | |
401 // Give access to the temp directory. | |
402 wchar_t temp_directory[MAX_PATH]; | |
403 wchar_t temp_file_name1[MAX_PATH]; | |
404 wchar_t temp_file_name2[MAX_PATH]; | |
405 wchar_t temp_file_name3[MAX_PATH]; | |
406 wchar_t temp_file_name4[MAX_PATH]; | |
407 wchar_t temp_file_name5[MAX_PATH]; | |
408 wchar_t temp_file_name6[MAX_PATH]; | |
409 wchar_t temp_file_name7[MAX_PATH]; | |
410 wchar_t temp_file_name8[MAX_PATH]; | |
411 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); | |
412 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name1), 0u); | |
413 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name2), 0u); | |
414 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name3), 0u); | |
415 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name4), 0u); | |
416 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name5), 0u); | |
417 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name6), 0u); | |
418 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name7), 0u); | |
419 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name8), 0u); | |
420 | |
421 | |
422 // Add rules to make file1->file2 succeed. | |
423 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name1)); | |
424 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name2)); | |
425 | |
426 // Add rules to make file3->file4 fail. | |
427 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name3)); | |
428 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, | |
429 temp_file_name4)); | |
430 | |
431 // Add rules to make file5->file6 fail. | |
432 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, | |
433 temp_file_name5)); | |
434 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name6)); | |
435 | |
436 // Add rules to make file7->no_pol_file fail. | |
437 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name7)); | |
438 | |
439 // Delete the files where the files are going to be renamed to. | |
440 ::DeleteFile(temp_file_name2); | |
441 ::DeleteFile(temp_file_name4); | |
442 ::DeleteFile(temp_file_name6); | |
443 ::DeleteFile(temp_file_name8); | |
444 | |
445 | |
446 wchar_t command[MAX_PATH*2 + 20] = {0}; | |
447 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name1, | |
448 temp_file_name2); | |
449 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command)); | |
450 | |
451 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name3, | |
452 temp_file_name4); | |
453 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); | |
454 | |
455 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name5, | |
456 temp_file_name6); | |
457 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); | |
458 | |
459 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name7, | |
460 temp_file_name8); | |
461 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); | |
462 | |
463 | |
464 // Delete all the files in case they are still there. | |
465 ::DeleteFile(temp_file_name1); | |
466 ::DeleteFile(temp_file_name2); | |
467 ::DeleteFile(temp_file_name3); | |
468 ::DeleteFile(temp_file_name4); | |
469 ::DeleteFile(temp_file_name5); | |
470 ::DeleteFile(temp_file_name6); | |
471 ::DeleteFile(temp_file_name7); | |
472 ::DeleteFile(temp_file_name8); | |
473 } | |
474 | |
475 TEST(FilePolicyTest, OpenSys32FilesDenyBecauseOfDir) { | |
476 TestRunner runner; | |
477 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, | |
478 L"notepad.exe")); | |
479 | |
480 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe")); | |
481 | |
482 runner.SetTestState(BEFORE_REVERT); | |
483 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
484 runner.RunTest(L"File_Win32Create notepad.exe")); | |
485 } | |
486 | |
487 TEST(FilePolicyTest, OpenSys32FilesAllowNotepad) { | |
488 TestRunner runner; | |
489 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, | |
490 L"notepad.exe")); | |
491 | |
492 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
493 runner.RunTest(L"File_Win32Create notepad.exe")); | |
494 | |
495 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create calc.exe")); | |
496 | |
497 runner.SetTestState(BEFORE_REVERT); | |
498 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
499 runner.RunTest(L"File_Win32Create notepad.exe")); | |
500 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_Win32Create calc.exe")); | |
501 } | |
502 | |
503 TEST(FilePolicyTest, FileGetDiskSpace) { | |
504 TestRunner runner; | |
505 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_GetDiskSpace")); | |
506 runner.SetTestState(BEFORE_REVERT); | |
507 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace")); | |
508 | |
509 // Add an 'allow' rule in the windows\system32 such that GetDiskFreeSpaceEx | |
510 // succeeds (it does an NtOpenFile) but windows\system32\notepad.exe is | |
511 // denied since there is no wild card in the rule. | |
512 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L"")); | |
513 runner.SetTestState(BEFORE_REVERT); | |
514 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace")); | |
515 | |
516 runner.SetTestState(AFTER_REVERT); | |
517 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace")); | |
518 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe")); | |
519 } | |
520 | |
521 TEST(FilePolicyTest, TestReparsePoint) { | |
522 TestRunner runner; | |
523 | |
524 // Create a temp file because we need write access to it. | |
525 wchar_t temp_directory[MAX_PATH]; | |
526 wchar_t temp_file_name[MAX_PATH]; | |
527 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); | |
528 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u); | |
529 | |
530 // Delete the file and create a directory instead. | |
531 ASSERT_TRUE(::DeleteFile(temp_file_name)); | |
532 ASSERT_TRUE(::CreateDirectory(temp_file_name, NULL)); | |
533 | |
534 // Create a temporary file in the subfolder. | |
535 std::wstring subfolder = temp_file_name; | |
536 std::wstring temp_file_title = subfolder.substr(subfolder.rfind(L"\\") + 1); | |
537 std::wstring temp_file = subfolder + L"\\file_" + temp_file_title; | |
538 | |
539 HANDLE file = ::CreateFile(temp_file.c_str(), FILE_ALL_ACCESS, | |
540 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, | |
541 CREATE_ALWAYS, 0, NULL); | |
542 ASSERT_TRUE(INVALID_HANDLE_VALUE != file); | |
543 ASSERT_TRUE(::CloseHandle(file)); | |
544 | |
545 // Create a temporary file in the temp directory. | |
546 std::wstring temp_dir = temp_directory; | |
547 std::wstring temp_file_in_temp = temp_dir + L"file_" + temp_file_title; | |
548 file = ::CreateFile(temp_file_in_temp.c_str(), FILE_ALL_ACCESS, | |
549 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, | |
550 CREATE_ALWAYS, 0, NULL); | |
551 ASSERT_TRUE(file != NULL); | |
552 ASSERT_TRUE(::CloseHandle(file)); | |
553 | |
554 // Give write access to the temp directory. | |
555 std::wstring temp_dir_wildcard = temp_dir + L"*"; | |
556 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, | |
557 temp_dir_wildcard.c_str())); | |
558 | |
559 // Prepare the command to execute. | |
560 std::wstring command_write; | |
561 command_write += L"File_Create Write \""; | |
562 command_write += temp_file; | |
563 command_write += L"\""; | |
564 | |
565 // Verify that we have write access to the original file | |
566 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write.c_str())); | |
567 | |
568 // Replace the subfolder by a reparse point to %temp%. | |
569 ::DeleteFile(temp_file.c_str()); | |
570 HANDLE dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS, | |
571 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, | |
572 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | |
573 EXPECT_TRUE(INVALID_HANDLE_VALUE != dir); | |
574 | |
575 std::wstring temp_dir_nt; | |
576 temp_dir_nt += L"\\??\\"; | |
577 temp_dir_nt += temp_dir; | |
578 EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str())); | |
579 EXPECT_TRUE(::CloseHandle(dir)); | |
580 | |
581 // Try to open the file again. | |
582 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write.c_str())); | |
583 | |
584 // Remove the reparse point. | |
585 dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS, | |
586 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, | |
587 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, | |
588 NULL); | |
589 EXPECT_TRUE(INVALID_HANDLE_VALUE != dir); | |
590 EXPECT_TRUE(DeleteReparsePoint(dir)); | |
591 EXPECT_TRUE(::CloseHandle(dir)); | |
592 | |
593 // Cleanup. | |
594 EXPECT_TRUE(::DeleteFile(temp_file_in_temp.c_str())); | |
595 EXPECT_TRUE(::RemoveDirectory(subfolder.c_str())); | |
596 } | |
597 | |
598 } // namespace sandbox | |
OLD | NEW |