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