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