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 "sandbox/win/src/filesystem_policy.h"
13 #include "sandbox/win/src/nt_internals.h"
14 #include "sandbox/win/src/sandbox.h"
15 #include "sandbox/win/src/sandbox_factory.h"
16 #include "sandbox/win/src/sandbox_policy.h"
17 #include "sandbox/win/src/win_utils.h"
18 #include "sandbox/win/tests/common/controller.h"
19 #include "sandbox/win/tests/common/test_utils.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 #define BINDNTDLL(name) \
23 name ## Function name = reinterpret_cast<name ## Function>( \
24 ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
28 const ULONG kSharing
= FILE_SHARE_WRITE
| FILE_SHARE_READ
| FILE_SHARE_DELETE
;
30 // Creates a file using different desired access. Returns if the call succeeded
31 // or not. The first argument in argv is the filename. The second argument
32 // determines the type of access and the dispositino of the file.
33 SBOX_TESTS_COMMAND
int File_Create(int argc
, wchar_t **argv
) {
35 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
37 std::wstring
operation(argv
[0]);
39 if (operation
== L
"Read") {
40 base::win::ScopedHandle
file1(CreateFile(
41 argv
[1], GENERIC_READ
, kSharing
, NULL
, OPEN_EXISTING
, 0, NULL
));
42 base::win::ScopedHandle
file2(CreateFile(
43 argv
[1], FILE_EXECUTE
, kSharing
, NULL
, OPEN_EXISTING
, 0, NULL
));
45 if (file1
.IsValid() == file2
.IsValid())
46 return file1
.IsValid() ? SBOX_TEST_SUCCEEDED
: SBOX_TEST_DENIED
;
47 return file1
.IsValid() ? SBOX_TEST_FIRST_ERROR
: SBOX_TEST_SECOND_ERROR
;
49 } else if (operation
== L
"Write") {
50 base::win::ScopedHandle
file1(CreateFile(
51 argv
[1], GENERIC_ALL
, kSharing
, NULL
, OPEN_EXISTING
, 0, NULL
));
52 base::win::ScopedHandle
file2(CreateFile(
53 argv
[1], GENERIC_READ
| FILE_WRITE_DATA
, kSharing
, NULL
, OPEN_EXISTING
,
56 if (file1
.IsValid() == file2
.IsValid())
57 return file1
.IsValid() ? SBOX_TEST_SUCCEEDED
: SBOX_TEST_DENIED
;
58 return file1
.IsValid() ? SBOX_TEST_FIRST_ERROR
: SBOX_TEST_SECOND_ERROR
;
60 } else if (operation
== L
"ReadCreate") {
61 base::win::ScopedHandle
file2(CreateFile(
62 argv
[1], GENERIC_READ
, kSharing
, NULL
, CREATE_NEW
, 0, NULL
));
63 base::win::ScopedHandle
file1(CreateFile(
64 argv
[1], GENERIC_READ
, kSharing
, NULL
, CREATE_ALWAYS
, 0, NULL
));
66 if (file1
.IsValid() == file2
.IsValid())
67 return file1
.IsValid() ? SBOX_TEST_SUCCEEDED
: SBOX_TEST_DENIED
;
68 return file1
.IsValid() ? SBOX_TEST_FIRST_ERROR
: SBOX_TEST_SECOND_ERROR
;
71 return SBOX_TEST_INVALID_PARAMETER
;
74 SBOX_TESTS_COMMAND
int File_Win32Create(int argc
, wchar_t **argv
) {
76 SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
79 base::string16 full_path
= MakePathToSys(argv
[0], false);
80 if (full_path
.empty()) {
81 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
84 HANDLE file
= ::CreateFileW(full_path
.c_str(), GENERIC_READ
, kSharing
,
85 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
87 if (INVALID_HANDLE_VALUE
!= file
) {
89 return SBOX_TEST_SUCCEEDED
;
91 if (ERROR_ACCESS_DENIED
== ::GetLastError()) {
92 return SBOX_TEST_DENIED
;
94 return SBOX_TEST_FAILED
;
97 return SBOX_TEST_SUCCEEDED
;
100 // Creates the file in parameter using the NtCreateFile api and returns if the
101 // call succeeded or not.
102 SBOX_TESTS_COMMAND
int File_CreateSys32(int argc
, wchar_t **argv
) {
103 BINDNTDLL(NtCreateFile
);
104 BINDNTDLL(RtlInitUnicodeString
);
105 if (!NtCreateFile
|| !RtlInitUnicodeString
)
106 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
109 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
111 base::string16
file(argv
[0]);
112 if (0 != _wcsnicmp(file
.c_str(), kNTObjManPrefix
, kNTObjManPrefixLen
))
113 file
= MakePathToSys(argv
[0], true);
115 UNICODE_STRING object_name
;
116 RtlInitUnicodeString(&object_name
, file
.c_str());
118 OBJECT_ATTRIBUTES obj_attributes
= {0};
119 InitializeObjectAttributes(&obj_attributes
, &object_name
,
120 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
123 IO_STATUS_BLOCK io_block
= {0};
124 NTSTATUS status
= NtCreateFile(&handle
, FILE_READ_DATA
, &obj_attributes
,
125 &io_block
, NULL
, 0, kSharing
, FILE_OPEN
,
127 if (NT_SUCCESS(status
)) {
128 ::CloseHandle(handle
);
129 return SBOX_TEST_SUCCEEDED
;
130 } else if (STATUS_ACCESS_DENIED
== status
) {
131 return SBOX_TEST_DENIED
;
132 } else if (STATUS_OBJECT_NAME_NOT_FOUND
== status
) {
133 return SBOX_TEST_NOT_FOUND
;
135 return SBOX_TEST_FAILED
;
138 // Opens the file in parameter using the NtOpenFile api and returns if the
139 // call succeeded or not.
140 SBOX_TESTS_COMMAND
int File_OpenSys32(int argc
, wchar_t **argv
) {
141 BINDNTDLL(NtOpenFile
);
142 BINDNTDLL(RtlInitUnicodeString
);
143 if (!NtOpenFile
|| !RtlInitUnicodeString
)
144 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
147 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
149 base::string16 file
= MakePathToSys(argv
[0], true);
150 UNICODE_STRING object_name
;
151 RtlInitUnicodeString(&object_name
, file
.c_str());
153 OBJECT_ATTRIBUTES obj_attributes
= {0};
154 InitializeObjectAttributes(&obj_attributes
, &object_name
,
155 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
158 IO_STATUS_BLOCK io_block
= {0};
159 NTSTATUS status
= NtOpenFile(&handle
, FILE_READ_DATA
, &obj_attributes
,
160 &io_block
, kSharing
, 0);
161 if (NT_SUCCESS(status
)) {
162 ::CloseHandle(handle
);
163 return SBOX_TEST_SUCCEEDED
;
164 } else if (STATUS_ACCESS_DENIED
== status
) {
165 return SBOX_TEST_DENIED
;
166 } else if (STATUS_OBJECT_NAME_NOT_FOUND
== status
) {
167 return SBOX_TEST_NOT_FOUND
;
169 return SBOX_TEST_FAILED
;
172 SBOX_TESTS_COMMAND
int File_GetDiskSpace(int argc
, wchar_t **argv
) {
173 base::string16 sys_path
= MakePathToSys(L
"", false);
174 if (sys_path
.empty()) {
175 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
177 ULARGE_INTEGER free_user
= {0};
178 ULARGE_INTEGER total
= {0};
179 ULARGE_INTEGER free_total
= {0};
180 if (::GetDiskFreeSpaceExW(sys_path
.c_str(), &free_user
, &total
,
182 if ((total
.QuadPart
!= 0) && (free_total
.QuadPart
!=0)) {
183 return SBOX_TEST_SUCCEEDED
;
186 if (ERROR_ACCESS_DENIED
== ::GetLastError()) {
187 return SBOX_TEST_DENIED
;
189 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
192 return SBOX_TEST_SUCCEEDED
;
195 // Move a file using the MoveFileEx api and returns if the call succeeded or
197 SBOX_TESTS_COMMAND
int File_Rename(int argc
, wchar_t **argv
) {
199 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
201 if (::MoveFileEx(argv
[0], argv
[1], 0))
202 return SBOX_TEST_SUCCEEDED
;
204 if (::GetLastError() != ERROR_ACCESS_DENIED
)
205 return SBOX_TEST_FAILED
;
207 return SBOX_TEST_DENIED
;
210 // Query the attributes of file in parameter using the NtQueryAttributesFile api
211 // and NtQueryFullAttributesFile and returns if the call succeeded or not. The
212 // second argument in argv is "d" or "f" telling if we expect the attributes to
213 // specify a file or a directory. The expected attribute has to match the real
214 // attributes for the call to be successful.
215 SBOX_TESTS_COMMAND
int File_QueryAttributes(int argc
, wchar_t **argv
) {
216 BINDNTDLL(NtQueryAttributesFile
);
217 BINDNTDLL(NtQueryFullAttributesFile
);
218 BINDNTDLL(RtlInitUnicodeString
);
219 if (!NtQueryAttributesFile
|| !NtQueryFullAttributesFile
||
220 !RtlInitUnicodeString
)
221 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
224 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND
;
226 bool expect_directory
= (L
'd' == argv
[1][0]);
228 UNICODE_STRING object_name
;
229 base::string16 file
= MakePathToSys(argv
[0], true);
230 RtlInitUnicodeString(&object_name
, file
.c_str());
232 OBJECT_ATTRIBUTES obj_attributes
= {0};
233 InitializeObjectAttributes(&obj_attributes
, &object_name
,
234 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
236 FILE_BASIC_INFORMATION info
= {0};
237 FILE_NETWORK_OPEN_INFORMATION full_info
= {0};
238 NTSTATUS status1
= NtQueryAttributesFile(&obj_attributes
, &info
);
239 NTSTATUS status2
= NtQueryFullAttributesFile(&obj_attributes
, &full_info
);
241 if (status1
!= status2
)
242 return SBOX_TEST_FAILED
;
244 if (NT_SUCCESS(status1
)) {
245 if (info
.FileAttributes
!= full_info
.FileAttributes
)
246 return SBOX_TEST_FAILED
;
248 bool is_directory1
= (info
.FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) != 0;
249 if (expect_directory
== is_directory1
)
250 return SBOX_TEST_SUCCEEDED
;
251 } else if (STATUS_ACCESS_DENIED
== status1
) {
252 return SBOX_TEST_DENIED
;
253 } else if (STATUS_OBJECT_NAME_NOT_FOUND
== status1
) {
254 return SBOX_TEST_NOT_FOUND
;
257 return SBOX_TEST_FAILED
;
260 TEST(FilePolicyTest
, DenyNtCreateCalc
) {
262 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY
,
265 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_CreateSys32 calc.exe"));
267 runner
.SetTestState(BEFORE_REVERT
);
268 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_CreateSys32 calc.exe"));
271 TEST(FilePolicyTest
, AllowNtCreateCalc
) {
273 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
, L
"calc.exe"));
275 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_CreateSys32 calc.exe"));
277 runner
.SetTestState(BEFORE_REVERT
);
278 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_CreateSys32 calc.exe"));
281 TEST(FilePolicyTest
, AllowNtCreateWithNativePath
) {
282 base::string16 calc
= MakePathToSys(L
"calc.exe", false);
283 base::string16 nt_path
;
284 ASSERT_TRUE(GetNtPathFromWin32Path(calc
, &nt_path
));
286 runner
.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY
, nt_path
.c_str());
288 wchar_t buff
[MAX_PATH
];
289 ::wsprintfW(buff
, L
"File_CreateSys32 %s", nt_path
.c_str());
290 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(buff
));
292 std::transform(nt_path
.begin(), nt_path
.end(), nt_path
.begin(), std::tolower
);
293 ::wsprintfW(buff
, L
"File_CreateSys32 %s", nt_path
.c_str());
294 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(buff
));
297 TEST(FilePolicyTest
, AllowReadOnly
) {
300 // Create a temp file because we need write access to it.
301 wchar_t temp_directory
[MAX_PATH
];
302 wchar_t temp_file_name
[MAX_PATH
];
303 ASSERT_NE(::GetTempPath(MAX_PATH
, temp_directory
), 0u);
304 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name
), 0u);
306 EXPECT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY
,
309 wchar_t command_read
[MAX_PATH
+ 20] = {0};
310 wsprintf(command_read
, L
"File_Create Read \"%ls\"", temp_file_name
);
311 wchar_t command_read_create
[MAX_PATH
+ 20] = {0};
312 wsprintf(command_read_create
, L
"File_Create ReadCreate \"%ls\"",
314 wchar_t command_write
[MAX_PATH
+ 20] = {0};
315 wsprintf(command_write
, L
"File_Create Write \"%ls\"", temp_file_name
);
317 // Verify that we cannot create the file after revert.
318 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command_read_create
));
320 // Verify that we don't have write access after revert.
321 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command_write
));
323 // Verify that we have read access after revert.
324 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(command_read
));
326 // Verify that we really have write access to the file.
327 runner
.SetTestState(BEFORE_REVERT
);
328 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(command_write
));
330 DeleteFile(temp_file_name
);
333 TEST(FilePolicyTest
, AllowWildcard
) {
336 // Create a temp file because we need write access to it.
337 wchar_t temp_directory
[MAX_PATH
];
338 wchar_t temp_file_name
[MAX_PATH
];
339 ASSERT_NE(::GetTempPath(MAX_PATH
, temp_directory
), 0u);
340 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name
), 0u);
342 wcscat_s(temp_directory
, MAX_PATH
, L
"*");
343 EXPECT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
, temp_directory
));
345 wchar_t command_write
[MAX_PATH
+ 20] = {0};
346 wsprintf(command_write
, L
"File_Create Write \"%ls\"", temp_file_name
);
348 // Verify that we have write access after revert.
349 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(command_write
));
351 DeleteFile(temp_file_name
);
354 TEST(FilePolicyTest
, AllowNtCreatePatternRule
) {
356 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
, L
"App*.dll"));
358 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
359 runner
.RunTest(L
"File_OpenSys32 appmgmts.dll"));
360 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_OpenSys32 appwiz.cpl"));
362 runner
.SetTestState(BEFORE_REVERT
);
363 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
364 runner
.RunTest(L
"File_OpenSys32 appmgmts.dll"));
365 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_OpenSys32 appwiz.cpl"));
368 TEST(FilePolicyTest
, CheckNotFound
) {
370 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
, L
"n*.dll"));
372 EXPECT_EQ(SBOX_TEST_NOT_FOUND
,
373 runner
.RunTest(L
"File_OpenSys32 notfound.dll"));
376 TEST(FilePolicyTest
, CheckNoLeak
) {
378 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_CreateSys32 notfound.exe"));
381 TEST(FilePolicyTest
, TestQueryAttributesFile
) {
383 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
,
385 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
,
387 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
, L
"drivers"));
388 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_QUERY
,
391 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
392 runner
.RunTest(L
"File_QueryAttributes drivers d"));
394 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
395 runner
.RunTest(L
"File_QueryAttributes appmgmts.dll f"));
397 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
398 runner
.RunTest(L
"File_QueryAttributes ipconfig.exe f"));
400 EXPECT_EQ(SBOX_TEST_DENIED
,
401 runner
.RunTest(L
"File_QueryAttributes ftp.exe f"));
403 EXPECT_EQ(SBOX_TEST_NOT_FOUND
,
404 runner
.RunTest(L
"File_QueryAttributes notfound.exe f"));
407 // Makes sure that we don't leak information when there is not policy to allow
409 TEST(FilePolicyTest
, TestQueryAttributesFileNoPolicy
) {
411 EXPECT_EQ(SBOX_TEST_DENIED
,
412 runner
.RunTest(L
"File_QueryAttributes ftp.exe f"));
414 EXPECT_EQ(SBOX_TEST_DENIED
,
415 runner
.RunTest(L
"File_QueryAttributes notfound.exe f"));
418 TEST(FilePolicyTest
, TestRename
) {
421 // Give access to the temp directory.
422 wchar_t temp_directory
[MAX_PATH
];
423 wchar_t temp_file_name1
[MAX_PATH
];
424 wchar_t temp_file_name2
[MAX_PATH
];
425 wchar_t temp_file_name3
[MAX_PATH
];
426 wchar_t temp_file_name4
[MAX_PATH
];
427 wchar_t temp_file_name5
[MAX_PATH
];
428 wchar_t temp_file_name6
[MAX_PATH
];
429 wchar_t temp_file_name7
[MAX_PATH
];
430 wchar_t temp_file_name8
[MAX_PATH
];
431 ASSERT_NE(::GetTempPath(MAX_PATH
, temp_directory
), 0u);
432 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name1
), 0u);
433 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name2
), 0u);
434 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name3
), 0u);
435 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name4
), 0u);
436 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name5
), 0u);
437 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name6
), 0u);
438 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name7
), 0u);
439 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name8
), 0u);
442 // Add rules to make file1->file2 succeed.
443 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
, temp_file_name1
));
444 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
, temp_file_name2
));
446 // Add rules to make file3->file4 fail.
447 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
, temp_file_name3
));
448 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY
,
451 // Add rules to make file5->file6 fail.
452 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY
,
454 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
, temp_file_name6
));
456 // Add rules to make file7->no_pol_file fail.
457 ASSERT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
, temp_file_name7
));
459 // Delete the files where the files are going to be renamed to.
460 ::DeleteFile(temp_file_name2
);
461 ::DeleteFile(temp_file_name4
);
462 ::DeleteFile(temp_file_name6
);
463 ::DeleteFile(temp_file_name8
);
466 wchar_t command
[MAX_PATH
*2 + 20] = {0};
467 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name1
,
469 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(command
));
471 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name3
,
473 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command
));
475 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name5
,
477 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command
));
479 wsprintf(command
, L
"File_Rename \"%ls\" \"%ls\"", temp_file_name7
,
481 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command
));
484 // Delete all the files in case they are still there.
485 ::DeleteFile(temp_file_name1
);
486 ::DeleteFile(temp_file_name2
);
487 ::DeleteFile(temp_file_name3
);
488 ::DeleteFile(temp_file_name4
);
489 ::DeleteFile(temp_file_name5
);
490 ::DeleteFile(temp_file_name6
);
491 ::DeleteFile(temp_file_name7
);
492 ::DeleteFile(temp_file_name8
);
495 TEST(FilePolicyTest
, OpenSys32FilesDenyBecauseOfDir
) {
497 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY
,
500 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_Win32Create notepad.exe"));
502 runner
.SetTestState(BEFORE_REVERT
);
503 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
504 runner
.RunTest(L
"File_Win32Create notepad.exe"));
507 TEST(FilePolicyTest
, OpenSys32FilesAllowNotepad
) {
509 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY
,
512 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
513 runner
.RunTest(L
"File_Win32Create notepad.exe"));
515 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_Win32Create calc.exe"));
517 runner
.SetTestState(BEFORE_REVERT
);
518 EXPECT_EQ(SBOX_TEST_SUCCEEDED
,
519 runner
.RunTest(L
"File_Win32Create notepad.exe"));
520 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_Win32Create calc.exe"));
523 TEST(FilePolicyTest
, FileGetDiskSpace
) {
525 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_GetDiskSpace"));
526 runner
.SetTestState(BEFORE_REVERT
);
527 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_GetDiskSpace"));
529 // Add an 'allow' rule in the windows\system32 such that GetDiskFreeSpaceEx
530 // succeeds (it does an NtOpenFile) but windows\system32\notepad.exe is
531 // denied since there is no wild card in the rule.
532 EXPECT_TRUE(runner
.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY
, L
""));
533 runner
.SetTestState(BEFORE_REVERT
);
534 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_GetDiskSpace"));
536 runner
.SetTestState(AFTER_REVERT
);
537 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(L
"File_GetDiskSpace"));
538 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(L
"File_Win32Create notepad.exe"));
541 TEST(FilePolicyTest
, TestReparsePoint
) {
544 // Create a temp file because we need write access to it.
545 wchar_t temp_directory
[MAX_PATH
];
546 wchar_t temp_file_name
[MAX_PATH
];
547 ASSERT_NE(::GetTempPath(MAX_PATH
, temp_directory
), 0u);
548 ASSERT_NE(::GetTempFileName(temp_directory
, L
"test", 0, temp_file_name
), 0u);
550 // Delete the file and create a directory instead.
551 ASSERT_TRUE(::DeleteFile(temp_file_name
));
552 ASSERT_TRUE(::CreateDirectory(temp_file_name
, NULL
));
554 // Create a temporary file in the subfolder.
555 base::string16 subfolder
= temp_file_name
;
556 base::string16 temp_file_title
= subfolder
.substr(subfolder
.rfind(L
"\\") + 1);
557 base::string16 temp_file
= subfolder
+ L
"\\file_" + temp_file_title
;
559 HANDLE file
= ::CreateFile(temp_file
.c_str(), FILE_ALL_ACCESS
,
560 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
561 CREATE_ALWAYS
, 0, NULL
);
562 ASSERT_TRUE(INVALID_HANDLE_VALUE
!= file
);
563 ASSERT_TRUE(::CloseHandle(file
));
565 // Create a temporary file in the temp directory.
566 base::string16 temp_dir
= temp_directory
;
567 base::string16 temp_file_in_temp
= temp_dir
+ L
"file_" + temp_file_title
;
568 file
= ::CreateFile(temp_file_in_temp
.c_str(), FILE_ALL_ACCESS
,
569 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
570 CREATE_ALWAYS
, 0, NULL
);
571 ASSERT_TRUE(file
!= NULL
);
572 ASSERT_TRUE(::CloseHandle(file
));
574 // Give write access to the temp directory.
575 base::string16 temp_dir_wildcard
= temp_dir
+ L
"*";
576 EXPECT_TRUE(runner
.AddFsRule(TargetPolicy::FILES_ALLOW_ANY
,
577 temp_dir_wildcard
.c_str()));
579 // Prepare the command to execute.
580 base::string16 command_write
;
581 command_write
+= L
"File_Create Write \"";
582 command_write
+= temp_file
;
583 command_write
+= L
"\"";
585 // Verify that we have write access to the original file
586 EXPECT_EQ(SBOX_TEST_SUCCEEDED
, runner
.RunTest(command_write
.c_str()));
588 // Replace the subfolder by a reparse point to %temp%.
589 ::DeleteFile(temp_file
.c_str());
590 HANDLE dir
= ::CreateFile(subfolder
.c_str(), FILE_ALL_ACCESS
,
591 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
592 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
593 EXPECT_TRUE(INVALID_HANDLE_VALUE
!= dir
);
595 base::string16 temp_dir_nt
;
596 temp_dir_nt
+= L
"\\??\\";
597 temp_dir_nt
+= temp_dir
;
598 EXPECT_TRUE(SetReparsePoint(dir
, temp_dir_nt
.c_str()));
599 EXPECT_TRUE(::CloseHandle(dir
));
601 // Try to open the file again.
602 EXPECT_EQ(SBOX_TEST_DENIED
, runner
.RunTest(command_write
.c_str()));
604 // Remove the reparse point.
605 dir
= ::CreateFile(subfolder
.c_str(), FILE_ALL_ACCESS
,
606 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
607 FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
,
609 EXPECT_TRUE(INVALID_HANDLE_VALUE
!= dir
);
610 EXPECT_TRUE(DeleteReparsePoint(dir
));
611 EXPECT_TRUE(::CloseHandle(dir
));
614 EXPECT_TRUE(::DeleteFile(temp_file_in_temp
.c_str()));
615 EXPECT_TRUE(::RemoveDirectory(subfolder
.c_str()));
618 TEST(FilePolicyTest
, CheckExistingNTPrefixEscape
) {
619 base::string16 name
= L
"\\??\\NAME";
621 base::string16 result
= FixNTPrefixForMatch(name
);
623 EXPECT_STREQ(result
.c_str(), L
"\\/?/?\\NAME");
626 TEST(FilePolicyTest
, CheckEscapedNTPrefixNoEscape
) {
627 base::string16 name
= L
"\\/?/?\\NAME";
629 base::string16 result
= FixNTPrefixForMatch(name
);
631 EXPECT_STREQ(result
.c_str(), name
.c_str());
634 TEST(FilePolicyTest
, CheckMissingNTPrefixEscape
) {
635 base::string16 name
= L
"C:\\NAME";
637 base::string16 result
= FixNTPrefixForMatch(name
);
639 EXPECT_STREQ(result
.c_str(), L
"\\/?/?\\C:\\NAME");
642 } // namespace sandbox