file_policy_test.cc 26 KB

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