Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sandbox / win / src / file_policy_test.cc
blobf7509bd36efc3415ec84fbbf6a95dbdd7710a155
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.
5 #include <algorithm>
6 #include <cctype>
8 #include <windows.h>
9 #include <winioctl.h>
11 #include "base/win/scoped_handle.h"
12 #include "base/win/windows_version.h"
13 #include "sandbox/win/src/filesystem_policy.h"
14 #include "sandbox/win/src/nt_internals.h"
15 #include "sandbox/win/src/sandbox.h"
16 #include "sandbox/win/src/sandbox_factory.h"
17 #include "sandbox/win/src/sandbox_policy.h"
18 #include "sandbox/win/src/win_utils.h"
19 #include "sandbox/win/tests/common/controller.h"
20 #include "sandbox/win/tests/common/test_utils.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 #define BINDNTDLL(name) \
24 name ## Function name = reinterpret_cast<name ## Function>( \
25 ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
27 namespace sandbox {
29 const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
31 // Creates a file using different desired access. Returns if the call succeeded
32 // or not. The first argument in argv is the filename. The second argument
33 // determines the type of access and the dispositino of the file.
34 SBOX_TESTS_COMMAND int File_Create(int argc, wchar_t **argv) {
35 if (argc != 2)
36 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
38 std::wstring operation(argv[0]);
40 if (operation == L"Read") {
41 base::win::ScopedHandle file1(CreateFile(
42 argv[1], GENERIC_READ, kSharing, NULL, OPEN_EXISTING, 0, NULL));
43 base::win::ScopedHandle file2(CreateFile(
44 argv[1], FILE_EXECUTE, kSharing, NULL, OPEN_EXISTING, 0, NULL));
46 if (file1.IsValid() == file2.IsValid())
47 return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
48 return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
50 } else if (operation == L"Write") {
51 base::win::ScopedHandle file1(CreateFile(
52 argv[1], GENERIC_ALL, kSharing, NULL, OPEN_EXISTING, 0, NULL));
53 base::win::ScopedHandle file2(CreateFile(
54 argv[1], GENERIC_READ | FILE_WRITE_DATA, kSharing, NULL, OPEN_EXISTING,
55 0, NULL));
57 if (file1.IsValid() == file2.IsValid())
58 return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
59 return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
61 } else if (operation == L"ReadCreate") {
62 base::win::ScopedHandle file2(CreateFile(
63 argv[1], GENERIC_READ, kSharing, NULL, CREATE_NEW, 0, NULL));
64 base::win::ScopedHandle file1(CreateFile(
65 argv[1], GENERIC_READ, kSharing, NULL, CREATE_ALWAYS, 0, NULL));
67 if (file1.IsValid() == file2.IsValid())
68 return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
69 return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
72 return SBOX_TEST_INVALID_PARAMETER;
75 SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t **argv) {
76 if (argc != 1) {
77 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
80 base::string16 full_path = MakePathToSys(argv[0], false);
81 if (full_path.empty()) {
82 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
85 HANDLE file = ::CreateFileW(full_path.c_str(), GENERIC_READ, kSharing,
86 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
88 if (INVALID_HANDLE_VALUE != file) {
89 ::CloseHandle(file);
90 return SBOX_TEST_SUCCEEDED;
91 } else {
92 if (ERROR_ACCESS_DENIED == ::GetLastError()) {
93 return SBOX_TEST_DENIED;
94 } else {
95 return SBOX_TEST_FAILED;
98 return SBOX_TEST_SUCCEEDED;
101 // Creates the file in parameter using the NtCreateFile api and returns if the
102 // call succeeded or not.
103 SBOX_TESTS_COMMAND int File_CreateSys32(int argc, wchar_t **argv) {
104 BINDNTDLL(NtCreateFile);
105 BINDNTDLL(RtlInitUnicodeString);
106 if (!NtCreateFile || !RtlInitUnicodeString)
107 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
109 if (argc != 1)
110 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
112 base::string16 file(argv[0]);
113 if (0 != _wcsnicmp(file.c_str(), kNTDevicePrefix, kNTDevicePrefixLen))
114 file = MakePathToSys(argv[0], true);
116 UNICODE_STRING object_name;
117 RtlInitUnicodeString(&object_name, file.c_str());
119 OBJECT_ATTRIBUTES obj_attributes = {};
120 InitializeObjectAttributes(&obj_attributes, &object_name,
121 OBJ_CASE_INSENSITIVE, NULL, NULL);
123 HANDLE handle;
124 IO_STATUS_BLOCK io_block = {};
125 NTSTATUS status = NtCreateFile(&handle, FILE_READ_DATA, &obj_attributes,
126 &io_block, NULL, 0, kSharing, FILE_OPEN,
127 0, NULL, 0);
128 if (NT_SUCCESS(status)) {
129 ::CloseHandle(handle);
130 return SBOX_TEST_SUCCEEDED;
131 } else if (STATUS_ACCESS_DENIED == status) {
132 return SBOX_TEST_DENIED;
133 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
134 return SBOX_TEST_NOT_FOUND;
136 return SBOX_TEST_FAILED;
139 // Opens the file in parameter using the NtOpenFile api and returns if the
140 // call succeeded or not.
141 SBOX_TESTS_COMMAND int File_OpenSys32(int argc, wchar_t **argv) {
142 BINDNTDLL(NtOpenFile);
143 BINDNTDLL(RtlInitUnicodeString);
144 if (!NtOpenFile || !RtlInitUnicodeString)
145 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
147 if (argc != 1)
148 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
150 base::string16 file = MakePathToSys(argv[0], true);
151 UNICODE_STRING object_name;
152 RtlInitUnicodeString(&object_name, file.c_str());
154 OBJECT_ATTRIBUTES obj_attributes = {};
155 InitializeObjectAttributes(&obj_attributes, &object_name,
156 OBJ_CASE_INSENSITIVE, NULL, NULL);
158 HANDLE handle;
159 IO_STATUS_BLOCK io_block = {};
160 NTSTATUS status = NtOpenFile(&handle, FILE_READ_DATA, &obj_attributes,
161 &io_block, kSharing, 0);
162 if (NT_SUCCESS(status)) {
163 ::CloseHandle(handle);
164 return SBOX_TEST_SUCCEEDED;
165 } else if (STATUS_ACCESS_DENIED == status) {
166 return SBOX_TEST_DENIED;
167 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
168 return SBOX_TEST_NOT_FOUND;
170 return SBOX_TEST_FAILED;
173 SBOX_TESTS_COMMAND int File_GetDiskSpace(int argc, wchar_t **argv) {
174 base::string16 sys_path = MakePathToSys(L"", false);
175 if (sys_path.empty()) {
176 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
178 ULARGE_INTEGER free_user = {};
179 ULARGE_INTEGER total = {};
180 ULARGE_INTEGER free_total = {};
181 if (::GetDiskFreeSpaceExW(sys_path.c_str(), &free_user, &total,
182 &free_total)) {
183 if ((total.QuadPart != 0) && (free_total.QuadPart !=0)) {
184 return SBOX_TEST_SUCCEEDED;
186 } else {
187 if (ERROR_ACCESS_DENIED == ::GetLastError()) {
188 return SBOX_TEST_DENIED;
189 } else {
190 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
193 return SBOX_TEST_SUCCEEDED;
196 // Move a file using the MoveFileEx api and returns if the call succeeded or
197 // not.
198 SBOX_TESTS_COMMAND int File_Rename(int argc, wchar_t **argv) {
199 if (argc != 2)
200 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
202 if (::MoveFileEx(argv[0], argv[1], 0))
203 return SBOX_TEST_SUCCEEDED;
205 if (::GetLastError() != ERROR_ACCESS_DENIED)
206 return SBOX_TEST_FAILED;
208 return SBOX_TEST_DENIED;
211 // Query the attributes of file in parameter using the NtQueryAttributesFile api
212 // and NtQueryFullAttributesFile and returns if the call succeeded or not. The
213 // second argument in argv is "d" or "f" telling if we expect the attributes to
214 // specify a file or a directory. The expected attribute has to match the real
215 // attributes for the call to be successful.
216 SBOX_TESTS_COMMAND int File_QueryAttributes(int argc, wchar_t **argv) {
217 BINDNTDLL(NtQueryAttributesFile);
218 BINDNTDLL(NtQueryFullAttributesFile);
219 BINDNTDLL(RtlInitUnicodeString);
220 if (!NtQueryAttributesFile || !NtQueryFullAttributesFile ||
221 !RtlInitUnicodeString)
222 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
224 if (argc != 2)
225 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
227 bool expect_directory = (L'd' == argv[1][0]);
229 UNICODE_STRING object_name;
230 base::string16 file = MakePathToSys(argv[0], true);
231 RtlInitUnicodeString(&object_name, file.c_str());
233 OBJECT_ATTRIBUTES obj_attributes = {};
234 InitializeObjectAttributes(&obj_attributes, &object_name,
235 OBJ_CASE_INSENSITIVE, NULL, NULL);
237 FILE_BASIC_INFORMATION info = {};
238 FILE_NETWORK_OPEN_INFORMATION full_info = {};
239 NTSTATUS status1 = NtQueryAttributesFile(&obj_attributes, &info);
240 NTSTATUS status2 = NtQueryFullAttributesFile(&obj_attributes, &full_info);
242 if (status1 != status2)
243 return SBOX_TEST_FAILED;
245 if (NT_SUCCESS(status1)) {
246 if (info.FileAttributes != full_info.FileAttributes)
247 return SBOX_TEST_FAILED;
249 bool is_directory1 = (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
250 if (expect_directory == is_directory1)
251 return SBOX_TEST_SUCCEEDED;
252 } else if (STATUS_ACCESS_DENIED == status1) {
253 return SBOX_TEST_DENIED;
254 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status1) {
255 return SBOX_TEST_NOT_FOUND;
258 return SBOX_TEST_FAILED;
261 TEST(FilePolicyTest, DenyNtCreateCalc) {
262 TestRunner runner;
263 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY,
264 L"calc.exe"));
266 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 calc.exe"));
268 runner.SetTestState(BEFORE_REVERT);
269 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
272 TEST(FilePolicyTest, AllowNtCreateCalc) {
273 TestRunner runner;
274 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"calc.exe"));
276 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
278 runner.SetTestState(BEFORE_REVERT);
279 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
282 TEST(FilePolicyTest, AllowNtCreateWithNativePath) {
283 if (base::win::GetVersion() < base::win::VERSION_WIN7)
284 return;
286 base::string16 calc = MakePathToSys(L"calc.exe", false);
287 base::string16 nt_path;
288 ASSERT_TRUE(GetNtPathFromWin32Path(calc, &nt_path));
289 TestRunner runner;
290 runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, nt_path.c_str());
292 wchar_t buff[MAX_PATH];
293 ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str());
294 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff));
296 std::transform(nt_path.begin(), nt_path.end(), nt_path.begin(), std::tolower);
297 ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str());
298 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff));
301 TEST(FilePolicyTest, AllowReadOnly) {
302 TestRunner runner;
304 // Create a temp file because we need write access to it.
305 wchar_t temp_directory[MAX_PATH];
306 wchar_t temp_file_name[MAX_PATH];
307 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
308 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
310 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
311 temp_file_name));
313 wchar_t command_read[MAX_PATH + 20] = {};
314 wsprintf(command_read, L"File_Create Read \"%ls\"", temp_file_name);
315 wchar_t command_read_create[MAX_PATH + 20] = {};
316 wsprintf(command_read_create, L"File_Create ReadCreate \"%ls\"",
317 temp_file_name);
318 wchar_t command_write[MAX_PATH + 20] = {};
319 wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
321 // Verify that we cannot create the file after revert.
322 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_read_create));
324 // Verify that we don't have write access after revert.
325 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write));
327 // Verify that we have read access after revert.
328 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_read));
330 // Verify that we really have write access to the file.
331 runner.SetTestState(BEFORE_REVERT);
332 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write));
334 DeleteFile(temp_file_name);
337 // Tests support of "\\\\.\\DeviceName" kind of paths.
338 TEST(FilePolicyTest, AllowImplicitDeviceName) {
339 if (base::win::GetVersion() < base::win::VERSION_WIN7)
340 return;
342 TestRunner runner;
344 wchar_t temp_directory[MAX_PATH];
345 wchar_t temp_file_name[MAX_PATH];
346 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
347 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
349 std::wstring path(temp_file_name);
350 EXPECT_TRUE(ConvertToLongPath(&path));
351 EXPECT_TRUE(GetNtPathFromWin32Path(path, &path));
352 path = path.substr(sandbox::kNTDevicePrefixLen);
354 wchar_t command[MAX_PATH + 20] = {};
355 wsprintf(command, L"File_Create Read \"\\\\.\\%ls\"", path.c_str());
356 path = std::wstring(kNTPrefix) + path;
358 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
359 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, path.c_str()));
360 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
362 DeleteFile(temp_file_name);
365 TEST(FilePolicyTest, AllowWildcard) {
366 TestRunner runner;
368 // Create a temp file because we need write access to it.
369 wchar_t temp_directory[MAX_PATH];
370 wchar_t temp_file_name[MAX_PATH];
371 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
372 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
374 wcscat_s(temp_directory, MAX_PATH, L"*");
375 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_directory));
377 wchar_t command_write[MAX_PATH + 20] = {};
378 wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
380 // Verify that we have write access after revert.
381 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write));
383 DeleteFile(temp_file_name);
386 TEST(FilePolicyTest, AllowNtCreatePatternRule) {
387 TestRunner runner;
388 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"App*.dll"));
390 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
391 runner.RunTest(L"File_OpenSys32 appmgmts.dll"));
392 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_OpenSys32 appwiz.cpl"));
394 runner.SetTestState(BEFORE_REVERT);
395 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
396 runner.RunTest(L"File_OpenSys32 appmgmts.dll"));
397 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_OpenSys32 appwiz.cpl"));
400 TEST(FilePolicyTest, CheckNotFound) {
401 TestRunner runner;
402 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"n*.dll"));
404 EXPECT_EQ(SBOX_TEST_NOT_FOUND,
405 runner.RunTest(L"File_OpenSys32 notfound.dll"));
408 TEST(FilePolicyTest, CheckNoLeak) {
409 TestRunner runner;
410 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 notfound.exe"));
413 TEST(FilePolicyTest, TestQueryAttributesFile) {
414 TestRunner runner;
415 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY,
416 L"appmgmts.dll"));
417 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY,
418 L"notfound.exe"));
419 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"drivers"));
420 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_QUERY,
421 L"ipconfig.exe"));
423 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
424 runner.RunTest(L"File_QueryAttributes drivers d"));
426 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
427 runner.RunTest(L"File_QueryAttributes appmgmts.dll f"));
429 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
430 runner.RunTest(L"File_QueryAttributes ipconfig.exe f"));
432 EXPECT_EQ(SBOX_TEST_DENIED,
433 runner.RunTest(L"File_QueryAttributes ftp.exe f"));
435 EXPECT_EQ(SBOX_TEST_NOT_FOUND,
436 runner.RunTest(L"File_QueryAttributes notfound.exe f"));
439 // Makes sure that we don't leak information when there is not policy to allow
440 // a path.
441 TEST(FilePolicyTest, TestQueryAttributesFileNoPolicy) {
442 TestRunner runner;
443 EXPECT_EQ(SBOX_TEST_DENIED,
444 runner.RunTest(L"File_QueryAttributes ftp.exe f"));
446 EXPECT_EQ(SBOX_TEST_DENIED,
447 runner.RunTest(L"File_QueryAttributes notfound.exe f"));
450 TEST(FilePolicyTest, TestRename) {
451 TestRunner runner;
453 // Give access to the temp directory.
454 wchar_t temp_directory[MAX_PATH];
455 wchar_t temp_file_name1[MAX_PATH];
456 wchar_t temp_file_name2[MAX_PATH];
457 wchar_t temp_file_name3[MAX_PATH];
458 wchar_t temp_file_name4[MAX_PATH];
459 wchar_t temp_file_name5[MAX_PATH];
460 wchar_t temp_file_name6[MAX_PATH];
461 wchar_t temp_file_name7[MAX_PATH];
462 wchar_t temp_file_name8[MAX_PATH];
463 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
464 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name1), 0u);
465 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name2), 0u);
466 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name3), 0u);
467 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name4), 0u);
468 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name5), 0u);
469 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name6), 0u);
470 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name7), 0u);
471 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name8), 0u);
474 // Add rules to make file1->file2 succeed.
475 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name1));
476 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name2));
478 // Add rules to make file3->file4 fail.
479 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name3));
480 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
481 temp_file_name4));
483 // Add rules to make file5->file6 fail.
484 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
485 temp_file_name5));
486 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name6));
488 // Add rules to make file7->no_pol_file fail.
489 ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name7));
491 // Delete the files where the files are going to be renamed to.
492 ::DeleteFile(temp_file_name2);
493 ::DeleteFile(temp_file_name4);
494 ::DeleteFile(temp_file_name6);
495 ::DeleteFile(temp_file_name8);
497 wchar_t command[MAX_PATH * 2 + 20] = {};
498 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name1,
499 temp_file_name2);
500 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
502 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name3,
503 temp_file_name4);
504 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
506 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name5,
507 temp_file_name6);
508 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
510 wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name7,
511 temp_file_name8);
512 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
515 // Delete all the files in case they are still there.
516 ::DeleteFile(temp_file_name1);
517 ::DeleteFile(temp_file_name2);
518 ::DeleteFile(temp_file_name3);
519 ::DeleteFile(temp_file_name4);
520 ::DeleteFile(temp_file_name5);
521 ::DeleteFile(temp_file_name6);
522 ::DeleteFile(temp_file_name7);
523 ::DeleteFile(temp_file_name8);
526 TEST(FilePolicyTest, OpenSys32FilesDenyBecauseOfDir) {
527 TestRunner runner;
528 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY,
529 L"notepad.exe"));
531 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe"));
533 runner.SetTestState(BEFORE_REVERT);
534 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
535 runner.RunTest(L"File_Win32Create notepad.exe"));
538 TEST(FilePolicyTest, OpenSys32FilesAllowNotepad) {
539 TestRunner runner;
540 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY,
541 L"notepad.exe"));
543 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
544 runner.RunTest(L"File_Win32Create notepad.exe"));
546 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create calc.exe"));
548 runner.SetTestState(BEFORE_REVERT);
549 EXPECT_EQ(SBOX_TEST_SUCCEEDED,
550 runner.RunTest(L"File_Win32Create notepad.exe"));
551 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_Win32Create calc.exe"));
554 TEST(FilePolicyTest, FileGetDiskSpace) {
555 TestRunner runner;
556 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_GetDiskSpace"));
557 runner.SetTestState(BEFORE_REVERT);
558 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
560 // Add an 'allow' rule in the windows\system32 such that GetDiskFreeSpaceEx
561 // succeeds (it does an NtOpenFile) but windows\system32\notepad.exe is
562 // denied since there is no wild card in the rule.
563 EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L""));
564 runner.SetTestState(BEFORE_REVERT);
565 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
567 runner.SetTestState(AFTER_REVERT);
568 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
569 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe"));
572 TEST(FilePolicyTest, TestReparsePoint) {
573 TestRunner runner;
575 // Create a temp file because we need write access to it.
576 wchar_t temp_directory[MAX_PATH];
577 wchar_t temp_file_name[MAX_PATH];
578 ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
579 ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
581 // Delete the file and create a directory instead.
582 ASSERT_TRUE(::DeleteFile(temp_file_name));
583 ASSERT_TRUE(::CreateDirectory(temp_file_name, NULL));
585 // Create a temporary file in the subfolder.
586 base::string16 subfolder = temp_file_name;
587 base::string16 temp_file_title = subfolder.substr(subfolder.rfind(L"\\") + 1);
588 base::string16 temp_file = subfolder + L"\\file_" + temp_file_title;
590 HANDLE file = ::CreateFile(temp_file.c_str(), FILE_ALL_ACCESS,
591 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
592 CREATE_ALWAYS, 0, NULL);
593 ASSERT_TRUE(INVALID_HANDLE_VALUE != file);
594 ASSERT_TRUE(::CloseHandle(file));
596 // Create a temporary file in the temp directory.
597 base::string16 temp_dir = temp_directory;
598 base::string16 temp_file_in_temp = temp_dir + L"file_" + temp_file_title;
599 file = ::CreateFile(temp_file_in_temp.c_str(), FILE_ALL_ACCESS,
600 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
601 CREATE_ALWAYS, 0, NULL);
602 ASSERT_TRUE(file != NULL);
603 ASSERT_TRUE(::CloseHandle(file));
605 // Give write access to the temp directory.
606 base::string16 temp_dir_wildcard = temp_dir + L"*";
607 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY,
608 temp_dir_wildcard.c_str()));
610 // Prepare the command to execute.
611 base::string16 command_write;
612 command_write += L"File_Create Write \"";
613 command_write += temp_file;
614 command_write += L"\"";
616 // Verify that we have write access to the original file
617 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write.c_str()));
619 // Replace the subfolder by a reparse point to %temp%.
620 ::DeleteFile(temp_file.c_str());
621 HANDLE dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS,
622 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
623 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
624 EXPECT_TRUE(INVALID_HANDLE_VALUE != dir);
626 base::string16 temp_dir_nt;
627 temp_dir_nt += L"\\??\\";
628 temp_dir_nt += temp_dir;
629 EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str()));
630 EXPECT_TRUE(::CloseHandle(dir));
632 // Try to open the file again.
633 EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write.c_str()));
635 // Remove the reparse point.
636 dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS,
637 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
638 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
639 NULL);
640 EXPECT_TRUE(INVALID_HANDLE_VALUE != dir);
641 EXPECT_TRUE(DeleteReparsePoint(dir));
642 EXPECT_TRUE(::CloseHandle(dir));
644 // Cleanup.
645 EXPECT_TRUE(::DeleteFile(temp_file_in_temp.c_str()));
646 EXPECT_TRUE(::RemoveDirectory(subfolder.c_str()));
649 TEST(FilePolicyTest, CheckExistingNTPrefixEscape) {
650 base::string16 name = L"\\??\\NAME";
652 base::string16 result = FixNTPrefixForMatch(name);
654 EXPECT_STREQ(result.c_str(), L"\\/?/?\\NAME");
657 TEST(FilePolicyTest, CheckEscapedNTPrefixNoEscape) {
658 base::string16 name = L"\\/?/?\\NAME";
660 base::string16 result = FixNTPrefixForMatch(name);
662 EXPECT_STREQ(result.c_str(), name.c_str());
665 TEST(FilePolicyTest, CheckMissingNTPrefixEscape) {
666 base::string16 name = L"C:\\NAME";
668 base::string16 result = FixNTPrefixForMatch(name);
670 EXPECT_STREQ(result.c_str(), L"\\/?/?\\C:\\NAME");
673 } // namespace sandbox