1 // Copyright 2014 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 "sandbox/win/src/process_mitigations_win32k_policy.h"
6
7 #include <stddef.h>
8
9 #include "sandbox/win/src/process_mitigations_win32k_interception.h"
10
11 namespace sandbox {
12
13 namespace {
14
15 // Define GUIDs for OPM APIs
16 const GUID DXGKMDT_OPM_GET_CONNECTOR_TYPE = {
17 0x81d0bfd5,
18 0x6afe,
19 0x48c2,
20 {0x99, 0xc0, 0x95, 0xa0, 0x8f, 0x97, 0xc5, 0xda}};
21 const GUID DXGKMDT_OPM_GET_SUPPORTED_PROTECTION_TYPES = {
22 0x38f2a801,
23 0x9a6c,
24 0x48bb,
25 {0x91, 0x07, 0xb6, 0x69, 0x6e, 0x6f, 0x17, 0x97}};
26 const GUID DXGKMDT_OPM_GET_VIRTUAL_PROTECTION_LEVEL = {
27 0xb2075857,
28 0x3eda,
29 0x4d5d,
30 {0x88, 0xdb, 0x74, 0x8f, 0x8c, 0x1a, 0x05, 0x49}};
31 const GUID DXGKMDT_OPM_GET_ACTUAL_PROTECTION_LEVEL = {
32 0x1957210a,
33 0x7766,
34 0x452a,
35 {0xb9, 0x9a, 0xd2, 0x7a, 0xed, 0x54, 0xf0, 0x3a}};
36 const GUID DXGKMDT_OPM_SET_PROTECTION_LEVEL = {
37 0x9bb9327c,
38 0x4eb5,
39 0x4727,
40 {0x9f, 0x00, 0xb4, 0x2b, 0x09, 0x19, 0xc0, 0xda}};
41
StringToUnicodeString(PUNICODE_STRING unicode_string,const std::wstring & device_name)42 void StringToUnicodeString(PUNICODE_STRING unicode_string,
43 const std::wstring& device_name) {
44 static RtlInitUnicodeStringFunction RtlInitUnicodeString;
45 if (!RtlInitUnicodeString) {
46 HMODULE ntdll = ::GetModuleHandle(kNtdllName);
47 RtlInitUnicodeString = reinterpret_cast<RtlInitUnicodeStringFunction>(
48 GetProcAddress(ntdll, "RtlInitUnicodeString"));
49 }
50 RtlInitUnicodeString(unicode_string, device_name.c_str());
51 }
52
53 struct MonitorListState {
54 HMONITOR* monitor_list;
55 uint32_t monitor_list_size;
56 uint32_t monitor_list_pos;
57 };
58
DisplayMonitorEnumProc(HMONITOR monitor,HDC hdc_monitor,LPRECT rect_monitor,LPARAM data)59 BOOL CALLBACK DisplayMonitorEnumProc(HMONITOR monitor,
60 HDC hdc_monitor,
61 LPRECT rect_monitor,
62 LPARAM data) {
63 MonitorListState* state = reinterpret_cast<MonitorListState*>(data);
64 if (state->monitor_list_pos >= state->monitor_list_size)
65 return false;
66 state->monitor_list[state->monitor_list_pos++] = monitor;
67 return true;
68 }
69
70 template <typename T>
GetExportedFunc(const wchar_t * libname,const char * name)71 T GetExportedFunc(const wchar_t* libname, const char* name) {
72 OverrideForTestFunction test_override =
73 ProcessMitigationsWin32KLockdownPolicy::GetOverrideForTestCallback();
74 if (test_override)
75 return reinterpret_cast<T>(test_override(name));
76
77 static T func = nullptr;
78 if (!func) {
79 func =
80 reinterpret_cast<T>(::GetProcAddress(::GetModuleHandle(libname), name));
81 DCHECK(!!func);
82 }
83 return func;
84 }
85
86 #define GDIFUNC(name) GetExportedFunc<name##Function>(L"gdi32.dll", #name)
87 #define USERFUNC(name) GetExportedFunc<name##Function>(L"user32.dll", #name)
88
89 struct ValidateMonitorParams {
90 HMONITOR monitor;
91 std::wstring device_name;
92 bool result;
93 };
94
GetMonitorDeviceName(HMONITOR monitor,std::wstring * device_name)95 bool GetMonitorDeviceName(HMONITOR monitor, std::wstring* device_name) {
96 MONITORINFOEXW monitor_info = {};
97 monitor_info.cbSize = sizeof(monitor_info);
98 if (!USERFUNC(GetMonitorInfoW)(monitor, &monitor_info))
99 return false;
100 if (monitor_info.szDevice[CCHDEVICENAME - 1] != 0)
101 return false;
102 *device_name = monitor_info.szDevice;
103 return true;
104 }
105
ValidateMonitorEnumProc(HMONITOR monitor,HDC,LPRECT,LPARAM data)106 BOOL CALLBACK ValidateMonitorEnumProc(HMONITOR monitor,
107 HDC,
108 LPRECT,
109 LPARAM data) {
110 ValidateMonitorParams* valid_params =
111 reinterpret_cast<ValidateMonitorParams*>(data);
112 std::wstring device_name;
113 bool result = false;
114 if (valid_params->device_name.empty()) {
115 result = monitor == valid_params->monitor;
116 } else if (GetMonitorDeviceName(monitor, &device_name)) {
117 result = device_name == valid_params->device_name;
118 }
119 valid_params->result = result;
120 if (!result)
121 return true;
122 return false;
123 }
124
IsValidMonitorOrDeviceName(HMONITOR monitor,const wchar_t * device_name)125 bool IsValidMonitorOrDeviceName(HMONITOR monitor, const wchar_t* device_name) {
126 ValidateMonitorParams params = {};
127 params.monitor = monitor;
128 if (device_name)
129 params.device_name = device_name;
130 USERFUNC(EnumDisplayMonitors)
131 (nullptr, nullptr, ValidateMonitorEnumProc,
132 reinterpret_cast<LPARAM>(¶ms));
133 return params.result;
134 }
135
136 } // namespace
137
138 OverrideForTestFunction
139 ProcessMitigationsWin32KLockdownPolicy::override_callback_;
140
GenerateRules(const wchar_t * name,TargetPolicy::Semantics semantics,LowLevelPolicy * policy)141 bool ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
142 const wchar_t* name,
143 TargetPolicy::Semantics semantics,
144 LowLevelPolicy* policy) {
145 PolicyRule rule(FAKE_SUCCESS);
146 if (!policy->AddRule(IpcTag::GDI_GDIDLLINITIALIZE, &rule))
147 return false;
148 if (!policy->AddRule(IpcTag::GDI_GETSTOCKOBJECT, &rule))
149 return false;
150 if (!policy->AddRule(IpcTag::USER_REGISTERCLASSW, &rule))
151 return false;
152 if (semantics != TargetPolicy::IMPLEMENT_OPM_APIS)
153 return true;
154 if (!policy->AddRule(IpcTag::USER_ENUMDISPLAYMONITORS, &rule))
155 return false;
156 if (!policy->AddRule(IpcTag::USER_ENUMDISPLAYDEVICES, &rule))
157 return false;
158 if (!policy->AddRule(IpcTag::USER_GETMONITORINFO, &rule))
159 return false;
160 if (!policy->AddRule(IpcTag::GDI_CREATEOPMPROTECTEDOUTPUTS, &rule))
161 return false;
162 if (!policy->AddRule(IpcTag::GDI_GETCERTIFICATE, &rule))
163 return false;
164 if (!policy->AddRule(IpcTag::GDI_GETCERTIFICATESIZE, &rule))
165 return false;
166 if (!policy->AddRule(IpcTag::GDI_DESTROYOPMPROTECTEDOUTPUT, &rule))
167 return false;
168 if (!policy->AddRule(IpcTag::GDI_CONFIGUREOPMPROTECTEDOUTPUT, &rule))
169 return false;
170 if (!policy->AddRule(IpcTag::GDI_GETOPMINFORMATION, &rule))
171 return false;
172 if (!policy->AddRule(IpcTag::GDI_GETOPMRANDOMNUMBER, &rule))
173 return false;
174 if (!policy->AddRule(IpcTag::GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE,
175 &rule))
176 return false;
177 if (!policy->AddRule(IpcTag::GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS, &rule))
178 return false;
179 return true;
180 }
181
EnumDisplayMonitorsAction(const ClientInfo & client_info,HMONITOR * monitor_list,uint32_t monitor_list_size)182 uint32_t ProcessMitigationsWin32KLockdownPolicy::EnumDisplayMonitorsAction(
183 const ClientInfo& client_info,
184 HMONITOR* monitor_list,
185 uint32_t monitor_list_size) {
186 MonitorListState state = {monitor_list, monitor_list_size, 0};
187 USERFUNC(EnumDisplayMonitors)
188 (nullptr, nullptr, DisplayMonitorEnumProc, reinterpret_cast<LPARAM>(&state));
189 return state.monitor_list_pos;
190 }
191
GetMonitorInfoAction(const ClientInfo & client_info,HMONITOR monitor,MONITORINFO * monitor_info_ptr)192 bool ProcessMitigationsWin32KLockdownPolicy::GetMonitorInfoAction(
193 const ClientInfo& client_info,
194 HMONITOR monitor,
195 MONITORINFO* monitor_info_ptr) {
196 if (!IsValidMonitorOrDeviceName(monitor, nullptr))
197 return false;
198 MONITORINFOEXW monitor_info = {};
199 monitor_info.cbSize = sizeof(MONITORINFOEXW);
200
201 bool success = USERFUNC(GetMonitorInfoW)(
202 monitor, reinterpret_cast<MONITORINFO*>(&monitor_info));
203 if (success)
204 memcpy(monitor_info_ptr, &monitor_info, sizeof(monitor_info));
205 return success;
206 }
207
208 NTSTATUS ProcessMitigationsWin32KLockdownPolicy::
GetSuggestedOPMProtectedOutputArraySizeAction(const ClientInfo & client_info,const std::wstring & device_name,uint32_t * suggested_array_size)209 GetSuggestedOPMProtectedOutputArraySizeAction(
210 const ClientInfo& client_info,
211 const std::wstring& device_name,
212 uint32_t* suggested_array_size) {
213 if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
214 return STATUS_ACCESS_DENIED;
215 }
216 UNICODE_STRING unicode_device_name;
217 StringToUnicodeString(&unicode_device_name, device_name);
218 DWORD suggested_array_size_dword = 0;
219 NTSTATUS status = GDIFUNC(GetSuggestedOPMProtectedOutputArraySize)(
220 &unicode_device_name, &suggested_array_size_dword);
221 if (!status)
222 *suggested_array_size = suggested_array_size_dword;
223 return status;
224 }
225
226 NTSTATUS
CreateOPMProtectedOutputsAction(const ClientInfo & client_info,const std::wstring & device_name,HANDLE * protected_outputs,uint32_t array_input_size,uint32_t * array_output_size)227 ProcessMitigationsWin32KLockdownPolicy::CreateOPMProtectedOutputsAction(
228 const ClientInfo& client_info,
229 const std::wstring& device_name,
230 HANDLE* protected_outputs,
231 uint32_t array_input_size,
232 uint32_t* array_output_size) {
233 if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
234 return STATUS_ACCESS_DENIED;
235 }
236
237 UNICODE_STRING unicode_device_name;
238 StringToUnicodeString(&unicode_device_name, device_name);
239 DWORD output_size = 0;
240
241 NTSTATUS status = GDIFUNC(CreateOPMProtectedOutputs)(
242 &unicode_device_name, DXGKMDT_OPM_VOS_OPM_SEMANTICS, array_input_size,
243 &output_size,
244 reinterpret_cast<OPM_PROTECTED_OUTPUT_HANDLE*>(protected_outputs));
245 if (!status)
246 *array_output_size = output_size;
247 return status;
248 }
249
GetCertificateSizeAction(const ClientInfo & client_info,const std::wstring & device_name,uint32_t * cert_size)250 NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateSizeAction(
251 const ClientInfo& client_info,
252 const std::wstring& device_name,
253 uint32_t* cert_size) {
254 if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
255 return STATUS_ACCESS_DENIED;
256 }
257 UNICODE_STRING unicode_device_name;
258 StringToUnicodeString(&unicode_device_name, device_name);
259
260 return GDIFUNC(GetCertificateSize)(&unicode_device_name,
261 DXGKMDT_OPM_CERTIFICATE,
262 reinterpret_cast<DWORD*>(cert_size));
263 }
264
GetCertificateAction(const ClientInfo & client_info,const std::wstring & device_name,BYTE * cert_data,uint32_t cert_size)265 NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateAction(
266 const ClientInfo& client_info,
267 const std::wstring& device_name,
268 BYTE* cert_data,
269 uint32_t cert_size) {
270 if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
271 return STATUS_ACCESS_DENIED;
272 }
273 UNICODE_STRING unicode_device_name;
274 StringToUnicodeString(&unicode_device_name, device_name);
275
276 return GDIFUNC(GetCertificate)(&unicode_device_name, DXGKMDT_OPM_CERTIFICATE,
277 cert_data, cert_size);
278 }
279
280 NTSTATUS
GetCertificateSizeByHandleAction(const ClientInfo & client_info,HANDLE protected_output,uint32_t * cert_size)281 ProcessMitigationsWin32KLockdownPolicy::GetCertificateSizeByHandleAction(
282 const ClientInfo& client_info,
283 HANDLE protected_output,
284 uint32_t* cert_size) {
285 auto get_certificate_size_func = GDIFUNC(GetCertificateSizeByHandle);
286 if (get_certificate_size_func) {
287 return get_certificate_size_func(protected_output, DXGKMDT_OPM_CERTIFICATE,
288 reinterpret_cast<DWORD*>(cert_size));
289 }
290 return STATUS_NOT_IMPLEMENTED;
291 }
292
GetCertificateByHandleAction(const ClientInfo & client_info,HANDLE protected_output,BYTE * cert_data,uint32_t cert_size)293 NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateByHandleAction(
294 const ClientInfo& client_info,
295 HANDLE protected_output,
296 BYTE* cert_data,
297 uint32_t cert_size) {
298 auto get_certificate_func = GDIFUNC(GetCertificateByHandle);
299 if (get_certificate_func) {
300 return get_certificate_func(protected_output, DXGKMDT_OPM_CERTIFICATE,
301 cert_data, cert_size);
302 }
303 return STATUS_NOT_IMPLEMENTED;
304 }
305
GetOPMRandomNumberAction(const ClientInfo & client_info,HANDLE protected_output,void * random_number)306 NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetOPMRandomNumberAction(
307 const ClientInfo& client_info,
308 HANDLE protected_output,
309 void* random_number) {
310 return GDIFUNC(GetOPMRandomNumber)(
311 protected_output, static_cast<DXGKMDT_OPM_RANDOM_NUMBER*>(random_number));
312 }
313
314 NTSTATUS ProcessMitigationsWin32KLockdownPolicy::
SetOPMSigningKeyAndSequenceNumbersAction(const ClientInfo & client_info,HANDLE protected_output,void * parameters)315 SetOPMSigningKeyAndSequenceNumbersAction(const ClientInfo& client_info,
316 HANDLE protected_output,
317 void* parameters) {
318 return GDIFUNC(SetOPMSigningKeyAndSequenceNumbers)(
319 protected_output,
320 static_cast<DXGKMDT_OPM_ENCRYPTED_PARAMETERS*>(parameters));
321 }
322
323 NTSTATUS
ConfigureOPMProtectedOutputAction(const ClientInfo & client_info,HANDLE protected_output,void * parameters_ptr)324 ProcessMitigationsWin32KLockdownPolicy::ConfigureOPMProtectedOutputAction(
325 const ClientInfo& client_info,
326 HANDLE protected_output,
327 void* parameters_ptr) {
328 DXGKMDT_OPM_CONFIGURE_PARAMETERS parameters;
329 memcpy(¶meters, parameters_ptr, sizeof(parameters));
330 if (parameters.guidSetting != DXGKMDT_OPM_SET_PROTECTION_LEVEL ||
331 parameters.cbParametersSize !=
332 sizeof(DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS)) {
333 return STATUS_INVALID_PARAMETER;
334 }
335
336 DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS prot_level;
337 memcpy(&prot_level, parameters.abParameters, sizeof(prot_level));
338 if (prot_level.Reserved || prot_level.Reserved2)
339 return STATUS_INVALID_PARAMETER;
340
341 if (prot_level.ulProtectionType != DXGKMDT_OPM_PROTECTION_TYPE_HDCP &&
342 prot_level.ulProtectionType != DXGKMDT_OPM_PROTECTION_TYPE_DPCP) {
343 return STATUS_INVALID_PARAMETER;
344 }
345
346 // Protection levels are same for HDCP and DPCP.
347 if (prot_level.ulProtectionLevel != DXGKMDT_OPM_HDCP_OFF &&
348 prot_level.ulProtectionLevel != DXGKMDT_OPM_HDCP_ON) {
349 return STATUS_INVALID_PARAMETER;
350 }
351
352 return GDIFUNC(ConfigureOPMProtectedOutput)(protected_output, ¶meters, 0,
353 nullptr);
354 }
355
GetOPMInformationAction(const ClientInfo & client_info,HANDLE protected_output,void * parameters_ptr,void * requested_info_ptr)356 NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetOPMInformationAction(
357 const ClientInfo& client_info,
358 HANDLE protected_output,
359 void* parameters_ptr,
360 void* requested_info_ptr) {
361 DXGKMDT_OPM_GET_INFO_PARAMETERS parameters;
362 memcpy(¶meters, parameters_ptr, sizeof(parameters));
363
364 bool valid_parameters = false;
365 // Validate sizes based on the type being requested.
366 if ((parameters.guidInformation == DXGKMDT_OPM_GET_CONNECTOR_TYPE ||
367 parameters.guidInformation ==
368 DXGKMDT_OPM_GET_SUPPORTED_PROTECTION_TYPES) &&
369 parameters.cbParametersSize == 0) {
370 valid_parameters = true;
371 } else if ((parameters.guidInformation ==
372 DXGKMDT_OPM_GET_VIRTUAL_PROTECTION_LEVEL ||
373 parameters.guidInformation ==
374 DXGKMDT_OPM_GET_ACTUAL_PROTECTION_LEVEL) &&
375 parameters.cbParametersSize == sizeof(uint32_t)) {
376 uint32_t param_value;
377 memcpy(¶m_value, parameters.abParameters, sizeof(param_value));
378 if (param_value == DXGKMDT_OPM_PROTECTION_TYPE_HDCP ||
379 param_value == DXGKMDT_OPM_PROTECTION_TYPE_DPCP) {
380 valid_parameters = true;
381 }
382 }
383 if (!valid_parameters)
384 return STATUS_INVALID_PARAMETER;
385 DXGKMDT_OPM_REQUESTED_INFORMATION requested_info = {};
386 NTSTATUS status = GDIFUNC(GetOPMInformation)(protected_output, ¶meters,
387 &requested_info);
388 if (!status)
389 memcpy(requested_info_ptr, &requested_info, sizeof(requested_info));
390
391 return status;
392 }
393
394 NTSTATUS
DestroyOPMProtectedOutputAction(HANDLE protected_output)395 ProcessMitigationsWin32KLockdownPolicy::DestroyOPMProtectedOutputAction(
396 HANDLE protected_output) {
397 return GDIFUNC(DestroyOPMProtectedOutput)(protected_output);
398 }
399
SetOverrideForTestCallback(OverrideForTestFunction callback)400 void ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback(
401 OverrideForTestFunction callback) {
402 override_callback_ = callback;
403 }
404
405 OverrideForTestFunction
GetOverrideForTestCallback()406 ProcessMitigationsWin32KLockdownPolicy::GetOverrideForTestCallback() {
407 return override_callback_;
408 }
409
410 } // namespace sandbox
411