- add sources.
[platform/framework/web/crosswalk.git] / src / sandbox / win / src / process_policy_test.cc
1 // Copyright (c) 2012 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 <memory>
6 #include <string>
7
8 #include "base/strings/string16.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "base/win/scoped_handle.h"
11 #include "base/win/scoped_process_information.h"
12 #include "base/win/windows_version.h"
13 #include "sandbox/win/src/sandbox.h"
14 #include "sandbox/win/src/sandbox_factory.h"
15 #include "sandbox/win/src/sandbox_policy.h"
16 #include "sandbox/win/tests/common/controller.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace {
20
21 // While the shell API provides better calls than this home brew function
22 // we use GetSystemWindowsDirectoryW which does not query the registry so
23 // it is safe to use after revert.
24 string16 MakeFullPathToSystem32(const wchar_t* name) {
25   wchar_t windows_path[MAX_PATH] = {0};
26   ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH);
27   string16 full_path(windows_path);
28   if (full_path.empty()) {
29     return full_path;
30   }
31   full_path += L"\\system32\\";
32   full_path += name;
33   return full_path;
34 }
35
36 // Creates a process with the |exe| and |command| parameter using the
37 // unicode and ascii version of the api.
38 sandbox::SboxTestResult CreateProcessHelper(const string16& exe,
39                                             const string16& command) {
40   base::win::ScopedProcessInformation pi;
41   STARTUPINFOW si = {sizeof(si)};
42
43   const wchar_t *exe_name = NULL;
44   if (!exe.empty())
45     exe_name = exe.c_str();
46
47   const wchar_t *cmd_line = NULL;
48   if (!command.empty())
49     cmd_line = command.c_str();
50
51   // Create the process with the unicode version of the API.
52   sandbox::SboxTestResult ret1 = sandbox::SBOX_TEST_FAILED;
53   if (!::CreateProcessW(exe_name, const_cast<wchar_t*>(cmd_line), NULL, NULL,
54                         FALSE, 0, NULL, NULL, &si, pi.Receive())) {
55     DWORD last_error = GetLastError();
56     if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
57         (ERROR_ACCESS_DENIED == last_error) ||
58         (ERROR_FILE_NOT_FOUND == last_error)) {
59       ret1 = sandbox::SBOX_TEST_DENIED;
60     } else {
61       ret1 = sandbox::SBOX_TEST_FAILED;
62     }
63   } else {
64     ret1 = sandbox::SBOX_TEST_SUCCEEDED;
65   }
66
67   pi.Close();
68
69   // Do the same with the ansi version of the api
70   STARTUPINFOA sia = {sizeof(sia)};
71   sandbox::SboxTestResult ret2 = sandbox::SBOX_TEST_FAILED;
72
73   std::string narrow_cmd_line;
74   if (cmd_line)
75     narrow_cmd_line = base::SysWideToMultiByte(cmd_line, CP_UTF8);
76   if (!::CreateProcessA(
77         exe_name ? base::SysWideToMultiByte(exe_name, CP_UTF8).c_str() : NULL,
78         cmd_line ? const_cast<char*>(narrow_cmd_line.c_str()) : NULL,
79         NULL, NULL, FALSE, 0, NULL, NULL, &sia, pi.Receive())) {
80     DWORD last_error = GetLastError();
81     if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
82         (ERROR_ACCESS_DENIED == last_error) ||
83         (ERROR_FILE_NOT_FOUND == last_error)) {
84       ret2 = sandbox::SBOX_TEST_DENIED;
85     } else {
86       ret2 = sandbox::SBOX_TEST_FAILED;
87     }
88   } else {
89     ret2 = sandbox::SBOX_TEST_SUCCEEDED;
90   }
91
92   if (ret1 == ret2)
93     return ret1;
94
95   return sandbox::SBOX_TEST_FAILED;
96 }
97
98 }  // namespace
99
100 namespace sandbox {
101
102 SBOX_TESTS_COMMAND int Process_RunApp1(int argc, wchar_t **argv) {
103   if (argc != 1) {
104     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
105   }
106   if ((NULL == argv) || (NULL == argv[0])) {
107     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
108   }
109   string16 path = MakeFullPathToSystem32(argv[0]);
110
111   // TEST 1: Try with the path in the app_name.
112   return CreateProcessHelper(path, string16());
113 }
114
115 SBOX_TESTS_COMMAND int Process_RunApp2(int argc, wchar_t **argv) {
116   if (argc != 1) {
117     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
118   }
119   if ((NULL == argv) || (NULL == argv[0])) {
120     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
121   }
122   string16 path = MakeFullPathToSystem32(argv[0]);
123
124   // TEST 2: Try with the path in the cmd_line.
125   string16 cmd_line = L"\"";
126   cmd_line += path;
127   cmd_line += L"\"";
128   return CreateProcessHelper(string16(), cmd_line);
129 }
130
131 SBOX_TESTS_COMMAND int Process_RunApp3(int argc, wchar_t **argv) {
132   if (argc != 1) {
133     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
134   }
135   if ((NULL == argv) || (NULL == argv[0])) {
136     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
137   }
138
139   // TEST 3: Try file name in the cmd_line.
140   return CreateProcessHelper(string16(), argv[0]);
141 }
142
143 SBOX_TESTS_COMMAND int Process_RunApp4(int argc, wchar_t **argv) {
144   if (argc != 1) {
145     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
146   }
147   if ((NULL == argv) || (NULL == argv[0])) {
148     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
149   }
150
151   // TEST 4: Try file name in the app_name and current directory sets correctly.
152   string16 system32 = MakeFullPathToSystem32(L"");
153   wchar_t current_directory[MAX_PATH + 1];
154   int result4;
155   bool test_succeeded = false;
156   DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
157   if (!ret)
158     return SBOX_TEST_FIRST_ERROR;
159
160   if (ret < MAX_PATH) {
161     current_directory[ret] = L'\\';
162     current_directory[ret+1] = L'\0';
163     if (::SetCurrentDirectory(system32.c_str())) {
164       result4 = CreateProcessHelper(argv[0], string16());
165       if (::SetCurrentDirectory(current_directory)) {
166         test_succeeded = true;
167       }
168     } else {
169       return SBOX_TEST_SECOND_ERROR;
170     }
171   }
172   if (!test_succeeded)
173     result4 = SBOX_TEST_FAILED;
174
175   return result4;
176 }
177
178 SBOX_TESTS_COMMAND int Process_RunApp5(int argc, wchar_t **argv) {
179   if (argc != 1) {
180     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
181   }
182   if ((NULL == argv) || (NULL == argv[0])) {
183     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
184   }
185   string16 path = MakeFullPathToSystem32(argv[0]);
186
187   // TEST 5: Try with the path in the cmd_line and arguments.
188   string16 cmd_line = L"\"";
189   cmd_line += path;
190   cmd_line += L"\" /I";
191   return CreateProcessHelper(string16(), cmd_line);
192 }
193
194 SBOX_TESTS_COMMAND int Process_RunApp6(int argc, wchar_t **argv) {
195   if (argc != 1) {
196     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
197   }
198   if ((NULL == argv) || (NULL == argv[0])) {
199     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
200   }
201
202   // TEST 6: Try with the file_name in the cmd_line and arguments.
203   string16 cmd_line = argv[0];
204   cmd_line += L" /I";
205   return CreateProcessHelper(string16(), cmd_line);
206 }
207
208 // Creates a process and checks if it's possible to get a handle to it's token.
209 SBOX_TESTS_COMMAND int Process_GetChildProcessToken(int argc, wchar_t **argv) {
210   if (argc != 1)
211     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
212
213   if ((NULL == argv) || (NULL == argv[0]))
214     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
215
216   string16 path = MakeFullPathToSystem32(argv[0]);
217
218   base::win::ScopedProcessInformation pi;
219   STARTUPINFOW si = {sizeof(si)};
220
221   if (!::CreateProcessW(path.c_str(), NULL, NULL, NULL, FALSE, CREATE_SUSPENDED,
222                         NULL, NULL, &si, pi.Receive())) {
223       return SBOX_TEST_FAILED;
224   }
225
226   HANDLE token = NULL;
227   BOOL result =
228       ::OpenProcessToken(pi.process_handle(), TOKEN_IMPERSONATE, &token);
229   DWORD error = ::GetLastError();
230
231   base::win::ScopedHandle token_handle(token);
232
233   if (!::TerminateProcess(pi.process_handle(), 0))
234     return SBOX_TEST_FAILED;
235
236   if (result && token)
237     return SBOX_TEST_SUCCEEDED;
238
239   if (ERROR_ACCESS_DENIED == error)
240     return SBOX_TEST_DENIED;
241
242   return SBOX_TEST_FAILED;
243 }
244
245
246 SBOX_TESTS_COMMAND int Process_OpenToken(int argc, wchar_t **argv) {
247   HANDLE token;
248   if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
249     if (ERROR_ACCESS_DENIED == ::GetLastError()) {
250       return SBOX_TEST_DENIED;
251     }
252   } else {
253     ::CloseHandle(token);
254     return SBOX_TEST_SUCCEEDED;
255   }
256
257   return SBOX_TEST_FAILED;
258 }
259
260 TEST(ProcessPolicyTest, TestAllAccess) {
261   // Check if the "all access" rule fails to be added when the token is too
262   // powerful.
263   TestRunner runner;
264
265   // Check the failing case.
266   runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
267   EXPECT_EQ(SBOX_ERROR_UNSUPPORTED,
268             runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
269                                         TargetPolicy::PROCESS_ALL_EXEC,
270                                         L"this is not important"));
271
272   // Check the working case.
273   runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_INTERACTIVE);
274
275   EXPECT_EQ(SBOX_ALL_OK,
276             runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
277                                         TargetPolicy::PROCESS_ALL_EXEC,
278                                         L"this is not important"));
279 }
280
281 TEST(ProcessPolicyTest, CreateProcessAW) {
282   TestRunner runner;
283   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
284   string16 system32 = MakeFullPathToSystem32(L"");
285   ASSERT_TRUE(!exe_path.empty());
286   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
287                              TargetPolicy::PROCESS_MIN_EXEC,
288                              exe_path.c_str()));
289
290   // Need to add directory rules for the directories that we use in
291   // SetCurrentDirectory.
292   EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_DIR_ANY,
293                                system32.c_str()));
294
295   wchar_t current_directory[MAX_PATH];
296   DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
297   ASSERT_TRUE(0 != ret && ret < MAX_PATH);
298
299   wcscat_s(current_directory, MAX_PATH, L"\\");
300   EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_DIR_ANY,
301                                current_directory));
302
303   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp1 calc.exe"));
304   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp2 calc.exe"));
305   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp3 calc.exe"));
306   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp5 calc.exe"));
307   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp6 calc.exe"));
308
309   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
310             runner.RunTest(L"Process_RunApp1 findstr.exe"));
311   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
312             runner.RunTest(L"Process_RunApp2 findstr.exe"));
313   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
314             runner.RunTest(L"Process_RunApp3 findstr.exe"));
315   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
316             runner.RunTest(L"Process_RunApp5 findstr.exe"));
317   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
318             runner.RunTest(L"Process_RunApp6 findstr.exe"));
319
320 #if !defined(_WIN64)
321   if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
322     // WinXP results are not reliable.
323     EXPECT_EQ(SBOX_TEST_SECOND_ERROR,
324         runner.RunTest(L"Process_RunApp4 calc.exe"));
325     EXPECT_EQ(SBOX_TEST_SECOND_ERROR,
326         runner.RunTest(L"Process_RunApp4 findstr.exe"));
327   }
328 #endif
329 }
330
331 TEST(ProcessPolicyTest, OpenToken) {
332   TestRunner runner;
333   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_OpenToken"));
334 }
335
336 TEST(ProcessPolicyTest, TestGetProcessTokenMinAccess) {
337   TestRunner runner;
338   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
339   ASSERT_TRUE(!exe_path.empty());
340   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
341                              TargetPolicy::PROCESS_MIN_EXEC,
342                              exe_path.c_str()));
343
344   EXPECT_EQ(SBOX_TEST_DENIED,
345             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
346 }
347
348 TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccess) {
349   TestRunner runner(JOB_UNPROTECTED, USER_INTERACTIVE, USER_INTERACTIVE);
350   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
351   ASSERT_TRUE(!exe_path.empty());
352   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
353                              TargetPolicy::PROCESS_ALL_EXEC,
354                              exe_path.c_str()));
355
356   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
357             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
358 }
359
360 TEST(ProcessPolicyTest, TestGetProcessTokenMinAccessNoJob) {
361   TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
362   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
363   ASSERT_TRUE(!exe_path.empty());
364   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
365                              TargetPolicy::PROCESS_MIN_EXEC,
366                              exe_path.c_str()));
367
368   EXPECT_EQ(SBOX_TEST_DENIED,
369             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
370 }
371
372 TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccessNoJob) {
373   TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
374   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
375   ASSERT_TRUE(!exe_path.empty());
376   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
377                              TargetPolicy::PROCESS_ALL_EXEC,
378                              exe_path.c_str()));
379
380   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
381             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
382 }
383
384 }  // namespace sandbox