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.
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))
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
) {
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
,
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
) {
77 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
) {
90 return SBOX_TEST_SUCCEEDED
;
92 if (ERROR_ACCESS_DENIED
== ::GetLastError()) {
93 return SBOX_TEST_DENIED
;
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
;
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
= {0};
120 InitializeObjectAttributes(&obj_attributes
, &object_name
,
121 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
124 IO_STATUS_BLOCK io_block
= {0};
125 NTSTATUS status
= NtCreateFile(&handle
, FILE_READ_DATA
, &obj_attributes
,
126 &io_block
, NULL
, 0, kSharing
, FILE_OPEN
,
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
;
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
= {0};
155 InitializeObjectAttributes(&obj_attributes
, &object_name
,
156 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
159 IO_STATUS_BLOCK io_block
= {0};
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
= {0};
179 ULARGE_INTEGER total
= {0};
180 ULARGE_INTEGER free_total
= {0};
181 if (::GetDiskFreeSpaceExW(sys_path
.c_str(), &free_user
, &total
,
183 if ((total
.QuadPart
!= 0) && (free_total
.QuadPart
!=0)) {
184 return SBOX_TEST_SUCCEEDED
;
187 if (ERROR_ACCESS_DENIED
== ::GetLastError()) {
188 return SBOX_TEST_DENIED
;
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
198 SBOX_TESTS_COMMAND
int File_Rename(int argc
, wchar_t **argv
) {
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
;
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
= {0};
234 InitializeObjectAttributes(&obj_attributes
, &object_name
,
235 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
237 FILE_BASIC_INFORMATION info
= {0};
238 FILE_NETWORK_OPEN_INFORMATION full_info
= {0};
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
) {
263 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY
,
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
) {
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
)
286 base::string16 calc
= MakePathToSys(L
"calc.exe", false);
287 base::string16 nt_path
;
288 ASSERT_TRUE(GetNtPathFromWin32Path(calc
, &nt_path
));
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
) {
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
,
313 wchar_t command_read
[MAX_PATH
+ 20] = {0};
314 wsprintf(command_read
, L
"File_Create Read \"%ls\"", temp_file_name
);
315 wchar_t command_read_create
[MAX_PATH
+ 20] = {0};
316 wsprintf(command_read_create
, L
"File_Create ReadCreate \"%ls\"",
318 wchar_t command_write
[MAX_PATH
+ 20] = {0};
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
)
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);
350 EXPECT_TRUE(ConvertToLongPath(temp_file_name
, &path
));
351 EXPECT_TRUE(GetNtPathFromWin32Path(path
, &path
));
352 path
= path
.substr(sandbox::kNTDevicePrefixLen
);
354 wchar_t command
[MAX_PATH
+ 20] = {0};
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
) {
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] = {0};
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
) {
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
) {
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
) {
410 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_CreateSys32 notfound.exe"));
413 TEST(FilePolicyTest
, TestQueryAttributesFile
) {
415 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
,
417 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
,
419 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
, L
"drivers"));
420 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_QUERY
,
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
441 TEST(FilePolicyTest
, TestQueryAttributesFileNoPolicy
) {
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
) {
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
,
483 // Add rules to make file5->file6 fail.
484 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY
,
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
);
498 wchar_t command
[MAX_PATH
*2 + 20] = {0};
499 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name1
,
501 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(command
));
503 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name3
,
505 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command
));
507 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name5
,
509 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command
));
511 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name7
,
513 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command
));
516 // Delete all the files in case they are still there.
517 ::DeleteFile(temp_file_name1
);
518 ::DeleteFile(temp_file_name2
);
519 ::DeleteFile(temp_file_name3
);
520 ::DeleteFile(temp_file_name4
);
521 ::DeleteFile(temp_file_name5
);
522 ::DeleteFile(temp_file_name6
);
523 ::DeleteFile(temp_file_name7
);
524 ::DeleteFile(temp_file_name8
);
527 TEST(FilePolicyTest
, OpenSys32FilesDenyBecauseOfDir
) {
529 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY
,
532 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_Win32Create notepad.exe"));
534 runner
.SetTestState(BEFORE_REVERT
);
535 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
536 runner
.RunTest(L
"File_Win32Create notepad.exe"));
539 TEST(FilePolicyTest
, OpenSys32FilesAllowNotepad
) {
541 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
,
544 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
545 runner
.RunTest(L
"File_Win32Create notepad.exe"));
547 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_Win32Create calc.exe"));
549 runner
.SetTestState(BEFORE_REVERT
);
550 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
551 runner
.RunTest(L
"File_Win32Create notepad.exe"));
552 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_Win32Create calc.exe"));
555 TEST(FilePolicyTest
, FileGetDiskSpace
) {
557 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_GetDiskSpace"));
558 runner
.SetTestState(BEFORE_REVERT
);
559 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_GetDiskSpace"));
561 // Add an 'allow' rule in the windows\system32 such that GetDiskFreeSpaceEx
562 // succeeds (it does an NtOpenFile) but windows\system32\notepad.exe is
563 // denied since there is no wild card in the rule.
564 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY
, L
""));
565 runner
.SetTestState(BEFORE_REVERT
);
566 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_GetDiskSpace"));
568 runner
.SetTestState(AFTER_REVERT
);
569 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_GetDiskSpace"));
570 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_Win32Create notepad.exe"));
573 TEST(FilePolicyTest
, TestReparsePoint
) {
576 // Create a temp file because we need write access to it.
577 wchar_t temp_directory
[MAX_PATH
];
578 wchar_t temp_file_name
[MAX_PATH
];
579 ASSERT_NE(::GetTempPath(MAX_PATH
, temp_directory
), 0u);
580 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name
), 0u);
582 // Delete the file and create a directory instead.
583 ASSERT_TRUE(::DeleteFile(temp_file_name
));
584 ASSERT_TRUE(::CreateDirectory(temp_file_name
, NULL
));
586 // Create a temporary file in the subfolder.
587 base::string16 subfolder
= temp_file_name
;
588 base::string16 temp_file_title
= subfolder
.substr(subfolder
.rfind(L
"\\") + 1);
589 base::string16 temp_file
= subfolder
+ L
"\\file_" + temp_file_title
;
591 HANDLE file
= ::CreateFile(temp_file
.c_str(), FILE_ALL_ACCESS
,
592 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
593 CREATE_ALWAYS
, 0, NULL
);
594 ASSERT_TRUE(INVALID_HANDLE_VALUE
!= file
);
595 ASSERT_TRUE(::CloseHandle(file
));
597 // Create a temporary file in the temp directory.
598 base::string16 temp_dir
= temp_directory
;
599 base::string16 temp_file_in_temp
= temp_dir
+ L
"file_" + temp_file_title
;
600 file
= ::CreateFile(temp_file_in_temp
.c_str(), FILE_ALL_ACCESS
,
601 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
602 CREATE_ALWAYS
, 0, NULL
);
603 ASSERT_TRUE(file
!= NULL
);
604 ASSERT_TRUE(::CloseHandle(file
));
606 // Give write access to the temp directory.
607 base::string16 temp_dir_wildcard
= temp_dir
+ L
"*";
608 EXPECT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
,
609 temp_dir_wildcard
.c_str()));
611 // Prepare the command to execute.
612 base::string16 command_write
;
613 command_write
+= L
"File_Create Write \"";
614 command_write
+= temp_file
;
615 command_write
+= L
"\"";
617 // Verify that we have write access to the original file
618 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(command_write
.c_str()));
620 // Replace the subfolder by a reparse point to %temp%.
621 ::DeleteFile(temp_file
.c_str());
622 HANDLE dir
= ::CreateFile(subfolder
.c_str(), FILE_ALL_ACCESS
,
623 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
624 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
625 EXPECT_TRUE(INVALID_HANDLE_VALUE
!= dir
);
627 base::string16 temp_dir_nt
;
628 temp_dir_nt
+= L
"\\??\\";
629 temp_dir_nt
+= temp_dir
;
630 EXPECT_TRUE(SetReparsePoint(dir
, temp_dir_nt
.c_str()));
631 EXPECT_TRUE(::CloseHandle(dir
));
633 // Try to open the file again.
634 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command_write
.c_str()));
636 // Remove the reparse point.
637 dir
= ::CreateFile(subfolder
.c_str(), FILE_ALL_ACCESS
,
638 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
639 FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
,
641 EXPECT_TRUE(INVALID_HANDLE_VALUE
!= dir
);
642 EXPECT_TRUE(DeleteReparsePoint(dir
));
643 EXPECT_TRUE(::CloseHandle(dir
));
646 EXPECT_TRUE(::DeleteFile(temp_file_in_temp
.c_str()));
647 EXPECT_TRUE(::RemoveDirectory(subfolder
.c_str()));
650 TEST(FilePolicyTest
, CheckExistingNTPrefixEscape
) {
651 base::string16 name
= L
"\\??\\NAME";
653 base::string16 result
= FixNTPrefixForMatch(name
);
655 EXPECT_STREQ(result
.c_str(), L
"\\/?/?\\NAME");
658 TEST(FilePolicyTest
, CheckEscapedNTPrefixNoEscape
) {
659 base::string16 name
= L
"\\/?/?\\NAME";
661 base::string16 result
= FixNTPrefixForMatch(name
);
663 EXPECT_STREQ(result
.c_str(), name
.c_str());
666 TEST(FilePolicyTest
, CheckMissingNTPrefixEscape
) {
667 base::string16 name
= L
"C:\\NAME";
669 base::string16 result
= FixNTPrefixForMatch(name
);
671 EXPECT_STREQ(result
.c_str(), L
"\\/?/?\\C:\\NAME");
674 } // namespace sandbox