security/sandbox/win/src/file_policy_test.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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

mercurial