1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/file_policy_test.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,599 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include <algorithm> 1.9 +#include <cctype> 1.10 + 1.11 +#include <windows.h> 1.12 +#include <winioctl.h> 1.13 + 1.14 +#include "base/win/scoped_handle.h" 1.15 +#include "sandbox/win/src/nt_internals.h" 1.16 +#include "sandbox/win/src/sandbox.h" 1.17 +#include "sandbox/win/src/sandbox_factory.h" 1.18 +#include "sandbox/win/src/sandbox_policy.h" 1.19 +#include "sandbox/win/src/win_utils.h" 1.20 +#include "sandbox/win/tests/common/controller.h" 1.21 +#include "sandbox/win/tests/common/test_utils.h" 1.22 +#include "testing/gtest/include/gtest/gtest.h" 1.23 + 1.24 +#define BINDNTDLL(name) \ 1.25 + name ## Function name = reinterpret_cast<name ## Function>( \ 1.26 + ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name)) 1.27 + 1.28 +namespace sandbox { 1.29 + 1.30 +const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE; 1.31 + 1.32 +// Creates a file using different desired access. Returns if the call succeeded 1.33 +// or not. The first argument in argv is the filename. If the second argument 1.34 +// is "read", we try read only access. Otherwise we try read-write access. 1.35 +SBOX_TESTS_COMMAND int File_Create(int argc, wchar_t **argv) { 1.36 + if (argc != 2) 1.37 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.38 + 1.39 + bool read = (_wcsicmp(argv[0], L"Read") == 0); 1.40 + 1.41 + if (read) { 1.42 + base::win::ScopedHandle file1(CreateFile( 1.43 + argv[1], GENERIC_READ, kSharing, NULL, OPEN_EXISTING, 0, NULL)); 1.44 + base::win::ScopedHandle file2(CreateFile( 1.45 + argv[1], FILE_EXECUTE, kSharing, NULL, OPEN_EXISTING, 0, NULL)); 1.46 + 1.47 + if (file1.Get() && file2.Get()) 1.48 + return SBOX_TEST_SUCCEEDED; 1.49 + return SBOX_TEST_DENIED; 1.50 + } else { 1.51 + base::win::ScopedHandle file1(CreateFile( 1.52 + argv[1], GENERIC_ALL, kSharing, NULL, OPEN_EXISTING, 0, NULL)); 1.53 + base::win::ScopedHandle file2(CreateFile( 1.54 + argv[1], GENERIC_READ | FILE_WRITE_DATA, kSharing, NULL, OPEN_EXISTING, 1.55 + 0, NULL)); 1.56 + 1.57 + if (file1.Get() && file2.Get()) 1.58 + return SBOX_TEST_SUCCEEDED; 1.59 + return SBOX_TEST_DENIED; 1.60 + } 1.61 +} 1.62 + 1.63 +SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t **argv) { 1.64 + if (argc != 1) { 1.65 + SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.66 + } 1.67 + 1.68 + std::wstring full_path = MakePathToSys(argv[0], false); 1.69 + if (full_path.empty()) { 1.70 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.71 + } 1.72 + 1.73 + HANDLE file = ::CreateFileW(full_path.c_str(), GENERIC_READ, kSharing, 1.74 + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 1.75 + 1.76 + if (INVALID_HANDLE_VALUE != file) { 1.77 + ::CloseHandle(file); 1.78 + return SBOX_TEST_SUCCEEDED; 1.79 + } else { 1.80 + if (ERROR_ACCESS_DENIED == ::GetLastError()) { 1.81 + return SBOX_TEST_DENIED; 1.82 + } else { 1.83 + return SBOX_TEST_FAILED; 1.84 + } 1.85 + } 1.86 + return SBOX_TEST_SUCCEEDED; 1.87 +} 1.88 + 1.89 +// Creates the file in parameter using the NtCreateFile api and returns if the 1.90 +// call succeeded or not. 1.91 +SBOX_TESTS_COMMAND int File_CreateSys32(int argc, wchar_t **argv) { 1.92 + BINDNTDLL(NtCreateFile); 1.93 + BINDNTDLL(RtlInitUnicodeString); 1.94 + if (!NtCreateFile || !RtlInitUnicodeString) 1.95 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.96 + 1.97 + if (argc != 1) 1.98 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.99 + 1.100 + std::wstring file(argv[0]); 1.101 + if (0 != _wcsnicmp(file.c_str(), kNTObjManPrefix, kNTObjManPrefixLen)) 1.102 + file = MakePathToSys(argv[0], true); 1.103 + 1.104 + UNICODE_STRING object_name; 1.105 + RtlInitUnicodeString(&object_name, file.c_str()); 1.106 + 1.107 + OBJECT_ATTRIBUTES obj_attributes = {0}; 1.108 + InitializeObjectAttributes(&obj_attributes, &object_name, 1.109 + OBJ_CASE_INSENSITIVE, NULL, NULL); 1.110 + 1.111 + HANDLE handle; 1.112 + IO_STATUS_BLOCK io_block = {0}; 1.113 + NTSTATUS status = NtCreateFile(&handle, FILE_READ_DATA, &obj_attributes, 1.114 + &io_block, NULL, 0, kSharing, FILE_OPEN, 1.115 + 0, NULL, 0); 1.116 + if (NT_SUCCESS(status)) { 1.117 + ::CloseHandle(handle); 1.118 + return SBOX_TEST_SUCCEEDED; 1.119 + } else if (STATUS_ACCESS_DENIED == status) { 1.120 + return SBOX_TEST_DENIED; 1.121 + } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { 1.122 + return SBOX_TEST_NOT_FOUND; 1.123 + } 1.124 + return SBOX_TEST_FAILED; 1.125 +} 1.126 + 1.127 +// Opens the file in parameter using the NtOpenFile api and returns if the 1.128 +// call succeeded or not. 1.129 +SBOX_TESTS_COMMAND int File_OpenSys32(int argc, wchar_t **argv) { 1.130 + BINDNTDLL(NtOpenFile); 1.131 + BINDNTDLL(RtlInitUnicodeString); 1.132 + if (!NtOpenFile || !RtlInitUnicodeString) 1.133 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.134 + 1.135 + if (argc != 1) 1.136 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.137 + 1.138 + std::wstring file = MakePathToSys(argv[0], true); 1.139 + UNICODE_STRING object_name; 1.140 + RtlInitUnicodeString(&object_name, file.c_str()); 1.141 + 1.142 + OBJECT_ATTRIBUTES obj_attributes = {0}; 1.143 + InitializeObjectAttributes(&obj_attributes, &object_name, 1.144 + OBJ_CASE_INSENSITIVE, NULL, NULL); 1.145 + 1.146 + HANDLE handle; 1.147 + IO_STATUS_BLOCK io_block = {0}; 1.148 + NTSTATUS status = NtOpenFile(&handle, FILE_READ_DATA, &obj_attributes, 1.149 + &io_block, kSharing, 0); 1.150 + if (NT_SUCCESS(status)) { 1.151 + ::CloseHandle(handle); 1.152 + return SBOX_TEST_SUCCEEDED; 1.153 + } else if (STATUS_ACCESS_DENIED == status) { 1.154 + return SBOX_TEST_DENIED; 1.155 + } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { 1.156 + return SBOX_TEST_NOT_FOUND; 1.157 + } 1.158 + return SBOX_TEST_FAILED; 1.159 +} 1.160 + 1.161 +SBOX_TESTS_COMMAND int File_GetDiskSpace(int argc, wchar_t **argv) { 1.162 + std::wstring sys_path = MakePathToSys(L"", false); 1.163 + if (sys_path.empty()) { 1.164 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.165 + } 1.166 + ULARGE_INTEGER free_user = {0}; 1.167 + ULARGE_INTEGER total = {0}; 1.168 + ULARGE_INTEGER free_total = {0}; 1.169 + if (::GetDiskFreeSpaceExW(sys_path.c_str(), &free_user, &total, 1.170 + &free_total)) { 1.171 + if ((total.QuadPart != 0) && (free_total.QuadPart !=0)) { 1.172 + return SBOX_TEST_SUCCEEDED; 1.173 + } 1.174 + } else { 1.175 + if (ERROR_ACCESS_DENIED == ::GetLastError()) { 1.176 + return SBOX_TEST_DENIED; 1.177 + } else { 1.178 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.179 + } 1.180 + } 1.181 + return SBOX_TEST_SUCCEEDED; 1.182 +} 1.183 + 1.184 +// Move a file using the MoveFileEx api and returns if the call succeeded or 1.185 +// not. 1.186 +SBOX_TESTS_COMMAND int File_Rename(int argc, wchar_t **argv) { 1.187 + if (argc != 2) 1.188 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.189 + 1.190 + if (::MoveFileEx(argv[0], argv[1], 0)) 1.191 + return SBOX_TEST_SUCCEEDED; 1.192 + 1.193 + if (::GetLastError() != ERROR_ACCESS_DENIED) 1.194 + return SBOX_TEST_FAILED; 1.195 + 1.196 + return SBOX_TEST_DENIED; 1.197 +} 1.198 + 1.199 +// Query the attributes of file in parameter using the NtQueryAttributesFile api 1.200 +// and NtQueryFullAttributesFile and returns if the call succeeded or not. The 1.201 +// second argument in argv is "d" or "f" telling if we expect the attributes to 1.202 +// specify a file or a directory. The expected attribute has to match the real 1.203 +// attributes for the call to be successful. 1.204 +SBOX_TESTS_COMMAND int File_QueryAttributes(int argc, wchar_t **argv) { 1.205 + BINDNTDLL(NtQueryAttributesFile); 1.206 + BINDNTDLL(NtQueryFullAttributesFile); 1.207 + BINDNTDLL(RtlInitUnicodeString); 1.208 + if (!NtQueryAttributesFile || !NtQueryFullAttributesFile || 1.209 + !RtlInitUnicodeString) 1.210 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.211 + 1.212 + if (argc != 2) 1.213 + return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; 1.214 + 1.215 + bool expect_directory = (L'd' == argv[1][0]); 1.216 + 1.217 + UNICODE_STRING object_name; 1.218 + std::wstring file = MakePathToSys(argv[0], true); 1.219 + RtlInitUnicodeString(&object_name, file.c_str()); 1.220 + 1.221 + OBJECT_ATTRIBUTES obj_attributes = {0}; 1.222 + InitializeObjectAttributes(&obj_attributes, &object_name, 1.223 + OBJ_CASE_INSENSITIVE, NULL, NULL); 1.224 + 1.225 + FILE_BASIC_INFORMATION info = {0}; 1.226 + FILE_NETWORK_OPEN_INFORMATION full_info = {0}; 1.227 + NTSTATUS status1 = NtQueryAttributesFile(&obj_attributes, &info); 1.228 + NTSTATUS status2 = NtQueryFullAttributesFile(&obj_attributes, &full_info); 1.229 + 1.230 + if (status1 != status2) 1.231 + return SBOX_TEST_FAILED; 1.232 + 1.233 + if (NT_SUCCESS(status1)) { 1.234 + if (info.FileAttributes != full_info.FileAttributes) 1.235 + return SBOX_TEST_FAILED; 1.236 + 1.237 + bool is_directory1 = (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; 1.238 + if (expect_directory == is_directory1) 1.239 + return SBOX_TEST_SUCCEEDED; 1.240 + } else if (STATUS_ACCESS_DENIED == status1) { 1.241 + return SBOX_TEST_DENIED; 1.242 + } else if (STATUS_OBJECT_NAME_NOT_FOUND == status1) { 1.243 + return SBOX_TEST_NOT_FOUND; 1.244 + } 1.245 + 1.246 + return SBOX_TEST_FAILED; 1.247 +} 1.248 + 1.249 +TEST(FilePolicyTest, DenyNtCreateCalc) { 1.250 + TestRunner runner; 1.251 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, 1.252 + L"calc.exe")); 1.253 + 1.254 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 calc.exe")); 1.255 + 1.256 + runner.SetTestState(BEFORE_REVERT); 1.257 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe")); 1.258 +} 1.259 + 1.260 +TEST(FilePolicyTest, AllowNtCreateCalc) { 1.261 + TestRunner runner; 1.262 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"calc.exe")); 1.263 + 1.264 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe")); 1.265 + 1.266 + runner.SetTestState(BEFORE_REVERT); 1.267 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe")); 1.268 +} 1.269 + 1.270 +TEST(FilePolicyTest, AllowNtCreateWithNativePath) { 1.271 + std::wstring calc = MakePathToSys(L"calc.exe", false); 1.272 + std::wstring nt_path; 1.273 + ASSERT_TRUE(GetNtPathFromWin32Path(calc, &nt_path)); 1.274 + TestRunner runner; 1.275 + runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, nt_path.c_str()); 1.276 + 1.277 + wchar_t buff[MAX_PATH]; 1.278 + ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str()); 1.279 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff)); 1.280 + 1.281 + std::transform(nt_path.begin(), nt_path.end(), nt_path.begin(), std::tolower); 1.282 + ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str()); 1.283 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff)); 1.284 +} 1.285 + 1.286 +TEST(FilePolicyTest, AllowReadOnly) { 1.287 + TestRunner runner; 1.288 + 1.289 + // Create a temp file because we need write access to it. 1.290 + wchar_t temp_directory[MAX_PATH]; 1.291 + wchar_t temp_file_name[MAX_PATH]; 1.292 + ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); 1.293 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u); 1.294 + 1.295 + EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, 1.296 + temp_file_name)); 1.297 + 1.298 + wchar_t command_read[MAX_PATH + 20] = {0}; 1.299 + wsprintf(command_read, L"File_Create Read \"%ls\"", temp_file_name); 1.300 + wchar_t command_write[MAX_PATH + 20] = {0}; 1.301 + wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name); 1.302 + 1.303 + // Verify that we have read access after revert. 1.304 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_read)); 1.305 + 1.306 + // Verify that we don't have write access after revert. 1.307 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write)); 1.308 + 1.309 + // Verify that we really have write access to the file. 1.310 + runner.SetTestState(BEFORE_REVERT); 1.311 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write)); 1.312 + 1.313 + DeleteFile(temp_file_name); 1.314 +} 1.315 + 1.316 +TEST(FilePolicyTest, AllowWildcard) { 1.317 + TestRunner runner; 1.318 + 1.319 + // Create a temp file because we need write access to it. 1.320 + wchar_t temp_directory[MAX_PATH]; 1.321 + wchar_t temp_file_name[MAX_PATH]; 1.322 + ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); 1.323 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u); 1.324 + 1.325 + wcscat_s(temp_directory, MAX_PATH, L"*"); 1.326 + EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_directory)); 1.327 + 1.328 + wchar_t command_write[MAX_PATH + 20] = {0}; 1.329 + wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name); 1.330 + 1.331 + // Verify that we have write access after revert. 1.332 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write)); 1.333 + 1.334 + DeleteFile(temp_file_name); 1.335 +} 1.336 + 1.337 +TEST(FilePolicyTest, AllowNtCreatePatternRule) { 1.338 + TestRunner runner; 1.339 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"App*.dll")); 1.340 + 1.341 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.342 + runner.RunTest(L"File_OpenSys32 appmgmts.dll")); 1.343 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_OpenSys32 appwiz.cpl")); 1.344 + 1.345 + runner.SetTestState(BEFORE_REVERT); 1.346 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.347 + runner.RunTest(L"File_OpenSys32 appmgmts.dll")); 1.348 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_OpenSys32 appwiz.cpl")); 1.349 +} 1.350 + 1.351 +TEST(FilePolicyTest, CheckNotFound) { 1.352 + TestRunner runner; 1.353 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"n*.dll")); 1.354 + 1.355 + EXPECT_EQ(SBOX_TEST_NOT_FOUND, 1.356 + runner.RunTest(L"File_OpenSys32 notfound.dll")); 1.357 +} 1.358 + 1.359 +TEST(FilePolicyTest, CheckNoLeak) { 1.360 + TestRunner runner; 1.361 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 notfound.exe")); 1.362 +} 1.363 + 1.364 +TEST(FilePolicyTest, TestQueryAttributesFile) { 1.365 + TestRunner runner; 1.366 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, 1.367 + L"appmgmts.dll")); 1.368 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, 1.369 + L"notfound.exe")); 1.370 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"drivers")); 1.371 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_QUERY, 1.372 + L"ipconfig.exe")); 1.373 + 1.374 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.375 + runner.RunTest(L"File_QueryAttributes drivers d")); 1.376 + 1.377 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.378 + runner.RunTest(L"File_QueryAttributes appmgmts.dll f")); 1.379 + 1.380 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.381 + runner.RunTest(L"File_QueryAttributes ipconfig.exe f")); 1.382 + 1.383 + EXPECT_EQ(SBOX_TEST_DENIED, 1.384 + runner.RunTest(L"File_QueryAttributes ftp.exe f")); 1.385 + 1.386 + EXPECT_EQ(SBOX_TEST_NOT_FOUND, 1.387 + runner.RunTest(L"File_QueryAttributes notfound.exe f")); 1.388 +} 1.389 + 1.390 +// Makes sure that we don't leak information when there is not policy to allow 1.391 +// a path. 1.392 +TEST(FilePolicyTest, TestQueryAttributesFileNoPolicy) { 1.393 + TestRunner runner; 1.394 + EXPECT_EQ(SBOX_TEST_DENIED, 1.395 + runner.RunTest(L"File_QueryAttributes ftp.exe f")); 1.396 + 1.397 + EXPECT_EQ(SBOX_TEST_DENIED, 1.398 + runner.RunTest(L"File_QueryAttributes notfound.exe f")); 1.399 +} 1.400 + 1.401 +TEST(FilePolicyTest, TestRename) { 1.402 + TestRunner runner; 1.403 + 1.404 + // Give access to the temp directory. 1.405 + wchar_t temp_directory[MAX_PATH]; 1.406 + wchar_t temp_file_name1[MAX_PATH]; 1.407 + wchar_t temp_file_name2[MAX_PATH]; 1.408 + wchar_t temp_file_name3[MAX_PATH]; 1.409 + wchar_t temp_file_name4[MAX_PATH]; 1.410 + wchar_t temp_file_name5[MAX_PATH]; 1.411 + wchar_t temp_file_name6[MAX_PATH]; 1.412 + wchar_t temp_file_name7[MAX_PATH]; 1.413 + wchar_t temp_file_name8[MAX_PATH]; 1.414 + ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); 1.415 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name1), 0u); 1.416 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name2), 0u); 1.417 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name3), 0u); 1.418 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name4), 0u); 1.419 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name5), 0u); 1.420 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name6), 0u); 1.421 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name7), 0u); 1.422 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name8), 0u); 1.423 + 1.424 + 1.425 + // Add rules to make file1->file2 succeed. 1.426 + ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name1)); 1.427 + ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name2)); 1.428 + 1.429 + // Add rules to make file3->file4 fail. 1.430 + ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name3)); 1.431 + ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, 1.432 + temp_file_name4)); 1.433 + 1.434 + // Add rules to make file5->file6 fail. 1.435 + ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, 1.436 + temp_file_name5)); 1.437 + ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name6)); 1.438 + 1.439 + // Add rules to make file7->no_pol_file fail. 1.440 + ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name7)); 1.441 + 1.442 + // Delete the files where the files are going to be renamed to. 1.443 + ::DeleteFile(temp_file_name2); 1.444 + ::DeleteFile(temp_file_name4); 1.445 + ::DeleteFile(temp_file_name6); 1.446 + ::DeleteFile(temp_file_name8); 1.447 + 1.448 + 1.449 + wchar_t command[MAX_PATH*2 + 20] = {0}; 1.450 + wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name1, 1.451 + temp_file_name2); 1.452 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command)); 1.453 + 1.454 + wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name3, 1.455 + temp_file_name4); 1.456 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); 1.457 + 1.458 + wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name5, 1.459 + temp_file_name6); 1.460 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); 1.461 + 1.462 + wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name7, 1.463 + temp_file_name8); 1.464 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command)); 1.465 + 1.466 + 1.467 + // Delete all the files in case they are still there. 1.468 + ::DeleteFile(temp_file_name1); 1.469 + ::DeleteFile(temp_file_name2); 1.470 + ::DeleteFile(temp_file_name3); 1.471 + ::DeleteFile(temp_file_name4); 1.472 + ::DeleteFile(temp_file_name5); 1.473 + ::DeleteFile(temp_file_name6); 1.474 + ::DeleteFile(temp_file_name7); 1.475 + ::DeleteFile(temp_file_name8); 1.476 +} 1.477 + 1.478 +TEST(FilePolicyTest, OpenSys32FilesDenyBecauseOfDir) { 1.479 + TestRunner runner; 1.480 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, 1.481 + L"notepad.exe")); 1.482 + 1.483 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe")); 1.484 + 1.485 + runner.SetTestState(BEFORE_REVERT); 1.486 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.487 + runner.RunTest(L"File_Win32Create notepad.exe")); 1.488 +} 1.489 + 1.490 +TEST(FilePolicyTest, OpenSys32FilesAllowNotepad) { 1.491 + TestRunner runner; 1.492 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, 1.493 + L"notepad.exe")); 1.494 + 1.495 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.496 + runner.RunTest(L"File_Win32Create notepad.exe")); 1.497 + 1.498 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create calc.exe")); 1.499 + 1.500 + runner.SetTestState(BEFORE_REVERT); 1.501 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, 1.502 + runner.RunTest(L"File_Win32Create notepad.exe")); 1.503 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_Win32Create calc.exe")); 1.504 +} 1.505 + 1.506 +TEST(FilePolicyTest, FileGetDiskSpace) { 1.507 + TestRunner runner; 1.508 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_GetDiskSpace")); 1.509 + runner.SetTestState(BEFORE_REVERT); 1.510 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace")); 1.511 + 1.512 + // Add an 'allow' rule in the windows\system32 such that GetDiskFreeSpaceEx 1.513 + // succeeds (it does an NtOpenFile) but windows\system32\notepad.exe is 1.514 + // denied since there is no wild card in the rule. 1.515 + EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L"")); 1.516 + runner.SetTestState(BEFORE_REVERT); 1.517 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace")); 1.518 + 1.519 + runner.SetTestState(AFTER_REVERT); 1.520 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace")); 1.521 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe")); 1.522 +} 1.523 + 1.524 +// http://crbug.com/146944 1.525 +TEST(FilePolicyTest, DISABLED_TestReparsePoint) { 1.526 + TestRunner runner; 1.527 + 1.528 + // Create a temp file because we need write access to it. 1.529 + wchar_t temp_directory[MAX_PATH]; 1.530 + wchar_t temp_file_name[MAX_PATH]; 1.531 + ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u); 1.532 + ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u); 1.533 + 1.534 + // Delete the file and create a directory instead. 1.535 + ASSERT_TRUE(::DeleteFile(temp_file_name)); 1.536 + ASSERT_TRUE(::CreateDirectory(temp_file_name, NULL)); 1.537 + 1.538 + // Create a temporary file in the subfolder. 1.539 + std::wstring subfolder = temp_file_name; 1.540 + std::wstring temp_file_title = subfolder.substr(subfolder.rfind(L"\\") + 1); 1.541 + std::wstring temp_file = subfolder + L"\\file_" + temp_file_title; 1.542 + 1.543 + HANDLE file = ::CreateFile(temp_file.c_str(), FILE_ALL_ACCESS, 1.544 + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 1.545 + CREATE_ALWAYS, 0, NULL); 1.546 + ASSERT_TRUE(INVALID_HANDLE_VALUE != file); 1.547 + ASSERT_TRUE(::CloseHandle(file)); 1.548 + 1.549 + // Create a temporary file in the temp directory. 1.550 + std::wstring temp_dir = temp_directory; 1.551 + std::wstring temp_file_in_temp = temp_dir + L"file_" + temp_file_title; 1.552 + file = ::CreateFile(temp_file_in_temp.c_str(), FILE_ALL_ACCESS, 1.553 + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 1.554 + CREATE_ALWAYS, 0, NULL); 1.555 + ASSERT_TRUE(file != NULL); 1.556 + ASSERT_TRUE(::CloseHandle(file)); 1.557 + 1.558 + // Give write access to the temp directory. 1.559 + std::wstring temp_dir_wildcard = temp_dir + L"*"; 1.560 + EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, 1.561 + temp_dir_wildcard.c_str())); 1.562 + 1.563 + // Prepare the command to execute. 1.564 + std::wstring command_write; 1.565 + command_write += L"File_Create Write \""; 1.566 + command_write += temp_file; 1.567 + command_write += L"\""; 1.568 + 1.569 + // Verify that we have write access to the original file 1.570 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write.c_str())); 1.571 + 1.572 + // Replace the subfolder by a reparse point to %temp%. 1.573 + ::DeleteFile(temp_file.c_str()); 1.574 + HANDLE dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS, 1.575 + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 1.576 + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 1.577 + EXPECT_TRUE(INVALID_HANDLE_VALUE != dir); 1.578 + 1.579 + std::wstring temp_dir_nt; 1.580 + temp_dir_nt += L"\\??\\"; 1.581 + temp_dir_nt += temp_dir; 1.582 + EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str())); 1.583 + EXPECT_TRUE(::CloseHandle(dir)); 1.584 + 1.585 + // Try to open the file again. 1.586 + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write.c_str())); 1.587 + 1.588 + // Remove the reparse point. 1.589 + dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS, 1.590 + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 1.591 + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 1.592 + NULL); 1.593 + EXPECT_TRUE(INVALID_HANDLE_VALUE != dir); 1.594 + EXPECT_TRUE(DeleteReparsePoint(dir)); 1.595 + EXPECT_TRUE(::CloseHandle(dir)); 1.596 + 1.597 + // Cleanup. 1.598 + EXPECT_TRUE(::DeleteFile(temp_file_in_temp.c_str())); 1.599 + EXPECT_TRUE(::RemoveDirectory(subfolder.c_str())); 1.600 +} 1.601 + 1.602 +} // namespace sandbox