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 "base/strings/stringprintf.h"
6#include "base/win/scoped_handle.h"
7
8#include "base/win/windows_version.h"
9#include "sandbox/win/src/nt_internals.h"
10#include "sandbox/win/src/process_mitigations.h"
11#include "sandbox/win/src/sandbox.h"
12#include "sandbox/win/src/sandbox_factory.h"
13#include "sandbox/win/src/target_services.h"
14#include "sandbox/win/src/win_utils.h"
15#include "sandbox/win/tests/common/controller.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace {
19
20typedef BOOL (WINAPI *GetProcessDEPPolicyFunction)(
21    HANDLE process,
22    LPDWORD flags,
23    PBOOL permanent);
24
25typedef BOOL (WINAPI *GetProcessMitigationPolicyFunction)(
26    HANDLE process,
27    PROCESS_MITIGATION_POLICY mitigation_policy,
28    PVOID buffer,
29    SIZE_T length);
30
31GetProcessMitigationPolicyFunction get_process_mitigation_policy;
32
33bool CheckWin8DepPolicy() {
34  PROCESS_MITIGATION_DEP_POLICY policy;
35  if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDEPPolicy,
36                                     &policy, sizeof(policy))) {
37    return false;
38  }
39  return policy.Enable && policy.Permanent;
40}
41
42bool CheckWin8AslrPolicy() {
43  PROCESS_MITIGATION_ASLR_POLICY policy;
44  if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessASLRPolicy,
45                                     &policy, sizeof(policy))) {
46     return false;
47  }
48  return policy.EnableForceRelocateImages && policy.DisallowStrippedImages;
49}
50
51bool CheckWin8StrictHandlePolicy() {
52  PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy;
53  if (!get_process_mitigation_policy(::GetCurrentProcess(),
54                                     ProcessStrictHandleCheckPolicy,
55                                     &policy, sizeof(policy))) {
56     return false;
57  }
58  return policy.RaiseExceptionOnInvalidHandleReference &&
59         policy.HandleExceptionsPermanentlyEnabled;
60}
61
62bool CheckWin8Win32CallPolicy() {
63  PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy;
64  if (!get_process_mitigation_policy(::GetCurrentProcess(),
65                                     ProcessSystemCallDisablePolicy,
66                                     &policy, sizeof(policy))) {
67     return false;
68  }
69  return policy.DisallowWin32kSystemCalls;
70}
71
72bool CheckWin8DllExtensionPolicy() {
73  PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy;
74  if (!get_process_mitigation_policy(::GetCurrentProcess(),
75                                     ProcessExtensionPointDisablePolicy,
76                                     &policy, sizeof(policy))) {
77     return false;
78  }
79  return policy.DisableExtensionPoints;
80}
81
82}  // namespace
83
84namespace sandbox {
85
86SBOX_TESTS_COMMAND int CheckWin8(int argc, wchar_t **argv) {
87  get_process_mitigation_policy =
88      reinterpret_cast<GetProcessMitigationPolicyFunction>(
89          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
90                           "GetProcessMitigationPolicy"));
91  if (!get_process_mitigation_policy)
92    return SBOX_TEST_NOT_FOUND;
93
94  if (!CheckWin8DepPolicy())
95    return SBOX_TEST_FIRST_ERROR;
96
97#if defined(NDEBUG)  // ASLR cannot be forced in debug builds.
98  if (!CheckWin8AslrPolicy())
99    return SBOX_TEST_SECOND_ERROR;
100#endif
101
102  if (!CheckWin8StrictHandlePolicy())
103    return SBOX_TEST_THIRD_ERROR;
104
105  if (!CheckWin8DllExtensionPolicy())
106    return SBOX_TEST_FIFTH_ERROR;
107
108  return SBOX_TEST_SUCCEEDED;
109}
110
111TEST(ProcessMitigationsTest, CheckWin8) {
112  if (base::win::GetVersion() < base::win::VERSION_WIN8)
113    return;
114
115  TestRunner runner;
116  sandbox::TargetPolicy* policy = runner.GetPolicy();
117
118  sandbox::MitigationFlags mitigations = MITIGATION_DEP |
119                                         MITIGATION_DEP_NO_ATL_THUNK |
120                                         MITIGATION_EXTENSION_DLL_DISABLE;
121#if defined(NDEBUG)  // ASLR cannot be forced in debug builds.
122  mitigations |= MITIGATION_RELOCATE_IMAGE |
123                 MITIGATION_RELOCATE_IMAGE_REQUIRED;
124#endif
125
126  EXPECT_EQ(policy->SetProcessMitigations(mitigations), SBOX_ALL_OK);
127
128  mitigations |= MITIGATION_STRICT_HANDLE_CHECKS;
129
130  EXPECT_EQ(policy->SetDelayedProcessMitigations(mitigations), SBOX_ALL_OK);
131
132  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8"));
133}
134
135
136SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t **argv) {
137  GetProcessDEPPolicyFunction get_process_dep_policy =
138      reinterpret_cast<GetProcessDEPPolicyFunction>(
139          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
140                           "GetProcessDEPPolicy"));
141  if (get_process_dep_policy) {
142    BOOL is_permanent = FALSE;
143    DWORD dep_flags = 0;
144
145    if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags,
146        &is_permanent)) {
147      return SBOX_TEST_FIRST_ERROR;
148    }
149
150    if (!(dep_flags & PROCESS_DEP_ENABLE) || !is_permanent)
151      return SBOX_TEST_SECOND_ERROR;
152
153  } else {
154    NtQueryInformationProcessFunction query_information_process = NULL;
155    ResolveNTFunctionPtr("NtQueryInformationProcess",
156                          &query_information_process);
157    if (!query_information_process)
158      return SBOX_TEST_NOT_FOUND;
159
160    ULONG size = 0;
161    ULONG dep_flags = 0;
162    if (!SUCCEEDED(query_information_process(::GetCurrentProcess(),
163                                             ProcessExecuteFlags, &dep_flags,
164                                             sizeof(dep_flags), &size))) {
165      return SBOX_TEST_THIRD_ERROR;
166    }
167
168    const int MEM_EXECUTE_OPTION_ENABLE = 1;
169    const int MEM_EXECUTE_OPTION_DISABLE = 2;
170    const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4;
171    const int MEM_EXECUTE_OPTION_PERMANENT = 8;
172    dep_flags &= 0xff;
173
174    if (dep_flags != (MEM_EXECUTE_OPTION_DISABLE |
175                      MEM_EXECUTE_OPTION_PERMANENT)) {
176      return SBOX_TEST_FOURTH_ERROR;
177    }
178  }
179
180  return SBOX_TEST_SUCCEEDED;
181}
182
183#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
184TEST(ProcessMitigationsTest, CheckDep) {
185  if (base::win::GetVersion() > base::win::VERSION_WIN7)
186    return;
187
188  TestRunner runner;
189  sandbox::TargetPolicy* policy = runner.GetPolicy();
190
191  EXPECT_EQ(policy->SetProcessMitigations(
192                MITIGATION_DEP |
193                MITIGATION_DEP_NO_ATL_THUNK |
194                MITIGATION_SEHOP),
195            SBOX_ALL_OK);
196  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDep"));
197}
198#endif
199
200SBOX_TESTS_COMMAND int CheckWin8Lockdown(int argc, wchar_t **argv) {
201  get_process_mitigation_policy =
202      reinterpret_cast<GetProcessMitigationPolicyFunction>(
203          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
204                           "GetProcessMitigationPolicy"));
205  if (!get_process_mitigation_policy)
206    return SBOX_TEST_NOT_FOUND;
207
208  if (!CheckWin8Win32CallPolicy())
209    return SBOX_TEST_FIRST_ERROR;
210  return SBOX_TEST_SUCCEEDED;
211}
212
213// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation on
214// the target process causes the launch to fail in process initialization.
215// The test process itself links against user32/gdi32.
216TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownFailure) {
217  if (base::win::GetVersion() < base::win::VERSION_WIN8)
218    return;
219
220  TestRunner runner;
221  sandbox::TargetPolicy* policy = runner.GetPolicy();
222
223  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
224            SBOX_ALL_OK);
225  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
226}
227
228// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation
229// along with the policy to fake user32 and gdi32 initialization successfully
230// launches the target process.
231// The test process itself links against user32/gdi32.
232TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownSuccess) {
233  if (base::win::GetVersion() < base::win::VERSION_WIN8)
234    return;
235
236  TestRunner runner;
237  sandbox::TargetPolicy* policy = runner.GetPolicy();
238
239  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
240            SBOX_ALL_OK);
241  EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
242                            sandbox::TargetPolicy::FAKE_USER_GDI_INIT, NULL),
243            sandbox::SBOX_ALL_OK);
244  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
245}
246
247}  // namespace sandbox
248
249