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